目录
通过MyClass.class获取,这里的MyClass指具体类~~
通过Class.forName("类的全局定名")获取,全局定名为包名+类名
通过new MyClass().getClass()获取,这里的MyClass指具体类
一、什么是反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
例子:
package com.justin.java.lang;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @program: Jdk1.8 Test
* @description: 正射、反射简单调用示例
* @author: JustinQin
* @create: 2021/8/22 13:23
* @version: v1.0.0
**/
public class Student {
private int id;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static void main(String[] args) throws Exception{
//一、正射调用过程
Student student = new Student();
student.setId(1);
System.out.println("正射调用过程Student id:" + student.getId());
//二、反射调用过程
Class clz = Class.forName("com.justin.java.lang.Student");
Constructor studentConstructor = clz.getConstructor();
Object studentObj = studentConstructor.newInstance();
Method setIdMethod = clz.getMethod("setId", int.class);
setIdMethod.invoke(studentObj, 2);
Method getIdMethod = clz.getMethod("getId");
System.out.println("正射调用过程Student id:" + getIdMethod.invoke(studentObj));
}
}
输出结果:
正射调用过程Student id:1
反射调用过程Student id:2
二.Java反射机制中获取Class的三种方式及区别?
2.1 Class的几种获取方式
-
通过
MyClass.class
获取,这里的MyClass指具体类~~
通过类名的属性class获取。
多用于参数的传递。
-
通过
Class.forName("类的全局定名")
获取,全局定名为包名+类名
将字节码文件加载进内存,返回Class对象。
多用于配置文件,将类名定义在配置文件中。读取文件,加载类。
-
通过
new MyClass().getClass()
获取,这里的MyClass指具体类
getClass()方法在Object类中定义着。
多用于对象的获取字节码文件的方式。
2.2 代码演示几种方式的区别:
(1)实体类
public class MyClass {
private static final String staticStr = "Hi";
private static int staticInt = 2021;
private String id;
static {
System.out.println("静态代码块:staticStr=" + staticStr + ",staticInt=" + staticInt);
}
{
System.out.println("动态代码块~");
}
public MyClass() {
System.out.println("无参构造方法~");
}
public MyClass(String id) {
System.out.println("有参构造方法~");
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "MyClass{" +
"id='" + id + '\'' +
'}';
}
}
(2)测试类
package com.justin.java.lang;
import org.junit.Test;
/**
* @program: Jdk1.8Test
* @description: Java反射机制中获取类的Class实例对象的常见三种方式及区别对比
* @author: JustinQin
* @create: 2021/8/22 15:04
* @version: v1.0.0
**/
public class MyClassTest {
@Test
public void test1() {
System.out.println("一、MyClass.class方式=========");
Class<?> class1 = MyClass.class;
}
@Test
public void test2() throws ClassNotFoundException {
System.out.println("二、Class.forName方式=========");
Class class2 = Class.forName("com.justin.java.lang.MyClass");
}
@Test
public void test3() {
System.out.println("三、new MyClass().getClass方式=========");
Class class3 = new MyClass().getClass();
}
@Test
public void test12() throws ClassNotFoundException {
System.out.println("一、MyClass.class方式=========");
Class<?> class1 = MyClass.class;
System.out.println("二、Class.forName方式=========");
Class class2 = Class.forName("com.justin.java.lang.MyClass");
}
@Test
public void test13() {
System.out.println("一、MyClass.class方式=========");
Class<?> class1 = MyClass.class;
System.out.println("三、new MyClass().getClass方式=========");
Class class3 = new MyClass().getClass();
}
@Test
public void test23() throws ClassNotFoundException {
System.out.println("二、Class.forName方式=========");
Class class2 = Class.forName("com.justin.java.lang.MyClass");
System.out.println("三、new MyClass().getClass方式=========");
Class class3 = new MyClass().getClass();
}
@Test
public void test() throws ClassNotFoundException {
System.out.println("四、三种方式内存地址比较=========");
Class<?> class1 = MyClass.class;
Class class2 = Class.forName("com.justin.java.lang.MyClass");
Class class3 = new MyClass().getClass();
System.out.println("比较结果=========");
System.out.println("MyClass.class和Class.forName内存地址比较是否相同:" + (class1 == class2));
System.out.println("MyClass.class和new MyClass().getClass内存地址比较是否相同:" + (class1 == class3));
System.out.println("Class.forName和new MyClass().getClass内存地址比较是否相同:" + (class2 == class3));
}
}
(3)通过测试,得到结果:
* test1()方法
一、MyClass.class方式=========
* test2()方法
二、Class.forName方式=========
静态代码块:staticStr=Hi,staticInt=2021
* test3()方法
三、new MyClass().getClass方式=========
静态代码块:staticStr=Hi,staticInt=2021
动态代码块~
无参构造方法~
* test12()方法
一、MyClass.class方式=========
二、Class.forName方式=========
静态代码块:staticStr=Hi,staticInt=2021
* test13()方法
一、MyClass.class方式=========
三、new MyClass().getClass方式=========
静态代码块:staticStr=Hi,staticInt=2021
动态代码块~
无参构造方法~
* test23()方法
二、Class.forName方式=========
静态代码块:staticStr=Hi,staticInt=2021
三、new MyClass().getClass方式=========
动态代码块~
无参构造方法~
* test()方法
四、三种方式内存地址比较=========
静态代码块:staticStr=Hi,staticInt=2021
动态代码块~
无参构造方法~
比较结果=========
MyClass.class和Class.forName内存地址比较是否相同:true
MyClass.class和new MyClass().getClass内存地址比较是否相同:true
Class.forName和new MyClass().getClass内存地址比较是否相同:true
(4)总结
MyClass.class
不会做任何类的初始化工作Class.forName
会进行类的静态初始化工作new MyClass().getClass
静态初始化和非静态初始化工作都会进行
注意:静态代码块只会被加载一次