Android面试题之Java 泛型和Kotlin泛型

简介: **Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

定义:JDK5引入的一种参数化类型特性

继承和实现接口可以多个
static class A{
   }
static interface B{
   }
static interface C{
   }

//类必须在接口的前面
static class D<T extends A & B & C>{
   }
泛型原理

泛型擦除:

  • 做类型检查,T如果有做类型限制,会转化为第1种限制,否则会擦除为object
  • 生成桥方法,里面调用对应的接口方法,调用的时候会进行类型的强转,转为T的限制类型
  • 泛型擦除后,字节码中没有泛型信息了,但是类的常量池里保留了泛型信息。反射的时候提供了一套API可以拿到,比如getGenericType()
泛型带来的问题
  1. 泛型类型变量不能使用基本类型
比如没有ArrayList<int>,只有ArrayList<Integer>,
当泛型擦除后,ArrayList的原始类中的类型变量T替换成了Object,但Object不能存放基本数据类型
  1. 不能使用instanceof运算符
因为泛型擦除后,ArrayList<String>只剩下原始类型,泛型信息String不存在了
  1. 泛型在静态方法和静态类中的问题

    因为泛型类中的泛型参数的实例化是在定义泛型类型对象时候指定的,而静态成员是不需要使用对象来调用的,所有对象都没创建,无法确定泛型参数;

    静态方法中是可以的,因为调用的时候可以确定参数中的泛型类型

  2. 泛型类型中的方法冲突

    因为擦除后2个equales方法变成一样的了,参数都会变成object

@Override
public boolean equals(Object o) {
   
    super.equals(o);
}
@Override
public boolean equals(T o) {
   
    super.equals(o);
}
  1. 没法创建泛型实例,因为类型不确定
public static <E> void append(List<E> list){
   
    //编译会报错
    E element = new E();
    list.add(element);
}
不过可以通过反射来创建
 public static <E> void append(List<E> list, Class<E> cls) throws Exception {
   
    E element = cls.newInstance();
    list.add(element);
}
  1. 没有泛型数组,因为数组遵循协变原则
协变:Apple extend Fruit,Apple[] 的父类是Fruit[]
泛型,继承和子类
  • 给定两种具体的类型 A和B,无论A和B是否相关,MyClass和MyClass都没有半毛钱关系;
比如Apple继承自Fruit,那Plate<Fruit>和Plate<Apple>也没有任何关系;
也就是说苹果是水果,但装苹果的盘子不是装水果的盘子
  • 继承关系中,泛型可以有多个,但如果有一个泛型参数是一样的,继承关系就存在的,不会因为有的类多个个泛型参数,继承关系就不在了
比如Plate<Apple> <--AIPlate<Apple> <--BIgPlate<Apple> <-- ColorPlate<String, Apple>
泛型和通配符

通配符让泛型转型更灵活

  • Plate<?> 非限定通配符,是一个泛型类型 ?表示未知,等价于 Plate<? extends Object>;副作用是既不能读也不能写;可以促使进行安全检查

  • List和List<?>,前者不会进行安全检查,后者会进行类型的安全检查

限定通配符

  • Plate<? extends T> 限定上届,能读不能写,类似于生产者
  • Plate<? super T> 限定下届,能写不能读,类似于消费者
通配符总结
  • 如果只需要从集合中获得类型T,使用<? extends T>;

  • 如果只需要将类型T放到集合中,使用<? super T>;

  • 既要获取又要放置元素,则不使用通配符

用<? extends Fruit>的后遗症

<? extends Fruit>是上届通配符,相当于“只读”

Plate<? extends Fruit> fruitPlate = plate(Plate<Apple> 类型)
//下面会报错,因为具体类型丢失了,只能是Fruit
fruitPlate.set(new Apple())

解决方案:可以用反射来set,但是安全性降低

Method set = friutPlate.getClass().getMethod("set", Object.class);
set.invoke(fruitPlate, new Banana())
//什么都能set,安全性降低
set.invoke(fruitPlate, new Beef())

面试题

1、Java泛型原理?什么是泛型擦除机制?

Java泛型是JDK5新引入的特性,为了向下兼容,虚拟机其实不支持泛型,所以Java实现的是伪泛型机制,也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本就不存在泛型信息

2、Java编译器具体是如何擦除泛型的

  • 检查泛型类型,获取目标类型

  • 擦除类型变量,并替换为限定类型。如果泛型类型的类型变量没有限定(\),则Object为原始类型;

 如果有限定(\<T extends XClass>),则用XClass作为限定类型;
 如果有多个限定(T extends XClass1 & XClass2),则使用第一个边界XClass1作为原始类。
  • 在必要时插入类型转换以保持类型安全

  • 生成桥方法以在扩展时保持多态性

Kotlin泛型

Kotlin的泛型可以看文章:Android面试题之Kotlin泛型和reified关键字


欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
27天前
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
29 9
|
3月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
3月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
3月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
100 4
|
4月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
68 1
|
4月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
151 2
|
4月前
|
Android开发 Kotlin
Android面试题之Kotlin中如何实现串行和并行任务?
本文介绍了 Kotlin 中 `async` 和 `await` 在并发编程中的应用,包括并行与串行任务的处理方法。并通过示例代码展示了如何启动并收集异步任务的结果。
56 0
|
4月前
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
71 0
|
4月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
55 0
|
5月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
211 1

热门文章

最新文章