美文网首页
Java基础知识(3)

Java基础知识(3)

作者: 小杨不想努力了 | 来源:发表于2022-02-09 21:40 被阅读0次
    1. Java中泛型是类型擦除的

      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)。
    2. 关于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)来判断。

    3. 基本数据类型的初始值

      boolean        false
      char           '/uoooo'(null)
      byte           (byte)0
      short          (short)0
      int            0
      long           0L
      float          0.0f
      double         0.0(d)
      引用数据类型的话   为null
      
    4. 创建对象

      1. 在堆区为实例对象分配内存

        为实例变量分配内存(包括本类和父类),但不包括任何静态变量

      2. 对实例变量赋默认值

        将方法区内对实例变量的定义拷贝一份到堆区,然后赋默认值

      3. 执行实例初始化代码

        先初始化父类再初始化子类,初始化时先执行非静态代码块(包括非静态初始化块,非静态属性)再执行构造方法

      4. 将堆区对象的地址赋值给栈区的引用变量

        有类似于Child c = new Child()形式的引用,将堆区对象的地址赋值给栈区的引用变量c

    5. 非静态内部类为什么持有外部类的引用

      // 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. 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;
      2. 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;
      3. 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。

    相关文章

      网友评论

          本文标题:Java基础知识(3)

          本文链接:https://www.haomeiwen.com/subject/zvsgkrtx.html