原文链接:https://blog.csdn.net/topdeveloperr/article/details/81066872

Class类

Class类是用来代表java的类的一个类。 就好比:人 是 小吕,小布实例的 类;Class 是 人的类的一个类。

那么为何java里面可以有Class这个类?,那么这个Class类对应的实例对象到底是一个什么样的对象,他和类的关系是什么,和对象的关系是什么?Class类也继承自Object类吗?带着这些问题我们继续往下看。

Java里面最出名得类可能是Object,众所周知,java里所有的类都继承自Object类,java体系里最顶上的类只有Object一个类。Class类肯定也是继承自Object类的。

并且在Object里面还提供了一个native方法getClass()用于返回调用这个方法的对象的运行时的class。英文原文注释如下:

/*
Returns the runtime class of this {@code Object}
*/
public final native Class<?> getClass();

在object里面定义了这个方法,意味着所有的对象都可以调用这个方法来获取自己运行时的类。

那么,为什么需要Class类?事实上Class类在java中是用来表示运行时类型信息的对应对象就是Class类对象。它包含了与类有关的信息。事实上,Class对象就是用来创建类的所有常规对象的。java使用Class对象来执行其RTTI。

每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象,更恰当的说,是保存在一个同名的.class文件中。

为了生成这个类的对象,运行这个程序的JVM讲使用类加载器子系统。

所有的类都是在对其第一次使用时,动态的加载到JVM中的。当程序创建第一个对象类的静态成员引用时,就会加载这个类。因此java程序在它开始运行之前并非完全被加载,其各个部分是在必须是才加载的。这一点与传统语言不同。也很难在C++当中做到。类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器根据类名查找.class文件。

一旦这个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

因此,也说明了java的对象的创建原理。

class Candy{static {System.out.println("Loading Candy too");}class Gum{static {System.out.println("Loading Gum");}
}class Cookie{static {System.out.println("Loading Cookie");}
}public class SweetShop {public static void main(String [] args){System.out.println("inside main");new Candy();System.out.println("After creating Candy");try {Class.forName("Gum");} catch (ClassNotFoundException e) {System.out.println("Couldn't find Gum");}System.out.println("After Class.forName(\"Gum\")");new Cookie();System.out.println("After creating Cookie");}
}

执行结果为

inside main
Loading Candy too
After creating Candy
Couldn't find Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie

这里的每个类Candy,Gum和Cookie,都有一个static子句,该子句在类第一次加载时候执行。这时会有相应的信息打印出来,告诉我们这个类什么时候被加载了。在main方法中,创建对象的代码被置于打印语句之间,帮助我们判断加载的时间点。

上面的代码的执行结果告诉我们,Class对象仅仅在需要的时候才被加载,static初始化是在类加载时进行的。

当虚拟机执行了new这个指令之后,(注意,不仅关键字new会使得虚拟机执行new指令,调用静态方法也会,jvm里面规定了五种情况必须初始化一个对象。)Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。实际上在Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象)。需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象。因此,java里的class类就是存放一个对象对应的类的信息的类。

这里可以引申一下,为什么synchronized关键字在锁定的是Class的时候会对所有类的实例都生效?

因此总结一下:

手动编写的每一个类被编译后都会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件).Class类的对象作用是运行时提供或获得某个对象的类型信息,当我们使用关键字new创建对象的时候再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值,这点对于反射技术也很重要。

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。一直以来反射技术都是Java中的闪亮点,这也是目前大部分框架(如Spring/Mybatis等)得以实现的支柱。在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持。

三种获得Class对象引用的方式

通过继承自Object类的getClass方法,
Class类的静态方法forName
字面常量的方式”.class”。
其中实例类的getClass方法和Class类的静态方法forName都将会触发类的初始化阶段。字面常量的方式不仅更简单,而且更安全,因为省去了forName方法,效率更高。比较有趣的一点是,使用.class来创建对Class对象的引用时,不会自动初始化Class对象。初始化被延迟到了对静态方法或者非常数静态域进行首次引用时才执行

初始化是类加载的最后一个阶段,也就是说完成这个阶段后类也就加载到内存中(Class对象在加载阶段已被创建),此时可以对类进行各种必要的操作了(如new对象,调用静态成员等),注意在这个阶段,才真正开始执行类中定义的Java程序代码或者字节码。

关于这一部分的内容请移步至:https://blog.csdn.net/javazejian/article/details/70768369

综上来看,Class这个类是用来在一个比较通用的层面上描述一个对象信息的一个类,每一个对象会有一个原生类,同时每个原生类也有一个对应的Class类。每一个Class对象都对应着一个真实的手动编写的类,表示的是创建的类的类型信息,无论创建多少个对象,他们对应的Class对象只会有一个。且Class类只有私有构造函数,意味着它只能被虚拟机自己实例化。Class类的对象的的作用是在运行时,可以根据某个对象去获取这个对象对应的类的类型信息(即类的方法,字段等等)。

Class类提供的方法解析
在看了上面的内容之后,这里我们就不难理解class类为何要提供下面的这些方法了。因为无论我们定义一个怎样的类,他都由字段,方法,构造方法,父类,注解这些东西组成。

获取类的加载器
方法如下:

@CallerSensitive
public ClassLoader getClassLoader() {ClassLoader cl = getClassLoader0();if (cl == null)return null;SecurityManager sm = System.getSecurityManager();if (sm != null) {ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());}return cl;
}

左右就是获取当前这个Class对象的类加载器的实例。

Class.forName()获取Class对象
在使用java的反射时,无论是要获取一个类的字段,还是构造方法,无论任何东西,第一件事首先是要获取一个这个类的一个实例。调用的方法便是Class类中的forName() 方法

在Class类中有两个重载的forName方法:

 @CallerSensitivepublic static Class<?> forName(String name, boolean initialize,ClassLoader loader)throws ClassNotFoundException{Class<?> caller = null;SecurityManager sm = System.getSecurityManager();if (sm != null) {// Reflective call to get caller class is only needed if a security manager// is present.  Avoid the overhead of making this call otherwise.caller = Reflection.getCallerClass();if (sun.misc.VM.isSystemDomainLoader(loader)) {ClassLoader ccl = ClassLoader.getClassLoader(caller);if (!sun.misc.VM.isSystemDomainLoader(ccl)) {sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);}}}return forName0(name, initialize, loader, caller);}```
```java@CallerSensitivepublic static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}```两个方法最后都是调用一个native方法实现的,该本地方法如下:

private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
本地方方法的参数当中有一个name参数,必然是类的全限定名,另外还有一个类ClassLoader。可以想到这个本地方法就是使用这个类加载器,然后根据类的全限定名去加载了这个类。然后我们才能获取到了这个类的实例,具体的forName0实现逻辑需要查看对应的实现源码,这里暂时不作深究。

再回到两个重载的forName方法,其中第二个方法在jdk library里面的注释如下

/**
* Returns the {@code Class} object associated with the class or
* interface with the given string name. Invoking this method is
* equivalent to:
*
*

* {@code Class.forName(className, true, currentLoader)}
*

*
* where {@code currentLoader} denotes the defining class loader of
* the current class.
*/
第一个方法的注释如下

/**
* Returns the {@code Class} object associated with the class or
* interface with the given string name, using the given class loader.
* Given the fully qualified name for a class or interface (in the same
* format returned by {@code getName}) this method attempts to
* locate, load, and link the class or interface. The specified class
* loader is used to load the class or interface. If the parameter
* {@code loader} is null, the class is loaded through the bootstrap
* class loader. The class is initialized only if the
* {@code initialize} parameter is {@code true} and if it has
* not been initialized earlier.
*
*/
直接看注释其实已经解释的非常清楚了,这两个类起到的作用,不作别的说明了

获取字段
通过字段名字获取一个字段,传入字段名字,获取字段

@CallerSensitive
public Field getField(String name)
throws NoSuchFieldException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Field field = getField0(name);
if (field == null) {
throw new NoSuchFieldException(name);
}
return field;
}
获取所有共有字段:

@CallerSensitive
public Field[] getFields() throws SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);return copyFields(privateGetPublicFields(null));
}

获取所有字段,包括公共的,私有的,受保护的

@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyFields(privateGetDeclaredFields(false));
}
获取普通方法
通过传入方法名字获得一个方法,注意,因为方法可能存在重载的情况,因此除了传入方法名之外,也需要传入方法参数,以此来唯一确定一个方法

@CallerSensitive
public Method getMethod(String name, Class<?>… parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(getName() + “.” + name + argumentTypesToString(parameterTypes));
}
return method;
}
获取所有的共方法

@CallerSensitive
public Method[] getMethods() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyMethods(privateGetPublicMethods());
}
获得所有方法,包括公共的和私有的以及受保护的

@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyMethods(privateGetDeclaredMethods(false));
}
构造方法
通过参数获取一个构造方法

@CallerSensitive
public Constructor<T> getConstructor(Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);return getConstructor0(parameterTypes, Member.PUBLIC);
}

获取所有的构造方法

@CallerSensitive
public Constructor<?>[] getConstructors() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyConstructors(privateGetDeclaredConstructors(true));
}
获取父类
public native Class<? super T> getSuperclass();
获取一个枚举类的所有枚举类型
public T[] getEnumConstants() {
T[] values = getEnumConstantsShared();
return (values != null) ? values.clone() : null;
}
获取一个类的注解
获取所有注解

public Annotation[] getAnnotations() {
return AnnotationParser.toArray(annotationData().annotations);
}
获取一个注解

/*** @throws NullPointerException {@inheritDoc}* @since 1.5*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {Objects.requireNonNull(annotationClass);return (A) annotationData().annotations.get(annotationClass);
}

————————————————
原文链接:https://blog.csdn.net/topdeveloperr/article/details/81066872

Class类是什么?相关推荐

  1. 自己搜集编写的Delphi 通用函数

    { ********************************************************************** } { Currency Common Functio ...

  2. 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题

    继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...

  3. MybatisPlus忽略实体类中的非数据库字段、JPA忽略实体类中的非数据库字段、HeHibernate忽略实体类中的非数据库字段

    mybatis plus忽略映射字段时可以在实体类属性上使用以下注解: @TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的. @TableField(e ...

  4. IDEA中根据数据库自动生成实体类,并自定义所生成的实体类中的注解 @Table @Id @...

    使用IDEA项目添加Hibernate扩展,生成实体类并配置实体类中的注解 一.使用Hibernate自动生成实体类 1.在项目上右键,选择Add Framework Support找到 Hibern ...

  5. IDEA自动生成类注解,IDEA作者信息自动生成,IDEA类信息自动生成

    在新建类文件的时候自动生成注解,诸如我们常见的那些 作者,创建时间,TODO 等等 将以下格式的代码放在Settings -> File and Code Templates -> Inc ...

  6. javabean实体类与实体类之间的快速转换

    一.Dozer是什么? dozer是一个能把实体和实体之间进行转换的工具.只要建立好映射关系.就像是ORM的数据库和实体映射一样. 使用方法示例如下: // article(PO) -> art ...

  7. 利用dom4j将实体类转换为对应的xml报文

    利用dom4j生成xml报文 目标格式: <?xml version="1.0" encoding="GBK"?><Packet type=& ...

  8. Idea groovy表生成实体类带注释

    Idea groovy表生成实体类带注释 1.点开datasourse,打开idea带的数据库工具,具体添加数据库连接,这里不描述. 这时点击会生成一个poji 这时生成的pojo中是不带中文注释的, ...

  9. java带参数的方法笔记_具有Java参数的方法的类声明

    类声明可以包含在Java中具有参数的方法.演示此过程的程序如下: 示例class Message { public void messagePrint(String msg) { System.out ...

  10. Python 闭包、单个装饰器、多个装饰器、装饰器修饰类、应用场景

    1. 闭包 在 Python 中,函数也可以作为参数.我们可以执行下面的代码: def func(a, b):return a + bprint(func) 我们直接输出函数名,而没有加括号.输出结果 ...

最新文章

  1. [置顶] AMF序列化为对象和AMF序列化为二进制字节流
  2. 贵阳市全国首部大数据立法《条例》5月起正式实施
  3. python实现终端3维数据可视化
  4. 的电路接法_放大电路的三种基本接法分享
  5. php内置的数组函数大全,php数组的内置函数大全
  6. 【C++ Priemr | 15】派生类向基类转换的可访问性
  7. python中input()与raw_input()的区别到底是啥?-----marsggbo原创作品为你解答
  8. ApacheCN PythonWeb 译文集 20211028 更新
  9. 浅谈Hybrid技术的设计与实现
  10. 动态图php打不开,PHP如何判断一个gif图片是否为动态图片
  11. Neo4j 语法帮助文档
  12. 华三交换机配置access命令_H3C交换机配置基本命令详解
  13. 从信息网络安全规则开始之——ISO27001
  14. uniapp小程序体验版-白屏现象
  15. 慧之声科技- 致AI 2B先驱者
  16. 计算机本地硬盘带蓝色问号,win10本地磁盘显示蓝色问号该怎么解决
  17. 电商销量预测方法综述
  18. python羊车门问题_羊车门作业 Python版
  19. ⅰcp经济模型_EOQ经济批量模型上篇(模型基础)
  20. 补充:爬虫技术成就了这些商业公司的

热门文章

  1. *Java软件开发面试知识整理*
  2. Google搜索API?
  3. java 信号量 闭锁_Java并发包之闭锁/栅栏/信号量
  4. Docker安装java环境并部署jar包运行
  5. 回归——一元线性回归
  6. 如何往虚拟机里面复制文件(末尾附带视频教程)
  7. 用flatpak安装程序(比如GIMP)的方法
  8. APIView 怎么写?
  9. 【你好Resilience4j】一:Resilience4j之初体验
  10. php处理大数据量数据的思路