Java泛型详解(下)

简介: 九. 泛型类型的继承规则假设现在有一个类Employee和它的子类Manager现在问题来了: Pair是Pair的子类吗?答案是:不是例如,下面的代码将不会编译成功:Manager[] topHonchos = .

九. 泛型类型的继承规则

假设现在有一个类Employee和它的子类Manager

现在问题来了:
Pair<Manager>是Pair<Employee>的子类吗?

答案是:不是

例如,下面的代码将不会编译成功:

Manager[] topHonchos = ...;
Pair<Employee> result = ArrayAlg.minmax(topHonchos); //Error
//minmax方法返回Pair<Manager>, 而不是Pair<Employee>, 这样的赋值是不合法的

也就是说,无论 S 与 T 有什么联系,通常,Pair<S>与Pair<T>没有什么联系
也可以这么理解,无论赋给类型变量的类型之间有什么联系,在泛型类里,这些关系都不存在了

另外,泛型类可以扩展或实现其他的泛型类,例如:ArrayList<T>类实现了List<T>接口,这意味着,一个ArrayList<Manager>可以被转换为一个List<Manager>。但是,一个ArrayList<Manager>不是一个ArrayList<Employee>或List<Employee>

十. 通配符类型

1. 通配符的概念:

假设我们现在需要打印一对员工的方法:

public static void printBuddies(Pair<Employee> p) {
    Employee first = p.getFirst();
    Employee second = p.getSecond();
    System.out.println(first.getName() + "and" + second.getName() + "are buddies.");
}

现在问题来了,Manager虽然不同于普通员工,但他也算是员工,他是员工的子类,但是根据之前说的泛型类继承规则,Pair<Manager>与Pair<Employee>没有任何关系,所以这个方法就不能接受Pair<Manager>类了,难道Manager与普通员工就不能做朋友了吗?不,为了解决这个问题,我们使用通配符类型

public static void printBuddies(Pair<? extends Employee> p)

类型Pair<Manager>是Pair<? extends Employee>的子类型
可以认为,通配符为泛型类之间添加了一层联系,然而这种联系并不纯粹,我们来看一个例子:

Pair<Manager> managerBuddies = new Pair<>(CEO, CFO); //JDK7之后可以省略构造函数的类型变量,由编译器根据语句自己翻译
Pair<? extends Employee> wildcBuddies; //OK
wildcardBuddies.setFirst(lowlyEmployee); //这步就会报错,compile-time error

究其原因,我们来看对于类型Pair<? extends Employee>内部对 setFirst 和 getFirst 方法的调用,它是这样的:

? extends Employee getFirst() //将getFirst返回值赋给一个Employee的引用完全合法
void setFirst(? extends Employee) //出现类型错误,因为编译器只知道需要某个Employee的子类型,但不知道具体是什么类型


2. 通配符的超类型限定

通配符还有一个比较强的功能就是可以指定一个超类,像这样:

? super Manager //super关键字限制通配符为Manager的所有超类(父类)

这样的做法与之前的子类型限定恰好相反。这样可以为方法提供参数(setFirst),但不能使用返回值(getFirst)

void setFirst(? super Manager)
? super Manager getFirst() 

直观的讲,带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取

3. 无限定通配符

还可以使用无限定通配符,例如,Pair<?>,初看起来,这好像与原始的Pair类型一样,实际上却有很大的不同,类型Pair<?>有以下的方法:

? getFirst()
void setFirst(?)

getFisrt的返回值只能赋给一个Object。setFirst方法不能被调用,甚至不能用Object调用。Pair<?>和Pair的本质不同在于:可以用任意Object对象调用原始Pair类的setObject方法

4. 通配符捕获


参考文献:[美]Cay S. Horsimann著 《Java 核心技术 卷I》(第十版)

目录
相关文章
|
3月前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
75 2
|
15天前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
14 0
[Java]泛型
|
24天前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
10 1
|
1月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
26 5
|
29天前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
17 1
|
2月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
34 9
Java——包装类和泛型
|
1月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
18 2
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
29天前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
13 0
|
2月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
下一篇
无影云桌面