泛型

泛型(加入现在的个人理解)

泛型:参数化类型(本质),可理解为,将类型定义为参数,在使用或是调用时传入具体的类型实参。

参数类型用在类,接口,方法中,就称之为,泛型类,泛型接口,泛型方法。

泛型的目的:1、规定类型

2、减少类型不同,属性,方法同样代码

作用时间:Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段

验证:

List<String> stringArrayList = new ArrayList<String>(); List<Integer> integerArrayList = new ArrayList<Integer>(); Class classStringArrayList = stringArrayList.getClass(); Class classIntegerArrayList = integerArrayList.getClass();

System.out.println(classStringArrayList.equals(classIntegerArrayList));

//true

泛型类:可以参考List,Map等的源码。

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 //在实例化泛型类时,必须指定T的具体类型 public class Generic<T>{ //key这个成员变量的类型为T,T的类型由外部指定 private T key; public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定 this.key = key; } public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定 return key; } }

//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型 //传入的实参类型需与泛型的类型参数类型相同,即为Integer. Generic<Integer> genericInteger = new Generic<Integer>(123456); //传入的实参类型需与泛型的类型参数类型相同,即为String. Generic<String> genericString = new Generic<String>("key_vlaue");

泛型接口:

/** * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中 * 即:class FruitGenerator<T> implements Generator<T>{ * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class" */ class FruitGenerator<T> implements Generator<T>{ @Override public T next() { return null; } }

当实现泛型接口的类,传入泛型实参时:

/** * 传入泛型实参时: * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T> * 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型 * 即: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)]; } }

泛型通配符:

同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

证明:Ingeter是Number的一个子类,Generic<Ingeter>与Generic<Number>实际上是相同的一种基本类型。

class Test<T> {

public int k = 7;

public void show(Test<Number> obj) {

System.out.println(obj.k);

}

 

public static void main(String[] args) {

Test<Integer> t1 = new Test<Integer>();

Test<Number> t2 = new Test<Number>();

t1.show(t2//要是传t1会报错);//这里是用传入的T是t1,但是要处理t2

}

}

所以为了不写两份代码可以将方法改为public void show(Test<?> obj){}

当具体类型不确定的时候,这个通配符就是 ?  ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能

泛型方法:是在调用方法的时候指明泛型的具体类型 

/** * 泛型方法的基本介绍 * @param tClass 传入的泛型实参 * @return T 返回值为T类型 * 说明: * 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。 * 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。 * 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。 * 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。 */ public <T> T genericMethod(Class<T> tClass)throws InstantiationException , IllegalAccessException{ T instance = tClass.newInstance(); return instance; }

是否为泛型方法:拥有<T>

public class Generic<T>{ private T key; public Generic(T key) { this.key = key; } //我想说的其实是这个,虽然在方法中使用了泛型,但是这并不是一个泛型方法。 //这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。 //所以在这个方法中才可以继续使用 T 这个泛型。 public T getKey(){ return key; } /** * 这个方法显然是有问题的,在编译器会给我们提示这样的错误信息"cannot reslove symbol E" * 因为在类的声明中并未声明泛型E,所以在使用E做形参和返回值类型时,编译器会无法识别。 public E setKey(E key){ this.key = keu } */ }

class GenerateTest<T>{ public void show_1(T t){ System.out.println(t.toString()); } //在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。 //由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。 public <E> void show_3(E t){ System.out.println(t.toString()); } //在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。 public <T> void show_2(T t){ System.out.println(t.toString()); } }

静态方法与泛型

静态方法要使用泛型的话,必须将静态方法也定义成泛型方法

public class StaticGenerator<T> { /** * 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法) * 即使静态方法要使用泛型类中已经声明过的泛型也不可以。 * 如:public static void show(T t){..},此时编译器会提示错误信息: "StaticGenerator cannot be refrenced from static context" */ public static <T> void show(T t){ } }

以上总结:泛型方法将整个类泛型化,那么就应该使用泛型方法

泛型上下边界:

为泛型添加上边界,即传入的类型实参必须是指定类型的子类型

如:public void show(Test<? extends Number> obj){}

泛型的上下边界添加,必须与泛型的声明在一起 。

如:

public <T> T show(Test<T extends Number> obj),编译器会报错:"Unexpected bound" public <T extends Number> T show(Test<T extends Number> obj ){}

泛型数组

java中是”不能创建一个确切的泛型类型的数组”的

List<String>[] ls = new ArrayList<String>[10]; 不可以

List<?>[] ls = new ArrayList<?>[10]; 可以

List<String>[] ls = new ArrayList[10]; 可以

由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给一个元素赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。

注:应该就是定长的数组可以按元素取值,然而转换后都是object,所以最后转的时候会出现类型转换异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值