RandomAccess接口
RandomAccess是一个接口,但里面并没有抽象方法,他只是一个标识,用来表示实现它的类可以随机访问。
List下的ArrayList和LinkedList。其中ArrayList实现了RandomAccess。而LinkedList没有。我们可以利用instanceof来判断哪一个是实现了RandomAccess。分辨出两个集合。其中ArrayList使用for循环遍历快,而LinkedList使用迭代器快。
Cloneable接口
cloneable也是一个标记接口,只有实现这个接口后,在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。
参考博客:Cloneable,浅拷贝深拷贝
transient关键字
transient是短暂的意思。对于transient 修饰的成员变量,在类的实例对象的序列化处理过程中会被忽略
。 因此,transient变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。
transient是Java语言的关键字,用来表示一个成员变量不是该对象序列化的一部分。当一个对象被序列化的时候,transient型变量的值不包括在序列化的结果中。而非transient型的变量是被包括进去的。 注意static修饰的静态变量天然就是不可序列化的。
参考博客:transient
static关键字
- static修饰成员变量:属于类的变量且
只能赋值一次
- static修饰方法:属于类的方法且
不可以被重写
- static修饰内部类:属于外部类,且
不能被继承
参考博客:static
final关键字
- final 修饰基本类型:值
不能被修改
; - final 修饰引用类型:
引用不可以被修改
也就是说不能指向其他对象,但是该引用的对象内容可以被修改
; - final 修饰 方法,方法
不可以重写
,但是可以被子类访问 【前提:方法不是 private 类型】。 - final 修饰 类,类
不可以被继承
。
成员变量必须在定义时或者构造器中进行初始化赋值
参考博客:final
String中”+”的具体实现以及final修饰的String的优化
代码:
public class FinalAndVariableDifference {
public static void main(String[] args) {
String a = "helloWord1";
final String b = "helloWord";
String F = "helloWord";
String c = b + 1;
String e = F + 1;
System.out.println((a == c));
System.out.println((a == e));
}
}
运行结果:
true false
解释:
true: 当final变量修饰基本数据类型以及String类型时,编译期间能知道它的确切值时,编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。 分析上面代码:由于变量
b
被final修饰,因此会被当做编译器常量,所以在使用到b
的地方会直接将变量b
替换为它的值(这种情况我们成为编译器的优化)。而对于变量F
的访问却需要在运行时才能连接确定,所以返回false
注意:只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化false: 本来我想着:F 原本是
helloWord
,+
表示在后面添加,那不就变成了helloWord1
了吗,此时常量池中已经有了helloWord1
,所以应该指向的是常量池中的数据,结果应该是true
才对。 然后去debug看了看到底是怎么回事,发现运行到String e = F + 1;
这一行的时候,首先进入了类加载器,加载StringBuffer
类,然后new了一个空的StringBuffer实例
,然后执行了StringBuffer的append方法
,把helloWord
加进去了,然后又执行append方法把1加进去了,加完之后又执行了toString方法
,把StringBuffer变成了String,结束。 到这里才明白,”+”实际上是先new一个StringBuffer,然后把新旧字符分别加进去然后再把StringBuffer变成String。 但是:运行到String c = b + 1
的时候并没有new一个StringBuffer
,而是直接把c变成了helloWord1