Logo

郎哥编程

认识Class对象

2020-01-03 217

前面我们谈到了使用new运算符实例化类时,如果类没有加载到内存,类加载器会把类的字节码文件读入内存,并创建一个java.lang.Class对象。java.lang.Class对象由JVM创建,它存储了被加载类在运行时态下的类信息,程序可以通过Class类提供的方法获取被加载类的类名、类的包名、类方法、类属性、类构造方法等类信息。

java编译器在编译Java类时,会创建Class对象数据,并存放在同名的.class文件中。类加载器加载该类时,JVM会检查该类是否已经加载到内存中,若是没有加载,则把class文件加载到内存并创建Class对象,创建的Class对象是该类所有实例化对象在内存中的代理。如下图所示:

image.png                    

                         

Class对象是该类所有实例化对象在内存中的代理

案例1:建立ClassTest类,并在ClassTest类的main()方法分别使用三种方式创建Book类的实例化对象,然后输出Book类实例化对象的Class对象的哈希码值,观察Book类三个实例化对象的Class对象的哈希码值是否相同。

在reflex包下新建ClassTest类。代码如下:

package reflex;
 
/**
 * @ClassName: ClassTest
 * @Description: 反射(认识Class对象)案例1
 * @author 编程训练营
 * @date
 *
 */
 
public class ClassTest {
 
    /**
     * @Title: main
     * @Description: Java程序入口main方法
     * @param @param args 参数
     *
     * @return void 返回类型 @throws
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
 
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
 
       try {
           // 使用Class.forName()
           Class<?> obj1 = Class.forName("reflex.Book");
           Book book1 = (Book) obj1.newInstance();
           // 输出book1的哈希码
           System.out.println("book1的Class对象的哈希码:---" + book1.getClass().hashCode());
 
           // 获取Book类的Class对象
           Class<?> obj2 = Book.class;
           Book book2 = (Book) obj2.newInstance();
           // 输出book2的哈希码
           System.out.println("book2的Class对象的哈希码:---" + book2.getClass().hashCode());
 
           // 使用new运算符实例化Book类
           Book book3 = new Book();
           // 输出rect2的Class对象的哈希码
           System.out.println("book3的Class对象的哈希码:---" + book3.getClass().hashCode());
 
       } catch (ClassNotFoundException e) {
 
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
 
    }
 
}

ClassTest程序分别使用Class类的forName方法、Book类的class静态变量、new运算符三种方式对Book类进行实例化,并分别输出实例化对象的哈希码。

程序执行结果如下图所示:

image.png


从执行结果可以看出,Book类的三个实例化对象book1、book2、book3的Class对象的哈希码值完全相同。因此可以说类的Class对象是该类所有实例化对象在内存中的代理。

类的哈希码通是过哈希算法散列得来的,在逻辑上可以确保类对象的唯一性,当多个类对象的哈希码相同时,就认为这多个类对象是同一个对象。

如何获取类的Class对象?

有三种方式获得Class对象:一种方式是使用Class类的forName方法来获取类的Class对象;一种方式是使用类实例化对象的getClass方法获取类的Class对象;一种方式是使用类的class静态变量获取Class对象,使用这种方式获取Class类对象时,JVM不会自动加载该类。

(1)使用Class类的forName方法获取类的Class对象

Class类的forName方法是一个静态方法,它使用一个包含类路径的文本串 String 作为输入参数,并返回该类Class 对象的引用。forName方法会调用类加载器从磁盘读取该类的字节码文件,并转换成 java.lang.Class 类的一个实例对象,并进行初始化操作,执行类的静态语句,包括静态变量的声明还有静态代码块。forName方法在调用类加载器加载类之前,会检查此类是否被加载到内存,如果没有,才会调用类加载器执行加载操作。如果该类已被加载到内存,forName会直接返回该类Class对象的引用。

Class类重载了forName方法,forName方法分别定义如下:

public static Class<?>  forName(String className)
public static Class<?>  forName(String name, boolean initialize, ClassLoader loader)

第一个forName重载方法只有一个参数,参数是包含类路径的String对象,类路径要包含类所在包的完整包路径和包名。

第二个forName重载方法有三个参数,第一个参数包含类路径的String对象,第二个参数是布尔值,设定是否初始化加载的类,第三个参数是类加载器对象,该参数用来加载由第一个参数指定的类。

(2) 使用类实例化对象的getClass方法获取类的Class对象

getClass()方法是在Object类定义的方法,方法说明如下:

●   Class<?>  getClass ()

该方法返回该实例化对象的Class对象。

例如:

// 获取Book类的Class对象
Book book = new Book();
Class<?> obj = book.getClass();

上面的例句调用book对象的getClass()方法,获取book对象的Class对象。

(3) 使用类的Class属性获取Class对象

每个类都有一个静态的Class属性,该属性指向Class对象。

例如:

// 获取Book类的Class对象
Class<?> obj = Book.class;

上面的例句获取Book类的Class对象。

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论