jdk1.5之后的新特性, jdk1.8之后, 等号右边的泛型不用写
可以在创建对象的时候, 明确类型, 常见在容器中使用
继承接口的泛型
interface MyInterface<T> {
}
实现接口的时候, 指明泛型
class test1 implements MyInterface<String> {
}
实现类也带泛型
class test<T> implements MyInterface<T> {}
泛型方法
直接使用型
class MyMethod <T> {
public void show(T t) {
System.out.println(t);
}
}
调用方法时候明确型
//泛型方法, 不一定在泛型类中声明, 在不是泛型的类中, 也可以使用
public <Q> void method(Q para) {
System.out.println(para);
}
// 调用的时候, 直接传参就行, 自动确认类型
泛型的继承与界定
泛型界定
泛型的界限是很有用的
假如有一个类我们希望他的泛型类型是Number类的子类, 比如是Integer或是Long, 但是泛型本身是不支持不同类型的泛型的, 于是有了泛型界定
我们使用 来表示一个泛型的上界. 也就是说这个T类型, 必须是Number或Number的子类, 可以这样理解, T是继承自Number的类, T也可用通配符?代替
public statci <T extends Number> T add(T a, T b) {
return a + b;
}
// 如上边那个例子, 是一个通用方法, 界定了泛型必须是Number的子类
//同样, 我们使用<T super Integer> 来界定下界. 所有的T类型, 必须是Integer的父类或Integer类
在源码中, 我们经常看到这样的代码
<T extends Comparable<T>>
有的同学可能已经蒙了. 其实这也是一个泛型的界定例子. 虽然他继承的类也是个泛型类, 多了个泛型T
上边这个例子你可以这样理解: T是一个实现了Comparable接口的类. 不实现这个接口就不能作为这个泛型
泛型的继承
当子类继承泛型父类(或者是泛型接口)时候, 有几种情况.
-
父类将泛型指定
这种情况时, 子类并不是一个泛型类, 就是个正常的类
//存在父类 class Father<T> { T name; } class Son extends Father<String> {} //此时, 子类继承过后的代码应该是 class Son { String name; }
-
子类也是个泛型类
这个时候, 子类的泛型T和父类的泛型T是一个泛型, 创建子类的时候,需要给子类泛型确定的类型, 同时, 会把父类的泛型也指定了.
class Son<T> extends Father<T> { public T print(T a) { System.out.println(a); return a; } } //此时, 子类继承过后的代码应该是 class Son { T name; public T print(T a) { System.out.println(a); return a; } }
-
子类拥有其他泛型, 父类指定类型
class Son<T> extends Father<String> { public T print(T a) { System.out.println(a); return a; } } //此时, 子类继承过后的代码应该是这样的, 注意, 继承父类的泛型, 被指定了. 但是, 子类拥有自己的泛型T, 并没有被指定, 所以继承过好如下 class Son<T> extends Father<String> { String name; public T print(T a) { System.out.println(a); return a; } }
-
子类拥有多种泛型
class Son<T, E> extends Father<T> { public E print(E e) { System.out.println(a); return a; } } // 这个时候, 子类的T和父类的T是一个泛型, 继承过后是这样的 class Son <T, E> { T name; public E print(E e) { System.out.println(a); return a; } }
总结
所以对于泛型的继承来讲, 不管子类是不是泛型类, 有多少个泛型类型. 所继承或实现的父类或接口, 必须被指定.
有时候在创建子类对象的时候指定, 有时候在写子类的时候实现,但是,规则就是父类的类型一定要被指定, 不然编译的时候就会报错.