Java泛型类的继承关系

本文探讨了Java中泛型类的继承关系,解释了BoxTest的字节码签名以及泛型类的子类型如何确定。内容包括:1) 使用javap工具查看boxTest方法的完整签名以理解参数类型;2) 分析泛型类的子类型创建,通过举例说明不同类型参数的泛型类之间无继承关系;3) 拓展讨论了包含额外类型参数的继承情况,如PayloadList接口及其子类的继承结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

类型兼容的对象可以进行赋值,如可将一个 Integer 对象传给一个 Object 对象,因为 ObjectInteger 的基类。

Object someObject = new Object();
Integer someInteger = new Integer(10);
someObject = someInteger;   // OK

对于方法的参数,也可传递类型兼容的对象。如 Integer 是一个 Number ,故如下代码可正确执行。

public void someMethod(Number n) { /* ... */ }

someMethod(new Integer(10));   // OK
someMethod(new Double(10.1));   // OK

类型兼容不能直接运用到泛型类型上,考虑如下方法:

public static void boxTest(Box<Number> box) {
    System.out.println(box.get());
}

该方法接受类型为 Box<Number> 的参数,那么该方法是否接收类型为 Box<Integer>Box<Double> 的参数?要回答这个问题,首先要清楚以下两个问题:
1. boxTest 的字节码签名是什么?
2. Box<Number> 的子类型应满足什么条件?

1. BoxTest的字节码签名

这个话题涉水较深,如果使用 javap -s -c, 只能看到 descriptor 的信息:

public static void boxTest(generic.inheritance.Box<java.lang.Number>);
descriptor: (Lgeneric/inheritance/Box;)V
Code:
   0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
   3: aload_0
   4: invokevirtual #3                  // Method generic/inheritance/Box.get:()Ljava/lang/Object;
   7: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
  10: return

由上面的信息只能推导出 boxTest 只接受类型为 Box 的参数。而 Box 是泛型类,其基类为 Object. 需要使用 javap -v 才能确定 boxTest 完整签名信息:

public static void boxTest(generic.inheritance.Box<java.lang.Number>);
descriptor: (Lgeneric/inheritance/Box;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
  stack=2, locals=1, args_size=1
     0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: aload_0
     4: invokevirtual #3                  // Method generic/inheritance/Box.get:()Ljava/lang/Object;
     7: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
    10: return
  LineNumberTable:
    line 11: 0
    line 12: 10
Signature: #19                          // (Lgeneric/inheritance/Box<Ljava/lang/Number;>;)V

Signature: #19 才是 boxText 的完整签名信息,表示该方法之接受类型为泛型类型 Box<Number> 的参数。接下来确定 Box<Number>的子类型。

2. 泛型类的子类型

泛型类或接口的子类型创建方式与创建常规的类或接口的子类型创建方式一致,即使用 extendsimplements 关键字。
Collections 为例,ArrayList<E> 实现了 List<E>, 同时 List<E> 扩展自 Collections<E>. 故 ArrayList<E>List<E> 的子类型,List<E>Collections<E> 的子类型。只要类型参数 E 一致,这三个类的继承关系就得到保持。
Collections的继承关系

由于 Box<Number>Box<Integer> 的类型参数不同,故两者没有继承关系,其关系可如下表示:

因此, testBox(Box<Number>) 不接收类型为 Box<Integer>Box<Double> 的参数。

小结

对于类 A 和类 B, MyClass<A>MyClass<B> 没有任何继承关系,即使 AB 的子类。MyClass<A>MyClass<B> 的共同子类为 Object.

拓展:包含额外类型参数的继承关系

对于自定义的列表接口, PlayloadList 包含了一个额外的类型参数 P, 表示列表中的每个元素都关联了类型为 P 的元素。设存在方法:

interface PayloadList<E,P> extends List<E> {
  void setPayload(int index, P val);
  ...
}

以下的三个 PayloadList 都是 List<String>的子类:

  • PayloadList<String,String>
  • PayloadList<String,Integer>
  • PayloadList<String,Exception>
    继承关系如下所示:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值