1.我所理解的泛型
多态是一种面向对象思想的泛化机制,我们往往会基于一个基类或者接口,扩展出不同的普通类,使得代码更加灵活,泛型的思想也类似于此。
Java 5 的重大变化之一就涉及泛型实现了参数化类型,使得你编写的组件或容器(通常是集合)可以适用于多种类型,即实例化时指明容器类持有唯一明确的的数据类型。
//声明一个ArrayList,不指定容器类型
List list = new ArrayList();
list.add("string");//添加一个字符串类型
list.add(100);//添加一个int类型
//取值的时候需要进行强制类型转换。
String str = (String)list.get(0);
//此元素非String类型,运行会出错
String strn = (String) list.get(1);
上图代码中list可以存放任意类型。有时,你可能并不知道容器类各个元素的类型,为了得到元素类型,在进行强制类型转换时,如果类型不匹配,则会运行出错。
如果我们再声明容器的时传入String这个明确的类型
可以看到,添加非String参数的时候,编译不会通过,并且在取值的时候,不需要强制类型转换。当看到这个ArrayList声明的时候,我们就知道这是一个String容器,不能传入其它类型。并且程序在编译期出错比在运行期间出错更加可控和安全。
这就是 Java 泛型的核心概念:你只需告诉编译器要使用什么类型,剩下的细节交给它来处理。合理的运用泛型至能让我们的程序更具可读性和安全性。
2.泛型的使用
2.1定义一个简单的泛型类
所谓泛型类,就是具有一个或多个类型变量的类。
public class Generic<T> {
private T field1;
private T field2;
public T getField1() {
return field1;
}
public void setField1(T field1) {
this.field1 = field1;
}
public T getField2() {
return field2;
}
public void setField2(T field2) {
this.field2 = field2;
}
}
Generic 类声明中的,我们称之类型变量,处于类名的后面。类定义中的类型变量也可以指定方法的返回类型以及局部变量的类型。
//当我们需要用具体类型实例化时的
new Generic<String>()
我们可以将泛型类看作工厂,根据需求得到不同的普通类。当执行了上面这条语句之后,逻辑上便有以下这样一个类可供我们操作的,其中的类型变量T,全部变成了String。
public class Generic {
private String field1;
private String field2;
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public String getField2() {
return field2;
}
public void setField2(String field2) {
this.field2 = field2;
}
}
泛型类也可以有多个类型变量。 例如, 可以定义 Generic类, 其中第一个域和第二个域使用不同的类型:
public class Generic<T,U> {
private T field1;
private U field2;
public T getField1() {
return field1;
}
public void setField1(T field1) {
this.field1 = field1;
}
public U getField2() {
return field2;
}
public void setField2(U field2) {
this.field2 = field2;
}
}
定义泛型接口与泛型类的规则一样,就不再复述。
2.2泛型方法和泛型类有关系吗?
首先需要声明的是泛型方法和泛型没有关系,存在泛型方法的类,不一定是泛型类。
public class Test {
//在普通类中定义一个泛型方法
public <T> void genericMethod(){}
}
其中类型参数需要写在返回值前面,并且声明的类型参数可以方法的返回值和参数,如下代码:
public class Test {
//声明的类型变量作为方法的返回值和参数
public <T> T genericMethod(T t){ return t;}
}
上面的两个例子都是普通类中的泛型方法,在泛型类中,也可以存在泛型方法。
public class Test<T> {
private T t;
public Test(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
//泛型类中泛型方法
public <T> T genericMethod(T t){ return t;}
}
在泛型类声明中的和在泛型方法中声明的所代表的含义是不一样的,他们之间没有任何关系;
Test<String> test = new Test("字符串");
Integer num = test.genericMethod(new Integer(100));
泛型类的类型参数是 String,而泛型方法的类型参数是 Integer。两者是不一样。
一般,为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数应该尽量避免同名
public class Test<T> {
private T t;
public Test(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
//泛型类中泛型方法
public <E> E genericMethod(E e){ return e;}
}
2.3类型变量的限定
3.通配符类型
4.类型擦除
泛型是 Java 1.5 版本才引进的概念,在这之前没有泛型的概念。也就是说之前虚拟机中没有泛型类型对象,即所有的对象都是普通类。泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,称之为类型擦除。
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
//更具以上有关泛型的描述,我们可以思考一下这两个对象的class对象是否一致?
System.out.println(l1.getClass() == l2.getClass());// 答案为true
我们可以先将两个class对象打印出来进行对比,发现它们是一样的,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPdXlyVl-1606749712482)(C:\Users\YMXD\AppData\Local\Temp\1606747958502.png)]
为什么呢?String和Integer去那里了?泛型信息被擦除了?是的,这便是泛型擦除。