Java基础4
泛型
泛型:泛指任意类型,又叫参数化类型,将具体的类型 参数化,类似于方法的参数,在使用时传入具体的类型。
<数据类型> 只能是引用类型;
使用泛型的意义:
1.代码复用,使得多种数据类型可以执行相同的代码;
2.类型安全,类型错误在编译时就能发现;
2.不需要强制类型转换,泛型中的类型在使用时指定;
泛型的使用方式
泛型类:
public class Gen<T> {
//成员变量可以使用类型T
private T name;
//成员方法可以使用类型T
public T getName() {
return this.name;
}
//静态方法 不可以使用类型T
//public static void print(T t) {
// System.out.println(t);
//}
//除非把静态方法 定义成泛型方法
public static <T> void print(T t) {
System.out.println(t);
}
}
泛型接口:
public interface Inter<T> {
void show(T t);
}
其实现类可以明确泛型T的具体类型
public class InterImpl implements Inter<String> {
@Override
public void show(String str) {
System.out.println(str);
}
}
也可以不明确泛型T的具体类型,实现类继续定义泛型
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
泛型方法:
public <T> T test(T t) {
return t;
}
<T>
表示 声明泛型类型T
;
T
表示 返回值类型;
传进来是什么类型,返回就是什么类型;
集合类泛型的使用:
JDK7之前:
ArrayList<String> list = new ArrayList<String>();
JDK7之后:
ArrayList<String> list = new ArrayList<>();
后面的<>
内可以不写数据类型,因为编译器可以从前面的中自动推断出来,这叫做菱形泛型。
public void test(List<Object> list) {
System.out.println(list);
}
test
方法中要求传入List<Object>
类型的参数,那就只能传入List<Object>
类型的;要想传入List<String>
类型的参数就会报错。
因为 虽然String和Object有继承关系,但List<Object>
和List<Object>
却是毫无关系的!
要想让test
方法中可以传入任意类型的List参数,可以使用通配符?
,即
public void test(List<?> list) {
System.out.println(list);
}
无界通配符 ?
符号?
可以匹配任意类型,但是它的类型是不确定的,就只能调用对象 与类型无关的方法,不能调用对象 与类型有关的方法。比如List<?> list
中不能调用add()
方法。
T
是一个确定的类型,通常用于泛型类、泛型接口和泛型方法的定义;
?
是一个不确定的类型,只能用于声明变量或者形参上,不能用于泛型类、泛型接口和泛型方法的定义上。
两个T
一定表示同一个类型;
两个?
不一定表示同一个类型;
比如:
public <T> void test(List<T> l1, List<T> l2) {};//l1和l2的元素类型一定相同
public void test(List<?> l1, List<?> l2) {};//l1和l2的元素类型不一定相同
上界通配符 <? extends E>
表示泛型中的参数只能是E 或者E的子类;主要用于读数据
下界通配符 <? super E>
表示泛型中的参数只能是E 或者E的父类;主要用于写数据
泛型类型擦除:
JVM并不知道泛型的存在,因为泛型在编译阶段就已经被替换为具体类型了,即类型擦除。
擦除规则:
若泛型没有限定<T>
、<?>
,则替换为Object
;
若有限定<T extends Number>
,则替换为Number
。