java 泛型理解

Java泛型T,Class<T>,Class<?>区别

T是一种具体的类,例如String,List,Map......等等,这些都是属于具体的类,这个比较好理解
Class是什么呢,Class也是一个类,但Class是存放上面String,List,Map......类信息的一个类,有点抽象,我们一步一步来看 。
如何获取到Class类呢,有三种方式:
1. 调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。
例如:

List list = null; 
Class clazz = list.getClass(); 

2. 使用Class类的中静态forName()方法获得与字符串对应的Class对象。
例如:

Class clazz = Class.forName("com.lyang.demo.fanxing.People"); 

3.获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。

Class clazz = List.class; 


** 那么问题来了?Class类是创建出来了,但是Class<T>和Class<?>适用于什么时候呢???**

使用Class<T>和Class<?>多发生在反射场景下,先看看如果我们不使用泛型,反射创建一个类是什么样的。

People people = (People) Class.forName("com.lyang.demo.fanxing.People").newInstance(); 

看到了么,需要强转,如果反射的类型不是People类,就会报java.lang.ClassCastException错误。
使用Class<T>泛型后,不用强转了

public class Test { 
 public static <T> T createInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException { 
  return clazz.newInstance(); 
 }

 public static void main(String[] args) throws IllegalAccessException, InstantiationException { 
  Fruit fruit= createInstance(Fruit .class);
  People people= createInstance(People.class);
 }
}

那Class<T>和Class<?>有什么区别呢
Class<T>在实例化的时候,T要替换成具体类
Class<?>它是个通配泛型,?可以代表任何类型主要用于声明时的限制情况
例如可以声明一个public Class<?> clazz;

但是你不能声明一个public Class<T> clazz;因为T需要指定类型
所以,当不知道定声明什么类型的Class的时候可以定义一个Class<?>,Class<?>可以用于参数类型定义方法返回值定义等。
class类中声明变量和方法值返回

public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

class<?> 作为参数

public static InputStream getStreamWithObj(Class<?> obj, String filePath) {
InputStream stream = null;
ClassLoader loader = obj.getClassLoader();
if (loader != null) {
stream = loader.getResourceAsStream(filePath);
}
return stream;
}

 Class<T>的常用场景:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

上层调用获取自己的实例类型:

DBFileMapper fileMapper = getMapper(DBFileMapper.class);
AlarmFixMapper fixMapper = getMapper(AlarmFixMapper.class);

 

 

https://www.jianshu.com/p/e5b8cd33ec94

https://www.jianshu.com/p/f25da582f592

PECS原则:

简单的说,当只想从集合中获取元素,请把这个集合看成生产者,请使用<? extends T>,从这个集合取get()方法

这就是Producer extends原则,PECS原则中的PE部分。

        List<Child> childList = new ArrayList<>();
        childList.add(new Child());
        List<? extends Parent> parents = childList;
        parents.forEach(System.out::println);

        Parent parent = parents.get(0); // 可行,
        // parents.add(new Child());
        //  parents.add(new Child2());
        //  parents.add(new Parent());  // 均编译报错,用了<? extends Fruit>相当于告诉编译器,
        //  我们的篮子(集合)是用来处理父类以及父类的子类型。因为子类型有许多,我们并没有告诉编译器是哪个子类型。
        // 编译器在这里遇到的问题是,如果add的是Apple类型时,则basket应该是List<Apple>,
        // 如果add是Fruit类型,则basket应该是List<Fruit>。而List<Apple>和List<Fruit>前面已经提过,是2个完全没有关系的类型,

 T和?区别:https://segmentfault.com/a/1190000023020690

posted @ 2021-07-27 10:41  卡卡西殿  阅读(23)  评论(0编辑  收藏  举报