1z-808复习 第3章

Core Java APIs

Creating and Manipulating Strings

理解什么是 concatenation,immutability, string pool, common methods, method chaining

Concatenation

Immutability

The trade-off for the optimal packing is zero flexibility.
打包的最优取舍就是零灵活性

String s1 = "1";
String s2 = s1.concat("2");
s2.concat("3");
System.out.println(s2);

结果应该是"12"而不是"123",一定要注意,因为s2本身没有变成"123"
新生成的字符串因为没有任何指向它的变量,理论上应该会被回收。

The String Pool

String Pool又叫做intern pool,是JVM用来存放String的地方。
String name = "Fluffy"
是正常使用StringPool,有可能会共用。
String name = new String("Fluffy");
要求JVM不要使用StringPool,即使效率更低,也一定要新生成一个Object。

Important String Methods

length(),charAt(),indexOf()
substring(),toLowerCase(),toUpperCase()
equals() and equalsIgnoreCase()
startsWith() and endsWith()
contains() and trim()

int indexOf(char ch, index fromIndex)
int indexOf(String str, index fromIndex)
注意这个fromIndex是按照下标来的,从0到length-1

substring()

int substring(int beginIndex, int endIndex)  
String string = "animals";  
System.out.println(string.substring(3, 7)); // mals  

第二个参数是指结束的下标,
所以取第三个字符就是3,4,而取到最后就会是3,7(最大下标+1或length)

这个跟charAt有点混淆,同样是超出下标出错,
substring是8,而charAt是7

contains() str.indexOf(otherString) != -1.
同样效果的写法,不需要再写了。

replace有两种写法,一个是char,一个是CharSequence
String replace(char oldChar, char newChar)
String replace(CharSequence oldChar, CharSequence newChar)

System.out.println("abcabc".replace('a', 'A')); // AbcAbc
System.out.println("abcabc".replace("a", "A")); // AbcAbc
同样的效果。

A CharSequence is a general way of representing several classes, including String and StringBuilder.
CharSequence是表示几个类的通用方法,包括String类和StringBuilder类。

trim()会去掉字符串开头和结尾的whitespace。
whitespace的定义是,space(单字节空格),制表符(\t),换行符(\n)
另外\r (carriage return):回车
\n换行:换到下一行
\r回车:行不变,定位到左边界
Windows里面换新行用的是"\r\n"
Unix里面换新行用的是"\n"

Method Chaining

String result = "AniMaL ".trim().toLowerCase().replace('a', 'A');
虽然连着写更加明了简洁,但总共还是创建了4个String对象。
跟分开写,性能没有任何影响。

Using the StringBuilder Class

//无效率的产生了26个可以垃圾回收的字符串
String alpha = "";
for(char current = 'a'; current <= 'z'; current++)
    alpha += current;
System.out.println(alpha);

//只有一个StringBuilder对象,效率大大提高
StringBuilder alpha = new StringBuilder();
for(char current = 'a'; current <= 'z'; current++)
    alpha.append(current);
System.out.println(alpha);

Mutability and Chaining

When we chained String method calls, the result was a new String with the answer.
Instead, the StringBuilder changes its own state and returns a reference to itself!

StringBuilder sb = new StringBuilder("start");
sb.append("+middle"); // sb = "start+middle"
StringBuilder same = sb.append("+end"); // "start+middle+end"

sb和same最后内容完全相同,都是"start+middle+end"
※※※
StringBuilder的函数作用是改变StringBuilder本身的状态,然后将自己参照返回。
String的函数作用是生成一个新的String,然后将新String的参照返回
※※※

Creating a StringBuilder

StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder("animal");
StringBuilder sb3 = new StringBuilder(10);

第三行代码不是创建一个内容是"10"的StringBuilder,
而是创建一个可以容纳10个字符的StringBuilder。

StringBuilder类的两个参数,一个是size,表示其中目前含有的字符数。
另一个是capacity,表示当前这个StringBuilder能够容纳的字符数。

对于StringBuilder,Java知道它的Size会变,因此在构建StringBuilder对象时,
它会设置缺省的capacity,(缺省是16,最大容纳16个字符)

Java在字符数超过StringBuilder的capacity的时候,会自动扩展其capacity。
但扩展多大,这个今后要看。好像是16

Important StringBuilder Methods

charAt(), indexOf(), length(), and substring()

StringBuilder sb = new StringBuilder("animals");
String sub = sb.substring(sb.indexOf("a"), sb.indexOf("al"));
int len = sb.length();
char ch = sb.charAt(6);
System.out.println(sub + " " + len + " " + ch);

答案是 anim 7 s。一开始以为substring是直接操作StringBuilder对象本身,
这个认识是错误的。
特别要注意的是substring(),这个是指从StringBuilder对象中切出一个新的String对象。
因此,StringBuilder类本身并没有变化。
可以把substring()想象成一个查询,查询从fromIndex到endIndex的内容,作为一个结果返回给新的String对象。

上面的函数执行完后StringBuilder对象的内容不会有变化

下面的函数执行完后StringBuilder对象的内容会被执行结果更新

append(),insert(),delete() and deleteCharAt()
StringBuilder insert(int offset, String str)
在offset之前,插入str

StringBuilder delete(int start, int end)
StringBuilder deleteCharAt(int index)

删除以start开始,到end之前的字符串

reverse()和toString()
就是将字符串的顺序反过来
"animals" ⇒ "slamina"

StringBuilder vs. StringBuffer

StringBuffer跟StringBuilder是一样的效果,
但是效率上会慢一点,因为它是线程安全的。
String也是线程安全的。

Understanding Equality

StringBuilder one = new StringBuilder();
StringBuilder two = new StringBuilder();
StringBuilder three = one.append("a");
System.out.println(one == two); // false
System.out.println(one == three); // true

因为append之后会把内容更新并返回自身,因此three和one相同。

String x = "Hello World";
String y = "Hello World";
System.out.println(x == y); // true


String x = "Hello World";
String z = " Hello World".trim();
System.out.println(x == z); // false


String x = new String("Hello World");
String y = "Hello World";
System.out.println(x == y); // false

因此千万不要用==来比较两个字符串

String类有equals方法,因此比较的是String内容是否一致。
而StringBuilder类没有equals方法,因此比较的是是否参照了同一个对象。

Understanding Java Arrays

Creating an Array of Primitives

int[] numbers = new int[3]; // 创建一个全是0的大小是3的整数型数组
int[] numbers2 = new int[] {42, 55, 99}; //创建一个大小是3的数组并初始化
int[] numbers2 = {42, 55, 99};//简略后

注意:使用大括号来赋值

int[] numAnimals;
int [] numAnimals2;
int numAnimals3[];
int numAnimals4 [];

上面4个声明变量的方法,结果完全相同。

int[] ids, types;
int ids[], types;

区别上面两行代码的结果,一个是生成了两个数组;
另一个是生成了1个数组和1个整形变量。

Creating an Array with Reference Variables

public class ArrayType {
public static void main(String args[]) {
    String [] bugs = { "cricket", "beetle", "ladybug" };
    String [] alias = bugs;
    System.out.println(bugs.equals(alias)); // true
    System.out.println(bugs.toString()); // [Ljava.lang.String;@160bc7c0
    System.out.println(Arrays.toString(bugs));//[cricket, beetle, ladybug]
} }

因为两个变量都参照了同一个对象,当然就是相等的。
L means it is an array, java.lang.String is the reference type, and 160bc7c0 is the hash code.

java.util.Arrays.toString(Object[] obj) 对每个Object.toString(),然后出力。
上面因为list的每个变量是一个String,因此就是把内容直接出力。

String[] strings = { "stringValue" };
Object[] objects = strings;
String[] againStrings = (String[]) objects;
againStrings[0] = new StringBuilder(); // DOES NOT COMPILE
objects[0] = new StringBuilder(); // careful!

strings, objects, againStrings都指向同一个object,一个String的Array。
StringBuilder对象无法放到放到String对象里去。
System.out.println(new StringBuilder().toString());
打印了一个空字符串而不是null,说明StringBuilder初始化不是null而是空字符串""。

最后一行在编译期不会发生错误,但是在执行期会出现ArrayStoreException。

Using an Array

Sorting

如果Array是数字型的则按数字大小排序
如果Array是String型的,则按字母顺序排序,“19”和“6”相比,因为1比6小,所以19排在前面
另外数字排在字母前面,大写排在小写前面

Searching

如果Arrays是排好序的,则可以使用binarySearh方法。
找到了会返回下标,找不到返回插入顺序取反之后-1的整数值。

后面学习一下二叉查询法。

Varargs

public static void main(String... args)
定义的方法在第一章里详细介绍。
使用方法在第四章里详细介绍。

Multidimensional Arrays

int[][] vars1; // 2D array
int vars2 [][]; // 2D array
int[] vars3[]; // 2D array
int[] vars4 [], space [][]; // a 2D AND a 3D array

Understanding an ArrayList

creating an ArrayList, common methods, autoboxing, conversion, and sorting.

Creating an ArrayList

Java 5 之前,用下面的方法定义。 ArrayList list2 = new ArrayList();
ArrayList list2 = new ArrayList(10);
参数10是capacity。表示生成可以放10个元素的ArrayList
java 5之后,需要指定ArrayList的元素类型。
ArrayList<String> list4 = new ArrayList<String>(); Java 7之后,可以省略右边的类型,用钻石符号"<>"来替代。
ArrayList<String> list5 = new ArrayList<>();

Using an ArrayList

Wrapper Classes

从String转回primitive和其wrapper class,这两个都可以。
int primitive = Integer.parseInt("123");
Integer wrapper = Integer.valueOf("123");

Autoboxing

List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.remove(1);
System.out.println(numbers);

结果打印的是1,而不是2的原因是,add的时候,1,2是内容。
remove的时候,1是index,如果想删除内容1,要写成
numbers.remove(new Integer(1));

Converting Between array and List

List<String> list = new ArrayList<>();
list.add("hawk");
list.add("robin");
Object[] objectArray = list.toArray();
System.out.println(objectArray.length); // 2
String[] stringArray = list.toArray(new String[0]);
System.out.println(stringArray.length); // 2

可以用list.toArray()来转换,但是转换结果是Object
如果想转成String
类型,要用list.toArray(new String[0])

反过来,从array转成List之后,这个list叫做
array backed List,并且array和List是共享一个参照。

String[] array = { "hawk", "robin" }; // [hawk, robin]
List<String> list = Arrays.asList(array); // returns fixed size list
System.out.println(list.size()); // 2
list.set(1, "test"); // [hawk, test]
array[0] = "new"; // [new, test]
for (String b : array) System.out.print(b + " "); // new test
list.remove(1); // throws UnsupportedOperation Exception

Arrays.asList(array)来转换。
这个ArrayList因为是array backed,因此是fixed siz

应为支持可变参数,因此用下面的方法更加方便的创建List
List<String> list = Arrays.asList("one", "two");

Sorting

用下面的方法排序。
Collections.sort(numbers);

Working with Dates and Times

最新的Date和Time操作类,需要做以下导入

import java.time.*; // import time classes

在后面章节,要学习create,manipulaing,formatting日期和时间

Creating Dates and Times

三个类:LocalDate,LocalTime,LocalDateTime
这3个类不带时区概念 如果需要带时区的日期,则用ZonedDateTime 这个怎么理解:
“the stroke of midnight on New Year’s.” Midnight on January 2 isn’t nearly as special, and clearly an hour after midnight isn’t as special either.
打印出来的格式类似:2015-01-20T12:45:18.401
日期加上时间,中间用字母“T”连接
创建当前日期可以用.now()静态方法。
如果要创建指定日期可以用静态方法.of()
该方法有很多overload的版本,例如:
public static LocalDateTime of(LocalDate date, LocalTime)
注意:这3个类都没有构建方法,必须用上面的静态方法来创建对象。

Manipulating Dates and Times

System.out.println(date); // 2014-01-29
date = date.plusMonths(1);
System.out.println(date); // 2014-02-28

因为不是闰年,所有2月没有29日,会自动设值28日。

System.out.println(dateTime); // 2020-01-18T19:15
dateTime = dateTime.minusSeconds(30);
System.out.println(dateTime); // 2020-01-18T19:14:30

没有操作秒的时候,秒不会显示,操作了之后,秒会自动显示。

Date和Time类跟String类似,是immutable的

LocalDate date = LocalDate.of(2020, Month.JANUARY, 20);
date.plusDays(10);
System.out.println(date);

如果不把计算结果返回,最终打印出来的还是1月20日

Working with Periods

LocalDate.of(1970, Month.JANUARY, 1).toEpochDay() 最后的值为0 Period没法用链式表达 Period wrong = Period.ofYears(1).ofWeeks(1); 最终的期间结果是1个礼拜而不是1年零7天。 日期的操作函数plusDate但效果不同,容易混淆,要注意。

Formatting Dates and Times

DateTimeFormatter类来控制输入的日期格式 两种格式化的方法,一种是直接用类自带的.format方法。

LocalDate date = LocalDate.of(2020, Month.JANUARY, 20);
LocalTime time = LocalTime.of(11, 12, 34);
LocalDateTime dateTime = LocalDateTime.of(date, time);
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));
System.out.println(time.format(DateTimeFormatter.ISO_LOCAL_TIME));
System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

第二种是用DateTimeFormatter类的format去格式化日期时间类。

DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
System.out.println(shortDateTime.format(dateTime)); // 1/20/20
System.out.println(shortDateTime.format(date)); // 1/20/20
System.out.println(shortDateTime.format(time)); // UnsupportedTemporalTypeException

DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);生成想要的格式的DateTimeFormatter。

注意有ofLocalizedDate,ofLocalizedDateTime,ofLocalizedTime三种类型,用相应的方法。

预定义格式有两种,SHORT和MEDIUM
如果需要自定义格式,需要用下面的格式。
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");

Parsing Dates and Times

Summary

Exam Essentials

1.DA
2.ACD
3.BCE
4.B
5.D
6.B
7.E
8.AED
9.C
10.F
11.F
12.A
13.F
14.AC
15.BCE
16.D
17.F
18.AC
19.C
20.D
21.C
22.D
23.A
24.B
25.E
26.C
27.B
28.DF
29.D
30.E
31.F
32.