JAVA笔记六:泛型程序设计

一、简单泛型类

1.1 为什么要使用泛型程序设计

泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。使得程序具有更好的可读性和安全性。

1.2 定义简单泛型类

一个泛型类就是具有一个或多个类型变量的类。

public class Pair<T, U>{...}
private T first;
//类型变量使用大写形式且比较短,使用变量E表示集合的元素类型,K和V分别表示表的关键字与值得类型。
Pair<String> ps = new Pair<Stirng>();

1.3 泛型方法

class ArrayAlg{
	public static <T> T getMiddle(T... a){
		return a[a.length / 2];
	}
}
String middle = ArryAlg.<String>getMiddle("John", "Q.", "Public");
String middle = ArrayAlg.getMiddle("John", "Q.", "Public");//可以省略,由编译器推断,但是有时候需要
//可以在普通类中定义泛型方法

1.4 类型变量的限定

有时候类或方法需要对类型变量加以约束。例如要计算泛型数组内最小元素,需要保证该类型有compareTo方法,可以通过限定实现了ComparaTo接口。
public static <T extends Comparable> T min(T[] a)...//C++则不能对模板参数类型加以限制。注意是Extend,意为绑定
T extends Comparable & Serializable //可以有多个绑定,绑定不只是接口,还可以是类,但是只能有一个类,且排在第一位

二、泛型代码和虚拟机

虚拟机没有泛型类型对象——所有对象都属于普通类。

2.1 类型擦除

无论何时定义一个泛型类型,都自动提供了一个相应的原始类型。无限定用Object,有限定用第一个限定的类型变量。

2.2 翻译泛型表达式

编译器会插入强制类型转换。

2.3 翻译泛型方法

类方法中的泛型类型被擦除后会与多态发生冲突。编译器会在泛型类种生成一个桥方法
Java泛型转换的事实:

  • 虚拟机中没有泛型,只有普通的类和方法
  • 所有的类型参数都用它们的限定类型替换
  • 桥方法被合成来保持多态
  • 为保持类型安全性,必要时插入强制类型转换

2.4 遗留代码问题

@SuppressWarnings("unchecked")//这个注解会关闭对语句或方法中所有代码的检查

三、 约束与局限性

3.1主要阐述Java泛型时需要考虑的一些限制,大多数限制都是由类型擦除引起的。

  1. 不能用基本类型实例化类型参数

  2. 运行时类型查询只适用于原始类型
    a instanceof Pair<String>,getClass()// Pair.class,不会有具体的类型

  3. 不能创建参数化类型的数组
    Pair<String>[] table = new Pair<String>[10] // Error

  4. Varargs警告
    java不支持泛型类型的数组,单数可以向参数可变的方法传递一个泛型类型的实例。但是会得到一个警告。有两种方法可以抑制这个警告。

    //@SuppressWarnings("unchecked")//1
    //@SafeVarags//2
    public static<T> void addAll(Collection<T> coll, T...ts){
    	for(T t: ts) coll.add(t);
    }
    
  5. 不能实例化类型变量
    即在泛型类或者方法内部不能使用new T()

  6. 不能构造泛型数组
    public static <T extends Comparable> T[] minmax(T[] a) {T[] mm = new T[2] ;...} // Error,类型擦除

  7. 泛型类的静态上下文中类型变量无效
    禁止使用带有类型变量的静态域和方法

    public class Singleton<T>{
    	private static T singleInstance; // Error,类型擦除后就剩下一个Object静态变量,不能为每个泛型生成一个静态变量
    }
    
  8. 不能抛出或捕获泛型类的实例
    泛型类不能拓展Throwable接口public class Problem<T> extends Exception {...} // Error
    但是使用类型变量是允许的
    publicstatic <T extends Throwable> void doWork(T t) throws T // OK

  9. 可以消除对受查异常的检查
    @SuppressWarnings("unchecked")//这个注解会关闭对语句或方法中所有代码的检查

  10. 注意擦除后的冲突

3.2 泛型类型的继承规则

泛型与Java数组之间的重要区别。可以将Manager[]数组赋给一个类型为Employee[] 的变量。但泛型不行。
注意继承范例可以参照List与ArrayList。

3.3 通配符类型

  1. 概念,通配符类型中,允许类型参数变化。
    Pair<? extends Employee>//表示泛型Pair类型,它的类型参数是Employee的子类,如Pair<Manager>,但不是Pair<String>

  2. 通配符的超类型限定
    通配符限定与类型变量限定十分类似,但是,还有一个附加能力,可以指定一个超类型限定。
    ? super Manager//这个通配符限制为Manager的所有超类型
    直观地讲,带有超类型限定的通配符可以向泛型对象写入,带有子类限定的通配符可以从泛型对象读取。

  3. 无限定通配符

    Pair<?>
    ? getFirst()
    void setFirst(?)//Pair<?>和Pair本质不同在于,可以用任意Object对象调用原始Pair类的setObject方法
    
    public static <T> void swapHelper(Pair<T> p){ // 通配符捕获样例
    T t = p.getFirst();
    p.setFirst(p.getSecond());
    p.setSecond(t);
    }
    public static void swap(Pair<?>p) { swapHelper(p); }
    
  4. 通配符捕获
    交换元素时需要暂存中间变量,但是不能使用?作为一种类型,因此需要用泛型来作为中间函数捕获。

四、反射与泛型

反射允许你在运行时分析任意的对象。如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值