区别
单独的T 代表一个类型 ,而 Class<T>代表这个类型所对应的类, Class<?>表示类型不确定的类
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
举例说明:
Set<T> 表示 集合里 是 T类的实例
List<E> 表示 集合里 是 E类的实例
List<?> 表示 集合里的对象类型不确定,未指定
List 同 List<?> 是一样的。
泛型的作用:
1、用泛型:
Java代码
List<T> list=new ArrayList<T>();
T t=list.get(0);
2、不用泛型:
Java代码
List list=new ArrayList();
T t=(T)list.get(0);
自定义泛型接口、泛型类和泛型方法
自定义泛型接口、泛型类和泛型方法与上述Java源码中的List、ArrayList类似。如下,我们看一个最简单的泛型类和方法定义:
public class GenericTest {
public static void main(String[] args) {
Box<String> name = new Box<String>("corn");
System.out.println("name:" + name.getData());
}
}
class Box<T> {
private T data;
public Box() {
}
public Box(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,由于接收来自外部使用时候传入的类型实参。那么对于不同传入的类型实参,生成的相应对象实例的类型是不是一样的呢?
public class GenericTest {
public static void main(String[] args) {
Box<String> name = new Box<String>("corn");
Box<Integer> age = new Box<Integer>(712);
System.out.println("name class:" + name.getClass()); // com.qqyumidi.Box
System.out.println("age class:" + age.getClass()); // com.qqyumidi.Box
System.out.println(name.getClass() == age.getClass()); // true
}
}
由此,我们发现,在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来的最基本的类型(本实例中为Box),当然,在逻辑上我们可以理解成多个不同的泛型类型。
究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
类型通配符
类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且Box<?>在逻辑上是Box<Integer>、Box<Number>...等所有Box<具体类型实参>的父类。由此,我们依然可以定义泛型方法,来完成此类需求。
public class GenericTest {
public static void main(String[] args) {
Box<String> name = new Box<String>("corn");
Box<Number> number = new Box<Number>(314);
Box<Integer> age = new Box<Integer>(712);
getData(name);
getData(number);
//如果方法写成 public static void getData(Box<Number> data),则1处位置报错
//The method getData(Box<Number>) in the type GenericTest is
//not applicable for the arguments (Box<Integer>)
getData(age);//1
}
public static void getData(Box<?> data) {
System.out.println("data :" + data.getData());
}
}
有时候,我们还可能听到类型通配符上限和类型通配符下限。
如果需要定义一个方法,但对类型实参又有进一步的限制:只能是Number类及其子类。此时,需要用到类型通配符上限。
类型通配符上限通过形如Box<? extends Number>形式定义,相对应的,类型通配符下限为Box<? super Number>形式,其含义与类型通配符上限正好相反.
方法中为什么需要<T> T修饰呢
泛型的声明,必须在方法的修饰符(public,static,final,abstract等)之后,返回值声明之前。
public static <T> T request2Bean(HttpServletRequest request,Class<T> clazz){}
其中第一个<T>是与传入的参数Class<T>相对应的,相当于返回值的一个泛型,后面的T是返回值类型,代表方法必须返回T类型的(由传入的Class<T>决定)
如何创建一个Class<T>类型的实例?
就像使用非泛型代码一样,有两种方式:调用方法 Class.forName() 或者使用类常量X.class。 Class.forName() 被定义为返 回 Class<?>。另一方面,类常量 X.class 被定义为具有类型 Class<X>,所 以 String.class 是Class<String> 类型的。
转载:https://www.cnblogs.com/zhima-hu/p/7352555.html