网站首页 > 精选教程 正文
在上篇文章《一篇文章全面了解Java反射机制》中我们学习了Java反射机制的基本使用,留心的朋友可能已经注意到了,在文中提到了三种获取Class对象的方法。
如果面试中涉及到Java反射,那么遇到该面试题的概率将大大增加。
以下三种获取Class对象的方式有什么不同?
1、new Object().getClass 2、Object.class 3、 Class.forName("java.util.String")
本篇文章就通过实例带大家来了解一下这三种获取Class对象的区别。示例基于JDK8。
实例演示场景一
为了更好的演示,我们先创建一个对象Person,对象内部定义了一些静态的方法。
public class Person {
static {
System.out.println("Person:静态代码块");
}
{
System.out.println("Person:动态代码块");
}
public Person(){
System.out.println("Person:构造方法");
}
}
在Person对象中分别定义了:静态代码块、动态代码块、构造方法。
针对上面的实例,我们构建了三个单元测试的场景,对应代码如下:
public class GetClassTest {
@Test
public void test1(){
Class<?> clz = Person.class;
}
@Test
public void test2() throws ClassNotFoundException {
Class<?> clz = Class.forName("com.choupangxia.reflect.Person");
}
@Test
public void test3() {
Class<?> clz = new Person().getClass();
}
}
分别执行三个单元测试发现,第一个单元测试没打印任何内容;第二个单元测试打印了“静态方法”中的内容;第三个单元测试打印出了全部内容:
Person:静态代码块
Person:动态代码块
Person:构造方法
也就是说通过Person.class的方法获取对象的Class对象,根本不会调用对象中任何的代码块或代码。而Class.forName()会调用静态代码块的内容。
而第三种方式打印所有内容的原因很显然,就因为要先实例化对象。
实例演示场景二
下面再组合一下这三种方式,看看一些其他的效果。
首先,依次调用三个获取Class对象的方法:
@Test
public void test4() throws ClassNotFoundException {
Class<?> clz = Person.class;
System.out.println("---------------");
clz = Class.forName("com.choupangxia.reflect.Person");
System.out.println("---------------");
clz = new Person().getClass();
}
test4打印日志如下:
---------------
Person:静态代码块
---------------
Person:动态代码块
Person:构造方法
通过日志说明,Class.forName()方法执行过静态代码块之后,new Person().getClass()就不再会执行同样的静态代码块了。这也证明静态代码块只会被初始化一次。
再调整组合第二种场景:
@Test
public void test5() throws ClassNotFoundException {
Class<?> clz = new Person().getClass();
System.out.println("---------------");
clz = Class.forName("com.choupangxia.reflect.Person");
}
test5打印日志如下:
Person:静态代码块
Person:动态代码块
Person:构造方法
---------------
同样只打印一次静态代码块的操作。再次证明类中的静态代码块只会被初始化一次。
实例演示场景三
这里,我们比较一下三种形式获得的Class对象是否是相同的。测试代码如下:
@Test
public void test6() throws ClassNotFoundException {
Class<?> clz1 = Person.class;
Class<?> clz2 = Class.forName("com.choupangxia.reflect.Person");
Class<?> clz3 = new Person().getClass();
System.out.println(clz1 == clz2);
System.out.println(clz2 == clz3);
}
注意,上面我们使用的是等号,也就是说比较的是引用。猜猜打印的结果?
true
true
三种形式获得的Class对象是同一个对象。这是为什么呢?
这要涉及到类的加载过程,我们知道类加载过程分:加载阶段、连接阶段和初始化阶段。
类的加载阶段是将class文件中的二进制数据读取到内存中,然后将该字节流所代表的静态存储结构转化为方法区中运行时的数据结构,并且在堆内存中生成一个该类的java.lang.class对象,作为方法区数据结构的入口。
类加载阶段的最终产物是堆内存中的class对象,对于同一个Classloader对象,不管某个类被加载多少次,对应堆内存中的class对象始终只有一个。
也就是说无论通过哪种形式来获取Class对象,获得的都是堆内存中对应的Class对象。
回顾三种形式
(1)类名.class:JVM将使用类装载器,将类装入内存(前提是:类还没有装入内存),不做类的初始化工作,返回Class的对象。
(2)Class.forName("类名字符串"):装入类,并做类的静态初始化,返回Class的对象。
(3)实例对象.getClass():对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象(子对象的引用会赋给父对象的引用变量中)所属的类的Class的对象。
本文首发来自微信公众号:程序新视界。一个软实力、硬技术同步学习的平台。
猜你喜欢
- 2025-04-26 Java面试题Spring篇
- 2025-04-26 2023年Java基础面试题目收集整理归纳(持续更新)
- 2025-04-26 Java 反射原理深度剖析:从困惑到精通
- 2025-04-26 月薪30k 的Java面试题,哭着也要背完!(附答案)
- 2025-04-26 java面试题整理《基础篇》六
- 2025-04-26 Java面试高频问答
- 2025-04-26 面试官最爱问的Java问题
- 2025-04-26 Java面试宝典 - 用一篇文章讲清楚 Java 的反射机制
- 2025-04-26 Java面试题及答案总结(2025版持续更新)
- 2025-04-26 又被问到了, java 面试题:反射的实现原理及用途?
你 发表评论:
欢迎- 04-26Java面试题Spring篇
- 04-262023年Java基础面试题目收集整理归纳(持续更新)
- 04-26Java 反射原理深度剖析:从困惑到精通
- 04-26月薪30k 的Java面试题,哭着也要背完!(附答案)
- 04-26java面试题整理《基础篇》六
- 04-26Java面试高频问答
- 04-26面试官最爱问的Java问题
- 04-26Java面试宝典 - 用一篇文章讲清楚 Java 的反射机制
- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)