Java泛型是J2 SE1.5引入的特性,本质上是参数化类型,可以用于类、接口、方法的创建中。
泛型的使用
//泛型定义在类
public class Generics<T> {
//实例方法使用类定义泛型
public T test1(T t){
return null;
}
//方法定义泛型
public <K> K test2(){
return null;
}
}
下面看个错误例子
public static ~~V~~ test3(){ return null; }
静态方法使用类上定义的泛型会出错,泛型是在对象创建之后获取,static修饰的是类级别的,加载静态方法时无法获取到泛型。
静态方法可以使用方法级别定义泛型
public static <P> P test4(){ return null;}
接口定义泛型
interface GenericInf<T>{
T add(T a,T b);
T sub(T a,T b);
T mul(T a,T b);
T div(T a,T b);
}
接口泛型实现案例
class DoubleCalc<Double> implements GenericInf<Double>{
@Override
public Double add(Double a, Double b) {
return null;
}
@Override
public Double sub(Double a, Double b) {
return null;
}
@Override
public Double mul(Double a, Double b) {
return null;
}
@Override
public Double div(Double a, Double b) {
return null;
}
}
泛型通配符
- 无界通配符 ?
//接受所有类型
public void border1(ArrayList<?> list){}
- 上界通配符 ? extends Number
// 只允许Number 及Number的子类型 ? extends Object等效于无界
public void border2(ArrayList<? extends Number> list){}
- 下界通配符 ? super Integer
//指定的类型
public void border3(ArrayList<? super Integer> list){}
泛型作用
- 编译类型检查,保证类型安全
- 避免类型转换硬编码
- 提高代码重用性
泛型的本质
泛型不会影响数据的基本类型。在java中泛型是伪泛型,java编译期间会将泛型擦除
public void check1(){
List list = new ArrayList();
List<String> stringList = new ArrayList<String>();
System.out.println(list.getClass() == stringList.getClass());//true
}
验证泛型的编译检查
public void check2() throws Exception{
// 仅在编译期进行类型检查
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
System.out.println(list.size());//2
//当利用反射在运行期间添加元素时 也改变了list的长度
Class<? extends List> clazz = list.getClass();
Method m = clazz.getDeclaredMethod("add", Object.class);
m.invoke(list, new Object());
System.out.println(list.size());//3
}
需要注意的是,由于java泛型擦除的特征,当一个可变泛型的参数指向一个无泛型的参数可能会产生堆污染。
class population{
public static void main(String[] args) {
Set set = new TreeSet();
populate(set);// 没有泛型的set传入到 populate方法中已经发生了堆污染
set.add("abc");// 因此在添加字符串时会报错
}
private static void populate(Set<Integer> set) {
set.add(new Integer(123));
System.out.println(set.size());
}
}
1
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at java.lang.String.compareTo(String.java:111)
at java.util.TreeMap.put(TreeMap.java:568)
at java.util.TreeSet.add(TreeSet.java:255)
at com.zld.cloud.population.main(Generics.java:67)
泛型擦除 对污染问题发生
interface ParentClass<T>{
T customerDefine(T t);
}
class ChildClass implements ParentClass<String> {
@Override
public String customerDefine(String s) {
return "看看是啥:"+s;
}
}
class BridgeMethod{
public static void main(String[] args) {
ParentClass childClass = new ChildClass();//父类的引用指向子类的实现 多态
//这里调用的时子类方法
System.out.println(childClass.customerDefine("12321"));
//这里调用的时父类的方法
System.out.println(childClass.customerDefine(new Object()));//编译通过 运行报错
}
}