Android面试题详解之List\<String\>能否转为List\<Object\>

List<String>能否转为List<Object>

详细讲解

享学课堂移动互联网系统课程:架构师筑基必备技能《架构设计中必不可少的泛型-Java泛型的定义与原理》

这道题想考察什么?

  1. 是否熟悉泛型的继承模式?
  2. 是否了解 Java 泛型的真正实现机制?
  3. 是否泛型解决多态的问题,利用“桥方法”

考察的知识点

  1. 泛型的继承模式?
  2. Java 泛型的真正实现机制
  3. 泛型解决多态的问题,利用“桥方法”

考生应该如何回答

Java的泛型是伪泛型,编译时会进行泛型擦除(《3.1 泛型是什么,泛型擦除呢?》)。

因此List<Number>和 List<Integer> 最终的类型都被擦除了,无论是List<String> 还是 List<Object> 都是List类型。

既然存在泛型擦除,但是下面的代码无法通过编译检查:

List<String> strs = new ArrayList<Integer>();
List<Object> objects = strs;

编译器会帮我我们检查明显的代码问题,因此上述代码会报错,这是编译器的行为,但是如果我们将代码改为:

List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;

注意,每条语句我们增加了强转声明。此时编译器能够成功完成编译。因此List<String>其实能够强转为List<Object>。但是存在隐患:

List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;
objects.add(123);
String str =  strs.get(0);

上述代码使用objects(List<Object> )向集合中增加整型数据:123。然后通过 strs获取数据时,因为其类型为List<String>,但是真实数据类型为整型。此时就会发生运行时异常:

Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String

3.3 Java的泛型中super 和 extends 有什么区别?

详细讲解

享学课堂移动互联网系统课程:架构师筑基必备技能《架构设计中必不可少的泛型-Java泛型的定义与原理》

这道题想考察什么?

掌握PECS原则,灵活运用泛型

考察的知识点

泛型上下边界

考生应该如何回答

在Java的泛型语法中,可以使用super和extends关键字指定泛型的上下边界。

extends

? extends T为上界通配符,也就是说限制类型只能是T 或者 T 的派生类,比如我们存在代表水果的Fruit类,代表苹果的Apple类以及代表香蕉的Banana类。苹果与香蕉都是水果,因此:

class Fruit{
    
    }
class Apple extends Fruit{
    
    }
class Banana extends Fruit{
    
    }

那么下面我们使用List集合作为盘子来装水果:

List<? extends Fruit> plates = new ArrayList<>();

但是当我们希望往plates中放入苹果或者香蕉时会发现,plates中无法放入任何元素,只能从plates中取出元素。

List<? extends Fruit> plates = new ArrayList<>();
plates.add(new Apple());  //Error
plates.add(new Banana()); //Error

Fruit fruit1 = paltes.get();
Object fruit1 = paltes.get(); 
Apple fruit1 = paltes.get(); //Error

其实原因在于,编译器只知道List中是Fruit或者其派生类,但是具体类型无从得知,可能是香蕉也可能是苹果甚至其他水果类。所以在add时,编译器无法判断你给的类型是不是能够和容器类型匹配,因此对于上界,不能往里存,只能往外取。

super

? super T 为通配符下界,也就是说限制类型只能是T 或者T的超类。

List<? super Fruit> plates = new ArrayList<>();
Fruit fruit = plates.get(0);//Error
Apple apple = plates.get(0);//Error
Object object = plates.get(0);

plates.add(new Apple());
plates.add(new Banana());

下界<? super T>不影响往里存,但往外取只能放在Object对象里。因为List<? super Fruit> 代表该容器元素是Fruit或者Fruit的超类。向容器中存储数据,只需要数据类型是Fruit的派生类即可,因为苹果是水果Fruit,香蕉也是水果Fruit。但是取数据时,无法得知取出来的数据到底时什么类型,所以只能使用Object来表示。

PECS原则

PECS原则即Producer Extends Consumer Super ,生产使用extends,消费使用super。结合上下界的特点可知:

  • 经常读取数据,使用Extends;
  • 经常加入数据,使用Super;

猜你喜欢

转载自blog.csdn.net/Misdirection_XG/article/details/131264734