Java 学习笔记——泛型
2015-10-14 15:55
253 查看
1. 定义一个泛型类
类型变量 T 表示任意类型(也可以用临近的字母 U、S 表示),Java 中使用 E 表示集合元素类型,K,V 分别表示表的 关键字和值 类型。可以定义多个类型变量如 class Pair<T,U>{ ... } 类型变量用逗号隔开。
2. 定义泛型方法
3. 限定类型变量
如果限定多个类型,则用符号 & 隔开,如 <T extends Comparable<T> & Serializable>,限定类型的顺序影响类型擦除后表示的类型,取第一个限定类型作为擦除后类型。比如 <T extends Comparable<T> & Serializable> 类型擦除后会用 Comparable 类替换 T。
4. 泛型类的类型擦除
在 Java 虚拟机中,不存在泛型类型对象,所有的对象都属于普通的类。定义一个泛型类型,会自动提供一个对应的原始类型,原始类型名是去掉泛型类型变量后的类名,并擦除类型变量,替换成限定的类型(没有限定类型就是 Object)。比如 Pair<T> 泛型类的原始类型是:
当程序调用泛型方法时,会先调用原始类型的方法,再强制类型转换成需要的类型。如:Pair<Employee> buddies = new Pair<Employee>();
Employee employee = buddies.getFirst();
buddies.getFirst() 返回 Object 类型,然后强制转换成 Employee 类型
5. 泛型方法的类型擦除
泛型方法的类型擦除也是把类型变量转换成限定类型,无限定类型就是 Object,如:// 泛型方法
public void <T> method(T extends Comparable param) {}
// 类型擦除后
public void Comparable method(Comparable param){} 如果泛型类的子类想要覆盖父类方法,编译器会在子类中生成一个桥方法,用于实现覆盖父类方法,例如:
通过桥方法实现覆盖父类的 setSecond 方法。原因是 DateInterval 类在类型擦除后,从父类继承的 setSecond 方法是:public void setSecond(Object second){},而自身的setSecond(Date
second){} 并没有覆盖掉父类的 setSecond 方法(方法名相同,方法参数(顺序、类型)不同,属于方法重载),所以编译器通过桥方法实现方法的覆盖。
6. 通配符
符号 ? 表示通配符,使用通配符为泛型类指定子类型和父类型,例如
Pair<Manager> 是 Pair<? extendsEmployee> 的子类,而 Pair<Manager> 和 Pair<Employee> 之间并没有关系,虽然 Manager 是 Employee 的子类。Pair<?
super Manager> 用于指定父类。
注:通配符不是类型变量,比如 Pair<?> 的 ? getFirst() 是非法的。
class Pair<T> { private T first; private T second; public Pair() { first = null; second = null; } public Pair(T first, T second) { this.first = first; this.second = second; } public void setFirst(T first) { this.first = first; } public T getFirst() { return first; } public void setSecond(T second) { this.second = second; } public T getSecond() { return second; } }
类型变量 T 表示任意类型(也可以用临近的字母 U、S 表示),Java 中使用 E 表示集合元素类型,K,V 分别表示表的 关键字和值 类型。可以定义多个类型变量如 class Pair<T,U>{ ... } 类型变量用逗号隔开。
2. 定义泛型方法
@SuppressWarnings("unchecked") public static <T> T getMiddle(T... a) { return a[a.length / 2]; }
3. 限定类型变量
public static <T extends Comparable<T>> T min(T[] a) { if (a == null || a.length == 0) return null; T smallest = a[0]; for (int i = 1; i < a.length; i++) if (smallest.compareTo(a[i]) > 0) smallest = a[i]; return smallest; }
如果限定多个类型,则用符号 & 隔开,如 <T extends Comparable<T> & Serializable>,限定类型的顺序影响类型擦除后表示的类型,取第一个限定类型作为擦除后类型。比如 <T extends Comparable<T> & Serializable> 类型擦除后会用 Comparable 类替换 T。
4. 泛型类的类型擦除
在 Java 虚拟机中,不存在泛型类型对象,所有的对象都属于普通的类。定义一个泛型类型,会自动提供一个对应的原始类型,原始类型名是去掉泛型类型变量后的类名,并擦除类型变量,替换成限定的类型(没有限定类型就是 Object)。比如 Pair<T> 泛型类的原始类型是:
class Pair { private Object first; private Object second; public Pair() { first = null; second = null; } public Pair(Object first, Object second) { this.first = first; this.second = second; } public void setFirst(Object first) { this.first = first; } public Object getFirst() { return first; } public void setSecond(Object second) { this.second = second; } public Object getSecond() { return second; } }
当程序调用泛型方法时,会先调用原始类型的方法,再强制类型转换成需要的类型。如:Pair<Employee> buddies = new Pair<Employee>();
Employee employee = buddies.getFirst();
buddies.getFirst() 返回 Object 类型,然后强制转换成 Employee 类型
5. 泛型方法的类型擦除
泛型方法的类型擦除也是把类型变量转换成限定类型,无限定类型就是 Object,如:// 泛型方法
public void <T> method(T extends Comparable param) {}
// 类型擦除后
public void Comparable method(Comparable param){} 如果泛型类的子类想要覆盖父类方法,编译器会在子类中生成一个桥方法,用于实现覆盖父类方法,例如:
class DateInterval extends Pair<Date> { @Override public void setSecond(Date second) { if (second.compareTo(getFirst()) >= 0) super.setSecond(second); } }编译器会在 DateInterval 类中生成桥方法
public void setSecond(Object second) { setSecond((Date)second); }
通过桥方法实现覆盖父类的 setSecond 方法。原因是 DateInterval 类在类型擦除后,从父类继承的 setSecond 方法是:public void setSecond(Object second){},而自身的setSecond(Date
second){} 并没有覆盖掉父类的 setSecond 方法(方法名相同,方法参数(顺序、类型)不同,属于方法重载),所以编译器通过桥方法实现方法的覆盖。
6. 通配符
符号 ? 表示通配符,使用通配符为泛型类指定子类型和父类型,例如
Pair<Manager> 是 Pair<? extendsEmployee> 的子类,而 Pair<Manager> 和 Pair<Employee> 之间并没有关系,虽然 Manager 是 Employee 的子类。Pair<?
super Manager> 用于指定父类。
注:通配符不是类型变量,比如 Pair<?> 的 ? getFirst() 是非法的。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统