transient
-
transient
会阻止实例中用此关键字声明的变量持久化,当对象被反序列化时,这样的实例变量值是不会被恢复的 -
transient
只能修饰变量,不能修饰方法和类,变量如果是自定义类,该类需要实现Serializable
接口 - 一个静态变量不管是否被
transient
修饰,均不能被序列化(被反序列化后,静态变量的值是JVM中存储的该变量的值)
for..each循环
for...each 原理
for...each是JDK提供的一种语法糖,其实际是通过迭代器来实现遍历的,这也是为什么for...each只能用于数组或实现了Iterable
接口的类,如集合
for...each 注意事项
在使用for...each时,不能更改被迭代的对象,否则会抛出ConcurrentModificationException
异常,因为for..each
的内部原理实质就是使用Iterator
迭代器进行迭代,而Iterator
是工作在一个独立的线程中,并且拥有一个mutex锁, Iterator
被创建之后会建立一个指向原来对象的单链表索引,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,从而抛出异常。
如果使用迭代器迭代集合,是可以使用迭代器自己的
remove
方法删除集合元素
for (String str : list) {
//...
}
for (String str : list) {
list.remove(str); //会抛出ConcurrentModificationException
}
Iterator iter = list.iterator();
while (iter.hasNext()) {
str = iter.next();
if (str.equals("")) {
iter.remove(); //如果使用iterator删除元素,不会抛出异常
}
}
泛型
类型擦除
Java的泛型都是在编译器的层次实现的,在最终生成的Java字节码中并不包含泛型的类型信息,编译器在编译的时候会取出泛型中的类型参数,这个过程称为泛型擦除,由此引出的泛型的特性有:
- 泛型类并没有自己独有的Class类对象, 对于List<String>, List<Integer>它们的Class都是List.class
- 静态变量被泛型类的所有实例共享, 如果有一个类声明为MyClass<T>, 同时有一个静态变量var, 则访问这个静态变量都是通过MyClass.var, 而不是MyClass<String>.var或MyClass<Integer>.var
- 泛型的类型参数不能出现在异常处理的
catch
语句中
上下界
通配符?
表示未知类型, 如List<?>表示List包含的元素是未知的. 不能通过List<?> list = new ArrayList<?>()
来创建List对象
可以使用上下界来限制位置类型的范围:
- List<? extends MyClass>, 表示List中包含的都是MyClass及其子类
- List<? super MyClass>, 表示List中包含的都是MyClass及其父类
ArrayList和LinkedList的区别
- ArrayList底层使用数组实现, LinkedList底层使用双向链表实现
数组的查询和赋值比较快,因为可以直接通过数组下标访问指定位置
链表中删除和增加比较快,因为可以直接通过修改链表的指针进行元素的增删
- LinkedList和ArrayList相比,增删的速度较快,但是查询和修改至的速度较慢,同时LinkedList还实现了Queue接口,所以还提供了
offer(), peek(), poll()
等方法