本文概要:
本节概要:
泛型的优点:
public class Location<T>{//标识符号可以随意写 private T x ; private T y ; public void setX(T x){//作为参数 this.x = x ; } public void setY(T y){ this.y = y ; } public T getX(){//作为返回值 return this.x ; } public T getY(){ return this.y ; } } 复制代码
以 , 进行分隔
public class MoreLocation<T,U> {//标识符号可以随意写 private T x; private U y; public void setX(T x) {//作为参数 this.x = x; } public void setY(U y) { this.y = y; } public T getX() {//作为返回值 return this.x; } public U getY() { return this.y; } } 复制代码
虽然标识符号可以随意取,但为了提高可读性,一般遵循以下规则.
在接口上定义泛型与在类中定义泛型是一样的
interface ILocation<T>{ // 在接口上定义泛型 T getZ() ; void setZ(T z); } 复制代码
public class LocationImpl implements ILocation<String>{ private String z ; public LocationImpl(String z){ this.setZ(z) ; } @Override public void setZ(String z){ this.z = z ; } @Override public String getZ(){ return this.z ; } } 复制代码
publick class LocationImpl<T,K,U> implements ILocation<U>{ //把第三个泛型变量U用来填充接口 private U z ; private T x; private K y; public LocationImpl(U z){ this.setZ(z) ; } @Override public void setZ(U z){ this.z = z ; } @Override public U getZ(){ return this.z ; } } 复制代码
在方法的返回值前加上来表示泛型变量.
public class MethodLocation { public static <T> void staticMethod(T text) { System.out.println("staticMethod:" + text); } //返回值与形参中存在泛型 public <T> T normalMethod(T text) { System.out.println("normalMethod:" + text); return text; } //定义泛型数组, T[]相当于String[]. public static <T> T[] funArray(T...arg){ // 接收可变参数 return arg ; // 返回泛型数组 } public static void main(String[] args) { MethodLocation methodLocation = new MethodLocation(); String text1 = methodLocation.normalMethod("hello");//方法1 String text2 = methodLocation.<String>normalMethod("genericity");//方法2 System.out.println("from main method:"+text1); System.out.println("--------------------------"); Integer[] intArray = MethodLocation.funArray(1, 2, 3, 4, 5, 6); System.out.println(Arrays.toString(intArray)); } } //输出结果 normalMethod:hello normalMethod:genericity from main method:hello -------------------------- [1, 2, 3, 4, 5, 6] 复制代码
注意:虽然方法2是推荐方式,但实际在IDEA中会提示使用方法1,这是因为它会实时检测传入类型是否一致,不一致直接提醒编译不通过.
本节概要:
在前一节中,T只能是Object的子类,所以在编译时只能调用Object类的相关方法.假如现在有个dog类,我们想在编译时就调用他父类Animal的方法.这时就需要用到类型绑定.
定义:
< T extends BoundingType >
优点:
//省略....创建dog,Animal,IAction相关代码. public class TypeBind { public static void main(String[] args) { Dog dog = new Dog("旺财"); String nameClass = getAnimalNameClass(dog); System.out.println(nameClass); System.out.println("---------------"); String actionInterface = getAnimalActionInterface(dog); System.out.println(actionInterface); System.out.println("---------------"); String nameAction = getAnimalNameAndAction(dog, dog); System.out.println(nameAction); } //绑定类 private static <T extends Animal> String getAnimalNameClass(T sub) { //这样编译时,就能调用Animal中的方法. return sub.getName(); } //绑定接口 private static <T extends IAction> String getAnimalActionInterface(T sub) { return sub.howl(); } //多个泛型绑定多个类型,通过&符号指定多个类型 private static <T extends Animal & Serializable, U extends IAction & Serializable> String getAnimalNameAndAction(T sub1, U sub2) { return sub1.getName() + sub2.howl(); } } 复制代码
通配符的意义就是它是一个未知的符号,可以是代表==任意的类==,通常用?号表示.
作用:用于填充泛型变量T,表示代表任意类型!仅仅是填充方式的一种.
//使用位置有且只有,只能用来在生成泛型实例时使用. Location<?> location; location = new Location<Integer>(); 复制代码
Location<? extends Number> location; location = new Location<Integer>(2,3); //取 Number number = location.getX();//编译通过 //存 location.setX(new Integer(123);//编译报错 复制代码
location的类型由<? extends Number>决定,并不会因为location = new Location(2,3)而改变类型.所以不能确定通配符类型.
/** * 准备三个类Animal(动物),Mammal(哺乳动物),Mouse(老鼠). * Mouse 继承 Mammal, Mammal 继承 Animal. * .....省略相关类代码 */ List<? super Mammal> list; list = new ArrayList<Animal>; //取 Animal animal = list.get(0);//编译报错 Object object = list.get(0); //存 list.add(new Animal());//编译报错 list.add(new Mammal()); list.add(new Mouse()); 复制代码
取的时候报错,编译器不能确定<? super Mammal>的父类就是Animal.
至于存的时候报错,同样因为是未知类型,编译器只能确定通配符类型为Mammal及其子类.
最后的话:
本文只是对参考链接的内容总结,如需详细了解,请参考启舰大佬的博客链接.
由于本人技术有限,如有错误的地方,麻烦大家给我提出来,本人不胜感激,大家一起学习进步.
参考链接: