定义:在java1.5之后推出的。
泛型又叫参数化类型或者类型参数化,在不创建新的类型的情况下,通过泛型指定不同类型来控制形参具体限制的类型,姑且把声明在类上的泛型也叫形参。
泛型应用的意义:
- 在编译期间确认类型,保证编译阶段时的类型不会出错。
- 避免强制转换逻辑。
- 可以提高代码的可重用性和增加程序的灵活性。
注意事项:
泛型的类型擦除:java的泛型只在编译阶段有效,泛型可以在逻辑上分成多种不同的类型,比如List<String> 与 List<Integer> 可以在逻辑上看作是不同的类型,但实质上是同一种类型List,因为java会在编译之后实施去泛型化操作。
证明:
泛型的使用:
- 泛型必须要先声明后才能使用。就像变量似的。
- 泛型采用一对尖括号声明<>。
- 声明一般采用单个大写字母表示,比如 <K,V>等。
- 泛型的声明和使用分为泛型类,泛型接口,泛型方法三种。
泛型类:
定义:声明在类上的泛型。
//泛型参数在类上声明了,可以在类中使用非静态元素使用。
public class TypeDemo<E,V> {
public V value;
private E element;
//这个是错误的,在类上定义的参数不能在静态变量上使用。
// 因为静态变量是类级别的,而在类上定义的泛型参数是对象级别的。
private static V value2;
public E getElement(){
return element;
}
/**
* 这个也是错误的,因为静态方法是类级别的,
* 而在类上定义的泛型参数是对象级别的。如果要在静态方法中使用泛型,
* 可以定义泛型方法。
* @return
*/
public static V getValue(){
return null;
}
}
//也可以在继承时使用泛型参数。
public class TypeDemoImpl extends TypeDemo<String,Integer> {
}
//也可以在继承时继续声明参数
public class TypeDemoImpl<E,V> extends TypeDemo<E,V> {
}
泛型接口的使用:
例子:List Map<K,V>。
泛型接口与泛型类类似。
public interface TypeInterface<K,V> {
K say();
V goodBye();
}
public class TypeInterfaceImpl implements TypeInterface<String,Integer> {
@Override
public String say() {
return null;
}
@Override
public Integer goodBye() {
return null;
}
}
public class TypeInterfaceImpl<K,V> implements TypeInterface<K,V> {
K key;
@Override
public K say() {
return null;
}
@Override
public V goodBye() {
return null;
}
}
}
泛型方法的使用:
成员方法可以直接使用类上声明的泛型参数,也可以在方法上自己声明泛型参数,但是静态方法要使用泛型就必须自己声明泛型参数。
public class TypeDemo<E,V> {
public V value;
private E element;
//这是使用类上声明的泛型参数E
public E getElement(){
return element;
}
//这是在成员方法上声明自定义泛型参数S
public <S> void say(S s){
}
/**
* 这是在静态方法上声明自定义的泛型参数R
* @return
*/
public static <R> R getValue(R role){
return role;
}
public static void main(String[] args) {
//使用泛型
TypeDemo<String,Integer> stringIntegerTypeDemo = new TypeDemo<>();
String element = stringIntegerTypeDemo.getElement();
Integer value = stringIntegerTypeDemo.value;
stringIntegerTypeDemo.say(true);
List<String> strings = TypeDemo.getValue(new ArrayList<>());
List<String> strings1 = stringIntegerTypeDemo.getValue(new ArrayList<>());
}
}
泛型通配符:
只能在定义方法时的形参使用,限制调用方法时实参的类型。
<?> //无边界,表示调用该方法时传递的实参可以是任意类型。
<? extends E> //上边界,表示调用该方法时传递的实参只能是E类型或者E类型的子类,E可以是真正的类型比如Number,也可以是已经声明好的泛型参数。
<? super E> //下边界,表示调用该方法时传递的实参只能是E类型获取E类型的父类或接口类,E可以是真正的类型比如Number,也可以是已经声明好的泛型参数。
这是Number类继承关系的类图:
public class TongPeiFuDemo<K,V> {
//无边界。调用该方法传递的实参可以任意类型的List
public void sayHello(List<?> list){
}
//上边界,调用该方法传递的实参只能是K或者K的子类的List
public void sayHelloExtendsK(List<? extends K> list){
}
//上边界,调用该方法传递的实参只能是Number或者Number的子类的List
public void sayHelloKExtendsNumber(List<? extends Number> list){
}
//下边界,调用该方法传递的实参只能是K或者K的父类或接口的List
public void sayHelloSuperK(List<? super K> list){
}
//下边界,调用该方法传递的实参只能是Number或者Number的父类或接口的List
public void sayHelloSuperNumber(List<? super Number> list){
}
public static void main(String[] args) {
TongPeiFuDemo<Number,Object> stringObjectTongPeiFuDemo = new TongPeiFuDemo<>();
//测试无边界:多种类型的List都可以。
stringObjectTongPeiFuDemo.sayHello(new ArrayList<String>());
stringObjectTongPeiFuDemo.sayHello(new ArrayList<Map<String,ObjectList>>());
stringObjectTongPeiFuDemo.sayHello(new ArrayList<Integer>());
//测试上边界,此时的K泛型参数被赋予了Number类型
//因为上边界是number,所以Number型的List可以
stringObjectTongPeiFuDemo.sayHelloExtendsK(new ArrayList<Number>());
//因为Integer是Number的子类,所以可以
stringObjectTongPeiFuDemo.sayHelloExtendsK(new ArrayList<Integer>());
//因为String与Number没有继承关系,所以报错
stringObjectTongPeiFuDemo.sayHelloExtendsK(new ArrayList<String>());
//因为Object是Number的父类,超越了上边界,所以会报错
stringObjectTongPeiFuDemo.sayHelloExtendsK(new ArrayList<Object>());
//测试下边界
//因为下边界是number,所以Number型的List可以
stringObjectTongPeiFuDemo.sayHelloSuperNumber(new ArrayList<Number>());
//因为Object是Number的父类。处于下边界之上,所以可以。
stringObjectTongPeiFuDemo.sayHelloSuperNumber(new ArrayList<Object>());
//因为String与Number没有继承关系,所以报错
stringObjectTongPeiFuDemo.sayHelloSuperNumber(new ArrayList<String>());
//因为Integer是Number的子类,超越了下边界,所以报错
stringObjectTongPeiFuDemo.sayHelloSuperNumber(new ArrayList<Integer>());
}
}
还可以在类或者接口上限制泛型参数类型,但是不能使用通配符。
public class ClassLimit<E extends Number> {
}
public interface InterfaceLimit<E extends Number>{
}