第18章 字符串
Java中的String类是使用最频繁的。
不可变字符串:
Java中的String类是一个不能被继承的类,在String类的方法中,它不会对当前字符串进行修改,而是基于当前字符串,生成一个新的字符串,看起来原字符串是被修改了。
重载+和StringBuilder:
+操作符可以用来拼接字符串,StringBuilder也是用来拼接字符串。
+操作符工作原理是每个被拼接的对象,都会先被创建为String对象,然后在字节码里看到的是这些String对象会被StringBuilder进行append方法调用拼接,最终StringBuilder的toString方法生成结果字符串。
一般用StringBuilder代替+操作符在大批量的拼接里使用。
无意识的递归:
所有类都有toString方法,如果一个类重写了toString方法,并且在toString方法里打印了【this】会导致容易产生递归打印情况。
字符串的常用方法:
length(),获取字符串长度;
indexOf(),查看一个字符串或字符在这个字符串里的索引位置
字符串的格式化输出:
格式化指的是在生成一条字符串时,可以使替代符号加在字符串里,在外面按照顺序传入参数。 而不是使用+操作符或者StringBuilder的append方法来拼接生成。
例如
System.out.printf("Row 1 [%d %f]", x, y);
Java提供了Formatter类,可看作是个转换器,将格式化字符串和数据转换为想要的结果。
字符 | 效果 |
d | 整数类型(十进制) |
c | Unicode字符 |
b | Boolean值 |
s | 字符串 |
f | 浮点数,十进制 |
e | 浮点数,科学记数法 |
x | 整数类型,十六进制 |
h | 哈希码,十六进制 |
% | 字面量% |
String自身有个format方法,可以进行字符串的格式化处理。
正则表达式:
基础:正则表达式用通用术语来描述字符串,如果字符串中包含这些内容,那么它就符合搜索条件。
-? 表示一个数前有没有减号;
\d 表示一个数字,但是一个反斜杠要用两个\\表示,所以在正则表达式里,数字表示方式为\\d;
+号 表示紧挨着的前面类型有一个或多个;\\d+表示前面有一个或多个数字;
| 表示表达式符号里的或含义。
String里有个split方法,可以传一个正则表达式,进行字符串的截断转数组。
Java中提供了Pattern和Mather工具类,来专门进行字符串的正则匹配;
matcher里的find方法可以应用它的CharSequence中查找多个匹配。
分组:是用括号括起来的正则表达式,分组0表示整个表达式,分组1是第一个带括号的分组,以此类推。
A(B(C))D,分组0是ABCD,分组1是BC,分组2是C
替换操作:正则表达式对于替换文本特别有用,replaceFirst,replaceAll等方法
第19章 反射
为什么需要反射?
在Java中,我们通常会使用继承和多态在进行程序业务的扩展。例如,正方形Square、圆形Circle、三角形Triangle都是形状Shape,
也就是说这三种具体的形状都使用extends来继承了Shape,在使用时所有具体形状,都会有一些公共方法。使用继承会涉及到向上转型,例如List 里可以存储这具体三种形状,如果新业务要求Triangle去画成蓝色,那么我们要在Shape里找到Triangle,使用反射,可以查到某个具体形状所指的确切类型,从而选择并隔离特殊情况。
Class对象:
程序中的每个类都有个class对象,它包含了类的相关信息,包括属于这个类的类加载器。类在首次使用时才会被加载到JVM中,首次使用除了传统的new 对象,类静态属性访问等,还有通过类的全路径名,使用Class.forName("")来进行类加载。
类在被加载的时候,就会对类进行初始化,如果该类有父类的话,会先初始化父类。
Class引用指向的是一个Class对象,该对象可以生成类的实例,并包含了这些实例所有方法的代码。可以使用泛型语法限制Class引用的类型。
Class genericIntClass = int.class;
Class引用的类型转换语法,也可以通过cast()方法转换
转型前要检查:
Java中提供了instanceof关键字用来动态检查一个类对象是不是属于一个类类型下的。
if(x instanceof Dog){
}
instanceof关键字和Class对象里的isInstance方法的实现效果是一样的。
动态代理:
proxy是基本的设计模式之一,它是为了代替【实际】对象而插入的一个对象,从而提供额外的或不同的操作。
Java的动态代理比代理更进一步,它可以动态的创建代理,并动态地处理对所代理方法的调用。
需要有个动态代理类,实现InvocationHandler接口,实现里面的方法;并通过Proxy.newProxyInstance()来创建动态代理。
使用Optional:
Optional创建了一个简单的代理来屏蔽潜在的null值,阻止代码直接抛出NullPointException。
第20章 泛型
泛型的意思是适用或者可兼容大批的类
简单泛型:
泛型的初衷之一就是为了能创建一个指定类型的集合。
在一个类里持有另一个类对象,第二个类属于泛型。
public class GenericHolder<T>{
private T t;
}
简单泛型里有一种被称为元组,用来将一组对象一起包装进了一个对象,该对象的接收方可以读取其中的元素,但不能往里面放新元素。
public class Tuple<A,B>{
private A a;
private B b;
}
包装的对象可以不止2个,可以更多个。
泛型接口:泛型可以定义在接口中
public interface Iterable<T> {
}
泛型可定义在方法中:方法参数或者返回类型。
public T f(T t){
}
类型擦除:Java的泛型是通过类型擦除实现的。
代码里写的泛型类,在代码编译后会被擦除掉。
泛型中的边界,指为泛型进行了限制,
class Color<T extends HasColor>{
// 要求被泛型的类必须是HasColor的子类
}
泛型中的通配符:
<?>表示无界通配符。
第21章 数组
数组,限定类型的对象集合,根据索引查询快。
数组可以作为参数、属性、返回结果使用在Java中。
数组有一维、二维、多维等方式。
int[] a1 = new int[]{1,2,3,4};
int[][] a2 = new int[][]{ {1,2,3},{1,2},{1,2,3,4} };
数组可以设定成泛型模式,基本类型除外。
public static <T> T[] f(T[] aa){
return aa;
}
Arrays.fill(),给一个数组里填充指定的对象,直到数组填满。
int[] aa = new int[5];
Arrays.fill(aa, 2);
数组排序
使用Arrays.sort()方法进行排序。
排序规则可以让类实现Comparable接口,重写compare方法