主要参考网址:
https://zhuanlan.zhihu.com/p/331620060
2.编译时更安全
如果使用Object类的话,可能转换异常 — ClassCastException
Foo newFoo = (Foo) my.doSomething(foo); // 可能转换异常 Foo newFoo = my.doSomething(foo); // 编译时更安全
泛型类、泛型接口、泛型方法
泛型常用标记含义
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
//在实例化泛型类时,必须指定具体类型 public class Generic<T>{ //key这个成员变量的类型为T, T的类型由外部指定 private T key; ? public Generic(T key) { this.key = key; } ? public T getKey(){ return key; } } ? //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型 Generic<Integer> genericInteger = new Generic<Integer>(10000); Generic<String> genericString = new Generic<String>("minnersun");
//定义一个泛型接口 public interface Generator<T> { public T next(); }
未传入泛型实参时,与泛型类的定义相同
在声明类的时候,需将泛型的声明也一起加到类中
// 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class" class FruitGenerator<T> implements Generator<T>{ @Override public T next() { return null; } }
在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
// 即:Generator<T>,public T next();中的的T都要替换成传入的String类型 public class FruitGenerator implements Generator<String> { ? private String[] fruits = new String[]{"Apple", "Banana", "Pear"}; ? @Override public String next() { Random rand = new Random(); return fruits[rand.nextInt(3)]; } }
public class GenericTest { public class Generic<T>{ private T key; ? public Generic(T key) { this.key = key; } ? // 注意!!! 虽然在方法中使用了泛型,但是这并不是一个泛型方法。 // 这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。 public T getKey(){ return key; } } ? /** * 这才是一个真正的泛型方法 * 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T * 这个T可以出现在这个泛型方法的任意位置 * 泛型的数量也可以为任意多个 * 如:public <T,K> K showKeyName(Generic<T> container){ * ... * } */ public <T> T showKeyName(Generic<T> container){ System.out.println("container key :" + container.getKey()); //当然这个例子举的不太合适,只是为了说明泛型方法的特性。 T test = container.getKey(); return test; } ? //这也不是一个泛型方法,这就是一个普通的方法,只是使用了Generic<Number>这个泛型类做形参而已。 public void showKeyValue1(Generic<Number> obj){ Log.d("泛型测试","key value is " + obj.getKey()); } ? //这也不是一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符? //同时这也印证了泛型通配符所描述的,?是一种类型实参,可以看做为Number等所有类的父类 public void showKeyValue2(Generic<?> obj){ Log.d("泛型测试","key value is " + obj.getKey()); } ? /** * 注意!!! * 只声明了泛型类型T,并未声明泛型类型E,因此编译器并不知道该如何处理E这个类型。 * 译器会为我们提示错误信息:"UnKnown class ‘E‘ " */ public <T> T showKeyName(Generic<E> container){ ... } ? }
public static <T> void printMsg(String str,T... args){ for (T t: args){ System.out.println(t); } } printMsg("minnersun",20000,"summer",44.45); // 20000 summer 44.45
因为静态方法加载顺序与类同级,所以 静态方法无法访问类上定义的泛型
必须要将泛型定义在方法上
public class StaticGenerator<T> { public static <T> void show(T t){ ? } }
传入的类型实参必须是指定类型的子类型
public void showKeyValue1(Generic<? extends Number> obj){ System.out.println("泛型测试","key value is " + obj.getKey()); } ? Generic<String> generic1 = new Generic<String>("10000"); Generic<Integer> generic2 = new Generic<Integer>(10000); Generic<Float> generic3 = new Generic<Float>(5.5f); Generic<Double> generic4 = new Generic<Double>(3.15); ? //这一行代码编译器会提示错误,因为String类型并不是Number类型的子类 //showKeyValue1(generic1); ? showKeyValue1(generic2); showKeyValue1(generic3); showKeyValue1(generic4); public class Generic<T extends Number>{ private T key; ? public Generic(T key) { this.key = key; } ? public T getKey(){ return key; } } ? //这一行代码也会报错,因为String不是Number的子类 Generic<String> generic1 = new Generic<String>("10000");
必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加
//public <T> T showKeyName(Generic<T extends Number> container),编译器会报错:"Unexpected bound" public <T extends Number> T showKeyName(Generic<T> container){ System.out.println("container key :" + container.getKey()); T test = container.getKey(); return test; }
?
原文:https://www.cnblogs.com/minnersun/p/15103190.html