Java泛型常见面试题

1. Java中的泛型是什么 ? 使用泛型的好处是什么?

  1. 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
  2. 好处:
    1. 类型安全,提供编译期间的类型检测
    2. 前后兼容
    3. 泛化代码,代码可以更多的重复利用
    4. 性能较高,用GJ(泛型JAVA)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件。

2. Java的泛型是如何工作的 ? 什么是类型擦除 ?如何工作?

  1. 如何工作
    1. 类型检查:在生成字节码之前提供类型检查
    2. 类型擦除:所有类型参数都用他们的限定类型替换,包括类、变量和方法(类型擦除)
    3. 如果类型擦除和多态性发生了冲突时,则在子类中生成桥方法解决
    4. 如果调用泛型方法的返回类型被擦除,则在调用该方法时插入强制类型转换
  2. 类型擦除:
    泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如 List< String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。

3. 使用Java泛型要注意什么?

  1. 不能使用基本数据类型如int,而是使用Integer等包装类型;
  2. 这种,T是要使用大写的T,而不能使用小写
  3. 泛型类不可以继承Exception类,即泛型类不可以作为异常被抛出
  4. 不可以定义泛型数组
  5. 不可以用泛型构造对象,即:first = new T(); 是错误的
  6. 在static方法中不可以使用泛型,泛型变量也不可以用static关键字来修饰
  7. 不要在泛型类中定义equals(T x)这类方法,因为Object类中也有equals方法,当泛型类被擦除后,这两个方法会冲突

4. 什么是泛型中的限定通配符和非限定通配符?

限定通配符对类型进行了限制。有两种限定通配符:

  1. 一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界
  2. 另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界
  3. 泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面<?>表 示了非限定通配符,因为<?>可以用任意类型来替代

5. List<? extends T>和List <? super T>之间有什么区别?

  1. 这两个List的声明都是限定通配符的例子
  2. List<? extends T>可以接受任何继承自T的类型的List
  3. List<? super T>可以接受任何T的父类构成的List。例如List<? extends Number>可以接受List< Integer>或List< Float>

6. 如何编写一个泛型方法,让它能接受泛型参数并返回泛型类型?

编写一个泛型方法,需要用泛型类型来替代原始类型,比如使用T, E or K,V等被广泛认可的类型占位符。最简单的情况下,一个泛型方法可能会像这样:

	public V put(K key, V value) {
		return cache.put(key, value);
	}

7. 可以把List传递给一个接受List参数的方法吗?

这样做的话会导致编译错误,因为List< Object>可以存储任何类型的对象包括String, Integer等等,而List< String>却只能用来存储Strings。

	List<Object> objectList;
	List<String> stringList;
	objectList = stringList; //compilation error incompatible types

8. Array中可以用泛型吗?

Array事实上并不支持泛型,建议使用List来代替Array,因为List可以提供编译期的类型安全保证,而Array却不能。

9. 如何阻止Java中的类型未检查的警告?

  1. 如果把泛型和原始类型混合起来使用,例如下列代码,java 5的javac编译器会产生类型未检查的警告,例如
	List<String> list = new ArrayList()

注意: xxx.java使用了未检查或称为不安全的操作
2. 这种警告可以使用@SuppressWarnings(“unchecked”)注解来屏蔽

10. Java中List< Object>和原始类型List之间的区别?

  1. 原始类型和带参数类型< Object>之间的主要区别是,在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用Object作为类型,可以告知编译器该方法可以接受任何类型的对象,比如String或Integer
  2. 它们之间的第二点区别是,你可以把任何带参数的类型传递给原始类型List,但却不能把List< String>传递给接受 List< Object>的方法,因为会产生编译错误

11. Java中List<?>和List之间的区别是什么?

List<?> 是一个未知类型的List,而List 其实是任意类型的List。你可以把List< String>, List< Integer>赋值给List<?>,却不能把List< String>赋值给 List< Object>

	List<?> listOfAnyType;
	List<Object> listOfObject = new ArrayList<Object>();
	List<String> listOfString = new ArrayList<String>();
	List<Integer> listOfInteger = new ArrayList<Integer>();
	listOfAnyType = listOfString; //legal
	listOfAnyType = listOfInteger; //legal
	listOfObjectType = (List<Object>) listOfString; //compiler error – in-convertible types	

12. List和原始类型List之间的区别?

带参数类型是类型安全的,而且其类型安全是由编译器保证的,但原始类型List却不是类型安全 的。不能把String之外的任何其它类型的Object存入String类型的List中,而可以把任何类型的对象存入原始List中。使用泛型的带参数类型不需要进行类型转换,但是对于原始类型,则需要进行显式的类型转换

	List listOfRawTypes = new ArrayList();
	listOfRawTypes.add(“abc”);
	listOfRawTypes.add(123); //编译器允许这样 – 运行时却会出现异常
	String item = (String) listOfRawTypes.get(0); //需要显式的类型转换
	item = (String) listOfRawTypes.get(1); //抛ClassCastException,因为Integer不能被转换为String
	List<String> listOfString = new ArrayList();
	listOfString.add(“abcd”);
	listOfString.add(1234); //编译错误,比在运行时抛异常要好
	item = listOfString.get(0); //不需要显式的类型转换 – 编译器自动转换

13. 编写一段泛型程序来实现LRU缓存?

提示:LinkedHashMap可以用来实现固定大小的LRU缓存,当LRU缓存已经满 了的时候,它会把最老的键值对移出缓存。LinkedHashMap提供了一个称为removeEldestEntry()的方法,该方法会被put() 和putAll()调用来删除最老的键值对

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值