java 泛型类的继承关系和转型问题

简介: java 泛型类的继承关系和转型问题

两个问题

问题一:FatherClass和ChildClass是父子类的关系,那List<FatherClass>和List<ChildClass>是否也是父子类的关系?

问题二:倘若不是父子类关系,那么通过什么方式可以达到向上转型的效果?

有两个类Fruit和Apple,Apple继承自Fruit,所以Fruit使Apple的父类,关系如下图所示

示例代码

public class GenericMain {
    public static void method1(Fruit fruit) {
        System.out.println("lingyejun eat fruit");
    }
    public static void method2(List<Fruit> fruitList) {
        System.out.println("lingyejun eat fruit list");
    }
    public static void method3(Collection<Fruit> fruitList) {
        System.out.println("lingyejun eat fruit collection");
    }
    public static void method4(List<? extends Fruit> fruitList) {
        System.out.println("lingyejun eat extends fruit list");
    }
    public static void main(String[] args) {
        method1(new Fruit());
        method1(new Apple());
        List<Fruit> fruitList = new ArrayList<>();
        fruitList.add(new Fruit());
        method2(fruitList);
        List<Apple> appleList = new ArrayList<>();
        appleList.add(new Apple());
        method2(appleList);// Compile Error
        method3(fruitList);// 可以向Collection<Apple>中传入List<Apple>
        Set<Fruit> fruitSet = new HashSet<>();
        method3(fruitSet);// 也可以向Collection<Apple>中传入Set<Apple>
        method4(fruitList);
        method4(appleList);
    }
}

method1的方法参数是Fruit类型,想method1方法中传递Fruit类型的变量或者Apple类型的变量都是可以的,因为Apple继承自Fruit,会进行向上类型转换。

method2的方法参数时List<Fruit>,我们试图传递List<Apple>类型的变量是会出现编译报错,因为List<Fruit>和List<Apple>并不存在所谓的父子关系,是两种无关的类型,所以编译会报错。 

集合类的继承关系

对于泛化的集合类型他们的继承关系,以Collection<E>为例,ArrayList<E>实现了List<E>, 同时 List<E> 扩展自 Collections<E>。故 ArrayList<E>是 List<E>的子类型,List<E>是Collections<E> 的子类型。只要类型参数E一致,这三个类的继承关系就得到保持。如下图所示左右分别是Collection<Fruit>和Collection<Apple>的继承链路。他们两个是相互独立的,没有交叉的两条关系链路,所以尝试在method2中传入appleList会编译报错。

同理,我们如果定义一个method3的参数列表为Collection<Fruit>,那么按照集合的继承体系,方法参数中可以传入泛型类型为Fruit的Collection下的所有子类型。

如果有这样的需求List<Fruit>和List<Apple>想使用同样的方法,那么我们该怎么样定义参数列表呢?

可以使用extends关键字来限制泛型参数的适用范围,List<T extends Fruit> 表示泛型实际参数可以是所有继承自Fruit的类,如lApple等。

小结

泛型类和普通类一样,可以扩展或实现其他的泛型类或接口。ArrayList<E>实现了List<E>接口,一个ArrayList<Apple>可以转化为List<Apple>,而一个ArrayList<Apple>并不是一个List<Fruit>或者ArrayList<Fruit>。

如果我们要实现List<Fruit>和List<Apple>之间的关联,可以使用泛型通配符在定义方法的时候指明这个List<? extends Fruit>来实现关联。

 

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。


目录
相关文章
|
1天前
|
安全 Java 开发者
Java一分钟之-文件与目录操作:Path与Files类
【5月更文挑战第13天】Java 7 引入`java.nio.file`包,`Path`和`Files`类提供文件和目录操作。`Path`表示路径,不可变。`Files`包含静态方法,支持创建、删除、读写文件和目录。常见问题包括:忽略异常处理、路径解析错误和权限问题。在使用时,注意异常处理、正确格式化路径和考虑权限,以保证代码稳定和安全。结合具体需求,这些方法将使文件操作更高效。
11 2
|
1天前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
19 3
|
1天前
|
安全 Java 数据安全/隐私保护
Java一分钟之-Java反射机制:动态操作类与对象
【5月更文挑战第12天】本文介绍了Java反射机制的基本用法,包括获取Class对象、创建对象、访问字段和调用方法。同时,讨论了常见的问题和易错点,如忽略访问权限检查、未捕获异常以及性能损耗,并提供了相应的避免策略。理解反射的工作原理和合理使用有助于提升代码灵活性,但需注意其带来的安全风险和性能影响。
23 4
|
1天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
45 3
|
1天前
|
Java
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
|
1天前
|
存储 安全 Java
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
|
1天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
15 0
|
1天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
21 0
|
1天前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
8 0
|
1天前
|
SQL Java 数据库连接
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
10 0