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部分。
1 2 3 4 5 6 7 8 9 10 11 12 | 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个完全没有关系的类型, |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步