看懂Class<T> clazz;所需的Java基础知识

参考博文:
https://blog.csdn.net/u012990509/article/details/61494047?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.pc_relevant_default&utm_relevant_index=13
https://blog.csdn.net/dufufd/article/details/80537638
https://www.liaoxuefeng.com/wiki/1252599548343744/1265104600263968

Class是一个类

如果说类是对“对象”的抽象和集合的话,那么Class类就是对“”的抽象和集合。

从某种意义上来说,java有两种对象:实例对象和Class对象。
每个类都有一个Class对象——用于记录该类的运行时的类型信息并且创建该类的实例对象。每当编译一个新类就产生一个Class对象,基本类型(boolean, byte, char, short, int, long, float, and double)也有Class对象,数组有Class对象,就连关键字void也有Class对象。(jiuwomeiyou)

User user;   //对普通类进行实例化得到普通的实例对象;
Class<T> clazz;//对Class<T>这个泛型类进行实例化得到的是泛型类T的Class对象,就可以用其来创建这个T类型的实例对象,以获取T类型的属性或方法。

为什么要获取Class<T>对象?

在进行数据库相关操作时,对不同的表进行的增删改查操作过程都是完全相同的,只是表内容不同而已。
表是同一个类的实例对象的集合。
类----------表
类中属性----------表中字段
对象----------记录

所以对不同的表进行增删改查操作,实际上就是在把不同类的实例对象增删改查到对应的表中。
因此,这些对数据库的数据处理方法必须是与内容无关的,不管什么类都是一样的操作。
所以就要用到泛型

泛型就是定义一种模板

例如ArrayList,然后在代码中为用到的类创建对应的ArrayList<类型>:

ArrayList<String> strList = new ArrayList<String>();

泛型就是编写模板代码来适应任意类型
泛型的好处是使用时不必对类型进行强制转换,它通过编译器对类型进行检查。

然而:
Java语言的泛型实现方式是擦拭法(Type Erasure)。所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T视为Object处理,但是,在需要转型的时候,编译器会根据T的类型自动为我们实行安全地强制转型。

了解了Java泛型的实现方式——擦拭法,我们就知道了Java泛型的局限:
局限一:不能是基本类型,例如int,因为实际类型是Object,Object类型无法持有基本类型:

Pair<int> p = new Pair<>(1, 2); // compile error!

局限二:无法取得带泛型的Class,
因为T是Object,我们对Pair和Pair类型获取Class时,获取到的是同一个Class,也就是Pair类的Class。
换句话说,所有泛型实例,无论T的类型是什么,getClass()返回同一个Class实例,因为编译后它们全部都是Pair。
局限三:无法判断带泛型的类型,
原因和前面一样,并不存在Pair.class,而是只有唯一的Pair.class。
局限四:不能实例化T类型,

public class Pair<T> 
{
    private T first;
    private T last;
    public Pair() {
        // Compile error:
        first = new T();
        last = new T();
    }
}

上述代码无法通过编译,因为构造方法的两行语句:

first = new T();
last = new T();

擦拭后实际上变成了:

first = new Object();
last = new Object();

这样一来,创建new Pair()和创建new Pair()就全部成了Object,显然编译器要阻止这种类型不对的代码。

要实例化T类型,我们必须借助额外的Class参数:

public class Pair<T> 
{
    private T first;
    private T last;
    public Pair(Class<T> clazz) 
    {
        first = clazz.newInstance();
        last = clazz.newInstance();
    }
}

上述代码借助Class<T>参数并通过反射来实例化T类型,使用的时候,也必须传入Class<T>。
例如:

Pair<String> pair = new Pair<>(String.class);

因为传入了Class<String>的实例,所以我们借助String.class就可以实例化String类型。

所以获取Class<T>的对象是为了实例化T类型,这样就可以

利用泛型传递实体类的类型参数到数据库帮助类中,通过反射得到所有的类型字段。
通过Class实例获取类信息的方法称为反射(Reflection)。

如何获得Class对象?

有三种获得Class对象的方式:

1.Class.forName(“类的全限定名”)
2.实例对象.getClass()
3.类名.class (类字面常量) 例如User.class

类字面量不仅可以应用于普通的类,也可以应用于接口、数组及基本数据类型。例如Integer.class

Java的反射API提供的Field类封装了字段的所有信息:

通过Class实例的方法可以获取Field实例:getField(),getFields(),getDeclaredField(),getDeclaredFields();
通过Field实例可以获取字段信息:getName(),getType(),getModifiers();
通过Field实例可以读取或设置某个对象的字段,如果存在访问限制,要首先调用setAccessible(true)来访问非public字段。
通过反射读写字段是一种非常规方法,它会破坏对象的封装。

  • 19
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值