整理Java知识点之对象占用字节数、泛型

对象占用字节数

考察知识点:对象的数据信息

  1. 对象包括:

    1. 对象头:

      1. mark word

        包含hashcode、GC年龄、锁信息等。

      2. klass:指向堆中类的Class对象

      3. (如果是数组的话)数组长度

    2. 实例数据:

    3. 对齐填充:填充以使得CPU可以更好地读取数据,如果未填充,那么可能需要多次读取,而且可能造成指令无法进行原子性的执行。

  2. Object占用内存分析

    markword由c++实现,默认是8字节。

    如果我们使用的是64位虚拟机,jvm默认开启指针压缩,那么klass由于是使用的堆中的对象,那么kalss占用4字节。

    总共8 + 4 = 12字节 (不为8的倍数) + 4字节填充 = 16字节

    在这里插入图片描述

    如果我们关闭指针压缩,那么klass占用8字节。

    总共8 + 8 = 16,无需填充

    在这里插入图片描述

  3. 布尔占用1字节,不过会有补齐。其他中规中矩

    在这里插入图片描述

泛型

使程序经过编译期检查,更容易发现向下转型错误。我们知道,在对象进行实例化的时候,步骤是

检查类加载 - 分配内存- 赋值零值 - 设置对象头 - 调用构造方法

构造方法调用时,会调用父类的构造方法。那么对象的内存如下。

父类:
	实例数据
	方法
子类:实例数据
	方法

我们的代码如果是

父类 a = new 子类()

其实在初始化子类的时候会调用父类的client和init,那么内存已经分配好了。

向下转型是可以的,不会有问题。

如果是

父类 a = new 父类();

向下转型会抛出错误,没有子类的属性和方法。

为了能在编译期检查出这种错误,提供了泛型。

泛型会帮助我们检查类型。

泛型实际编译后的代码是类型擦除的。

带来的问题:

父类如果是泛型类,子类重写父类时,如果指定了泛型类型,由于父类的类型擦除,导致的结果是会多出现几个方法,相当于实现了重载,而不是重写,java编译时会帮我们加上相关方法的调用来解决这个问题。例如:

public class TTest<T> {
    public T v;

    public T getV() {
        return v;
    }

    public void setV(T v) {
        this.v = v;
    }
}

class S extends TTest<String> {
    @Override
    public String getV() {
        return super.getV();
    }

    @Override
    public void setV(String v) {
        super.setV(v);
    }

}

// 实际编译后
class S extends TTest<String> {
    public getV()Ljava/lang/String;
   L0
    LINENUMBER 22 L0
    ALOAD 0
    INVOKESPECIAL base/TTest.getV ()Ljava/lang/Object;
    CHECKCAST java/lang/String
    ARETURN

  // access flags 0x1
  public setV(Ljava/lang/String;)V
    LINENUMBER 27 L0
    ALOAD 0
    ALOAD 1
    INVOKESPECIAL base/TTest.setV (Ljava/lang/Object;)V
// 多出的方法,直接调用本类的String参数的S.setV (Ljava/lang/String;)
   public synthetic bridge setV(Ljava/lang/Object;)V
   L0
    LINENUMBER 19 L0
    ALOAD 0
    ALOAD 1
    CHECKCAST java/lang/String
    INVOKEVIRTUAL base/S.setV (Ljava/lang/String;)V
    RETURN

// 多出的方法
  public synthetic bridge getV()Ljava/lang/Object;
   L0
    LINENUMBER 19 L0
    ALOAD 0
    INVOKEVIRTUAL base/S.getV ()Ljava/lang/String;
    ARETURN
}

而且还有问题就是 即使AppleFruit是有继承关系的,List<Apple>List<Fruit>也没有继承关系。你不能用两个一样的杯子,一个装了苹果,一个装了水果,你就说这两个杯子是有继承关系的,这好像说不通。

所以为了匹配这种的。加入了通配符<?>、<extends>、<super>。用来实现各种要求。

猜你喜欢

转载自blog.csdn.net/qq_42254247/article/details/107901883