实现了参数化类型的概念 通过泛型解耦类的方法与所使用的类型之间的约束
参数化类型 指定一个类型作为实参 由修改该类的代码所提供的类型 来将该类进行参数化
具体类型实例化 插入一个实际的java类型作为参数
用途举例
- 创造容器类: 用来指定容器类要持有什么类型的对象,而且由编译器来保证类型的正确性
- 实现元组 (将一组对象直接打包存储于其中的一个单个对象),允许读取其中的元素,但不允许修改
- 实现堆栈类
- 实现生成器
泛型类 语法: 可见修饰符 class 类名 <类型参数> [extends | implement] .. ( <类型参数>添加在类名之后)
public class TwoTuple <A,B>{
public final A first;
public final B second;
public TwoTuple(A a,B b){
first = a;
second = b;
}
}
//通过继承机制 实现长度更长的元组
public class ThreeTuple <A,B,C> extends TowTuple{
public final D third;
public ThreeTuple(A a,B b,C c){
super(A a,B b;
third = c;
}
}
-
非泛型子类: 必须 填充父类型的参数类型
-
class DateList extends ArrayList<Date>{ } DataList dataList = new DateList(); dateList.add( new Date() ); List<Date> ld = dateList;
-
泛型子类
- 和父类共享类型变量 该类型变量通过向上传递可以对父类进行实例化
-
class AjustableTrap<T> extends Trap<T>{ }
使用泛型类
-
List <String> words = new LinkedList<String>(); //JDK7之后可以 在声明引用时指定类型 创建对象时不用再写类型 List <String> words = new LinkedList<>();
泛型接口:接口名 <类型参数> [implement ] .. ( <类型参数>添加在接口名之后)
public interface Generator<T> { //习惯上以单个大写字母表示 类型参数
T next();
}
泛型方法 语法: 可见修饰符 <类型参数> 返回类型 (形参) .. ( <类型参数>添加在返回类型之前)
-
方法的泛型与类的泛型没有必然联系,尽量用方法的泛型取代类的泛型
-
若方法的泛型与类的泛型 类型参数 重名,则在该方法内 方法的泛型将覆盖类型的参数
-
static方法无法访问泛型类的类型参数, 但static方法可以成为泛型方法
-
实现泛型方法时,可以不指明参数声明 编译器会为我们找出具体的类型 称类型参数推断 (泛型类和泛型接口必须指名参数声明) 类型参数推断仅对赋值操作有效
1.显示的类型说明
在泛型方法中可以显示的指明类型,在点操作符与方法名之间插入尖括号<>,然后把类型置于尖括号之间
对象.<类型参数>方法名()
2.若在定义该方法的内部则
this.<类型参数>方法名()
3.泛型方法为静态static时
类名.<类型参数>方法名()
4.可变参数与泛型方法能很好的共存
//<T>为泛型方法的声明 必须 List<T>为返回值 (List<T>中T的使用是在声明了泛型的情况下)
public static <T> List<T> makeList(T...args){
List<T> result = new ArrayList<T>();
for(T item : args)
result.add(item);
return result;
}//将多个类型为T的参数args 存储在List<T> 中并将其返回
调用 类名.<String>makeList()
泛型也可以应用于内部类以及匿名内部类
泛型与异常
例如 实际使用的是Throwsable的一个类型 <T extends Throwable>
ExceptionTester<T extends Throwable>{ public void test(T exception) throws T{ throw exception; } } try{ new ExceptionTester<ClassNotFoundException>(),test(new ClassNotFoundException() ); } catch( ClassNotFountException e){..}
不能使用泛型来创建新的异常类型
通配符
定义 ? 通配符自身称为 无界限通配符
<? extends 类> 称为 有界限通配符
- 还可以扩展一个或多个接口 用&间隔 同样的 类必须在最左边 <T extends Comparable& Serializable &Iterable>
对于无方法体的接口应排在后面(因为 切换限定)
使用
<?> 使用?代替一个实际的参数类型 表示该类型可以被赋予泛型类型可能的实例化范围中的一种
意义: 通配符实例化允许我们在参数类型上实现多态
通配符表示一种对象或者可能的对象的一个集合
通配符实例化充当了一个变量的类型 不能使用通配符创建一个类的实例 即和new关键字来使用
通配符捕获: 指泛型方法可以操作的参数 其类型为一个类型的通配符实例 就好像已知类型一样
通配符捕获意义: 可以将通配符实例作为参数传入一个真正的泛型中,来避免通配符实例仅能读/写的局限
List<?> anyList = new ArrayLsit<Date>();
可靠类型:指未被擦除修改过的类型 包括 java具体类 基本类型 无界限通配符实例
边界
对参数类型设置边界
上边界
扩展一个类或接口<T extends Employee>
扩展多个接口 多个 <T extends Ranked & Printable>
扩展一个类和多个接口 <T extends 类 & 接口1 &接口2> 类必须出现在最左边
类型变量也可以引用声明其他类型变量
class Foo <A, B extends A>
读 与 写
把一个对象的一个方法获得具体类型的返回值 称为读取一个类型
传递具体类型的参数给对象的方法 称为将对象写入一个类型
List<Date> 可以被读成Date类型 可以写入Date的子类型
通配符实例化 与边界
List<? extends Date> someDateList = new ArrayList<MyDate>(); Date date = someDateList.get(0); //通配符实例化上边界 仅可读 List<? super MyDate> superMydate = new ArrayList<Date>; superMydate.add( new MyDate() );//通配符实例化上边界 仅可写
下边界
<? super MyDate> ?必须是MyDate 或MyDate的父类
只有通配符实例语法可以使用super关键字来表示下界 在泛型类的声明中 类型变量的边界时不能有霞姐的
擦除使用上界来替换其所有的引用 因此运行时类型无法保证这种契约