-
List<String>、List<T> 擦除后的类型为 List。 List<String>[]、List<T>[] 擦除后的类型为 List[]。 List<? extends E>、List<? super E> 擦除后的类型为 List<E>。 List<T extends Serialzable & Cloneable> 擦除后类型为 List<Serializable>。
Java 为什么这么处理呢?有以下两个原因:
- 避免 JVM 的大换血。如果 JVM 将泛型类型延续到运行期,那么到运行期时 JVM 就需要进行大量的重构工作了,提高了运行期的效率。
- 版本兼容。 在编译期擦除可以更好地支持原生类型(Raw Type)。
-
关于List,Set,Map能否存储null
1、vector、arraylist、linkedlist可以存储多个null
2、hashset、linkedset可以存储一个null;treeset不能存储null
3、hashmap 、linkedhashmap key与value均可以为null,仅可1个key为null;treemap,key不可以为null,value可以为null;hashtable、concurrenthashmap,key与value均不能为null。
ps:hashtable、concurrenthashmap用于多线程,并发的,如果map.get(key)为null,不能判断到底是映射的value为null,还是没找到对应的key而为null,而单线程状态的hashmap可以contains(key)来判断。
-
基本数据类型的初始值
boolean false char '/uoooo'(null) byte (byte)0 short (short)0 int 0 long 0L float 0.0f double 0.0(d) 引用数据类型的话 为null
-
创建对象
-
在堆区为实例对象分配内存
为实例变量分配内存(包括本类和父类),但不包括任何静态变量
-
对实例变量赋默认值
将方法区内对实例变量的定义拷贝一份到堆区,然后赋默认值
-
执行实例初始化代码
先初始化父类再初始化子类,初始化时先执行非静态代码块(包括非静态初始化块,非静态属性)再执行构造方法
-
将堆区对象的地址赋值给栈区的引用变量
有类似于Child c = new Child()形式的引用,将堆区对象的地址赋值给栈区的引用变量c
-
-
非静态内部类为什么持有外部类的引用
// InnerClassReference.class public class InnerClassReference { private InnerClassReference.InnerClass clazz = new InnerClassReference.InnerClass(); public InnerClassReference() {} private class InnerClass { private InnerClass() {} } } // InnerClassReference$InnerClass.class class InnerClassReference$InnerClass { private InnerClassReference$InnerClass(InnerClassReference var1) { this.this$0 = var1; } } 可以看到在InnerClass.class中,构造方法在编译的时候添加了一个参数,这个参数就是外部类的实例!
关于内部类如何访问外部类的成员, 分析之后其实也很简单, 主要是通过以下几步做到的:
- 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;
- 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;
- 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。
网友评论