Java 中对于泛型方法的定义:
public <T> T getT(){
.....相关代码;
}
其中我对<T>的理解就是申明只是一个泛型方法的标记,T是返回的类型。
对于泛型类的定义:
public class Type<T>{
....相关代码
}
上面写的是关于泛型方法和泛型类的定义。这里写这篇博客的主要目的是为了记录<? extends T> 和 <? super T>的理解。
<? extends T>是上界通配符。逻辑上来说,一个可以往里面放动物的容器,也可以往里面放狗,因为狗是继承了动物的,所以从
逻辑上来说,一个可以放狗的容器也应该是继承一个可以放动物的容器的。但是Java中这是不对的。这时候就需要上界通配符来解决这个问题。
可以定义一个Content<? extends Animal> content,这个content容器里面可以放任何Animal包括其子类。这使得容器Content之间也有
了一定的联系。但是其中的也有一定的副作用。Content类里面有个getContent()方法,这个方法是不会影响使用的。因为对java编译器来说,
里面所有的东西都有一个相同的父亲,那就是Animal。但是如果你想要使用setContent()方法,这时就会出现一个问题,问题是什么呢?那就
是我只知道里面的类型是Animal以及Animal的派生类,但是无法确定具体的类型,是Dog或者Cat等。这里的类型没有具体给明,所以编译器
在这里只是给了一个占位符,所以到后面往t里面放Dog或者Apple的时候他都不知道是不是和Animal相匹配,所以这是不允许使用set的。下面
方法中的 public void setContent(List<T> content) 如果想可以set T包括T的子类的List的时候,可以这么定义:
public void setContent(List<?extends T> content)。
<? super T>是下界通配符。其作用这好和上面的<? extends T>相反。Content<? super Animal> content 表示的是Animal 以及Animal
基类的容器,但不是Dog基类的容器。里面的setContent()方法是可以正常使用的。因为它规定了最小粒度的下限,那就是Animal。但是它往外面
getContent()就比较费劲,因为他们公共的基类只有Object。所以取出来的内容只能用Object来装。
所以这里总结了一点就是如果一个内容他需要set的内容比较多,那就使用<? super T>。如若使用get的多一点,那就使用<? extends T>。
- 泛型参数Class、Class<?>、Class<? extends xx>的对比
* Created by ypyue on 2017/6/19.
*/
public class Main2 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
System.out.println("1-----------");
Dog dog1 = creatNew1(Dog.class);
System.out.println(dog1.name + " is " + dog1.type+ "\n");
System.out.println("2-----------");
Animal ani1 = creatNew2(Cat.class);
Cat cat1 = (Cat) ani1;
System.out.println(cat1.name + " is " + cat1.type + "\n");
System.out.println("3-----------");
Object obj = creatNew3(Dog.class);
Dog dog2 = (Dog) obj;
System.out.println(dog1.name + " is " + dog2.type + "\n");
System.out.println("4-----------");
Object obj2 = creatNew4(Cat.class);
Cat cat2 = (Cat) obj2;
System.out.println(cat2.name + " is " + cat2.type + "\n");
System.out.println("5-----------");
Object obj3 = creatNew5(new Cat());
Cat cat3 = (Cat) obj3;
System.out.println(cat3.name + " is " + cat3.type + "\n");
}
/**
* 此方法是一个非泛型类中的泛型方法,参数为Class<T>类型,可以传入任何类,但是Class<T>将参数在函数内部的类型固定为 T类,使用clazz.newInstance(),返回的类型也为固定的 T 类型。
* 如: 传入Dog.class, 函数中的 T 固定为Dog.class,函数返回的是Dog类型,不需要强制转换为Dog类型
* (当然,函数返回类型也可以是Object类型,但是没必要)
*/
public static <T> T creatNew1(Class<T> clazz) throws IllegalAccessException, InstantiationException {
System.out.println(clazz);//打印具体传入的类型。
return clazz.newInstance();
}
/**
* 此方法参数是Class<? extends Animal>,只能传入Animal及其子类的类型,函数返回类型只能声明为Animal或Object类型,
* 如:传入Cat.class,函数返回一个Animal的子类对象,需将此子类对象强制转换为具体的子类(即Cat类)。
*/
public static Animal creatNew2(Class<? extends Animal> clazz) throws IllegalAccessException, InstantiationException {
System.out.println(clazz);//打印具体传入的类型。
return clazz.newInstance();
}
/**
* 此方法参数是Class,可传入任何类,其返回只能声明为Object类对象。
* 如:传入Dog.class, 返回的是Object类型的对象,需强制转换为Dog类型的对象。
*/
public static Object creatNew3(Class clazz) throws IllegalAccessException, InstantiationException {
System.out.println(clazz);//打印具体传入的类型。
return clazz.newInstance();
}
/**
* 传入参数Class<?> 和 上一个方法传入 Class 的区别还不是很清楚,其返回只能声明为Object类对象。
* 如:Cat.class, 返回的是Object类型的对象,需强制转换为Cat类型的对象。
*/
public static Object creatNew4(Class<?> clazz) throws IllegalAccessException, InstantiationException {
System.out.println(clazz);//打印具体传入的类型。
return clazz.newInstance();
}
/**
* 传入Object类型的对象,返回也声明为Object类型。
*/
public static Object creatNew5(Object object) {
System.out.println(object.getClass());//打印具体传入的类型。
return object;
}
}
abstract class Animal {
public String type = "type = animal ";
}
class Dog extends Animal {
public String name = "name = gou";
}
class Cat extends Animal {
public String name = "name = mao";
}
/**
* 这些方法,传的参数声明不同,其返回的声明也必然要随之不同。
*/