Java-反射
文章推荐
https://blog.csdn.net/ju_362204801/article/details/90578678
有视频,非常好理解,强烈推荐。
简单理解
类是一个模板,用于描述一类对象的行为和状态,对象是类的一个实例,有状态和行为。类对象,是用于描述这种类,都有什么属性、方法的。
反射是从Class类对象开始,因为万物皆可对象,代码存储在.java文件中,编译得到.class文件,用于执行,即这些class文件就是Class类。反射就是对这个这个Class类进行 “解剖” ,感觉这个词用的很形象。“解剖” 是在Class类对象中,利用反射把一个类的成员变量、方法、属性等信息,映射成一个个对象。然后对对象进行操作。
反射主要是用于框架(尤其是Spring框架)和工具开发,是框架设计的关键,但耗性能。当需要切换调用业务方法,可以不需要修改代码,不需要重新编译,只修改对应配置文件,通过反射调用,实现切换调用另外的业务方法。
获取类对象
使用反射先要得到想反射的类,有多种方法获得Class对象。
- Class.forName
- Test_Main.class
- new Test_Main().getClass()
需要抛出多种异常
//三种获取Class类的方法 public void test1() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); } public void test2() throws Exception{ Class tClass = Test_Main.class; } public void test3() throws Exception{ Class tClass = new Test_Main().getClass(); }
Class实例: 就是指JVM中一份字节码,一个类在JVM中只有一份字节码。在一个JVM中,一种类,只会有一个类对象存在。所以不同方式取出来的类对象,都是一样的。
Java创建对象
另外Java创建对象的方法有很多。
- 通过new语句实例化一个对象
- 通过反射机制创建对象
- 通过clone()方法创建对象
- 在使用clone()方法,不会调用构造函数,而是需要有一个分配了内存的源对象。在创建新对象时,首先应该分配一个和源对象一样大的内存空间。
- 通过反序列化的方式创建对象
- 序列化就是把对象通过流的方式存储到文件里,那么反序列化就是把字节内容读出来,并还原成Java对象,这里还原的过程就是反序列化,使用反序列化时也不会调用构造方法。
反射方法
无参方法
/* m1() 无参方法 public void m1(){ System.out.println("m1"); } */ @Test public void test1() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Test_Main test_main = (Test_Main)tClass.newInstance(); //新建实例 Method m1 = tClass.getMethod("m1",null); //输入空值 m1.invoke(test_main,null); //调用实例和输入值 }
含参方法
/* m2(): public void m2(String name){ System.out.println(name); } */ @Test public void test2() throws Exception{ Class tClass = Test_Main.class; Test_Main test_main = (Test_Main)tClass.newInstance(); Method m2 = tClass.getMethod("m2", String.class); m2.invoke(test_main,"tom");//输出tom }
有返回类型和多参数方法
/* public String m4(String name ,int age){ return name+age; } */ @Test public void test4() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Test_Main test_main = (Test_Main) tClass.newInstance(); Method m4 = tClass.getMethod("m4", String.class, int.class); String returnValue = (String) m4.invoke(test_main,"jerry",5); //返回类型 System.out.println(returnValue); //打印jerry5 }
private 方法
反射private 方法会显示带锁,需要使用 getDeclaredMethod 方法调用,设置对象的Accessible的访问标志位为true,就可以通过反射获取私有变量。
/* private void m3(){ System.out.println("m3"); } */ @Test public void test3() throws Exception{ Class tClass = new Test_Main().getClass(); Test_Main test_main = (Test_Main)tClass.newInstance(); //新建实例 Method m3 = tClass.getDeclaredMethod("m3",null); //强制访问 m3.setAccessible(true); //设置访问标志位为 True m3.invoke(test_main,null); //打印m3 }
static方法
不需要新建实例,直接获取方法。
/* static 方法 public static void m5(){ System.out.println("m5"); } */ @Test public void test5() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Method m5 = tClass.getMethod("m5",null); //没有返回值 m5.invoke(null,null); // 没有实例化对象,无输入参数 打印m5 }
反射属性和反射构造函数方法都是使用类似方法步骤。
反射属性字段
//属性字段 public String name = "Paige"; public static int id = 147; private int age = 5;
获取/修改属性
@Test public void test1() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Test_Main test_main = (Test_Main) tClass.newInstance(); //新建实例 Field field1 = tClass.getField("name"); //获取属性 String returnValue = (String) field1.get(test_main); //通过get获取属性 System.out.println(returnValue); //打印出:Paige field1.set(test_main,"tom"); //set修改属性 System.out.println(field1.get(test_main)); //打印出:tom }
private属性
Field field2 = tClass.getDeclaredField("age"); field2.setAccessible(true); //private属性同样需要强制访问 System.out.println(field2.get(test_main)); //打印出:5
static属性
Field field3 = tClass.getField("id"); System.out.println(field3.get(null)); //static 同样不需要实例,设置为null即可 //打印出:147
反射构造函数方法都是使用类似方法步骤,只是使用方法不同。
反射构造方法
无参构造方法
/* public Test_Main() { System.out.println("无参构造方法"); } */ @Test public void test_constructor1() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Constructor constructor1 = tClass.getConstructor(null); //得到无参构造函数 constructor1.newInstance(null); //用构造方法创建对象 }
一个参数
/* public Test_Main(String name) { this.name = name; System.out.println("name:"+name); } */ @Test public void test_constructor2() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Constructor constructor1 = tClass.getConstructor(String.class); //得到String构造函数 constructor1.newInstance("tomas"); //用构造方法创建对象,输出name: tomas }
多个参数
/* public Test_Main(String name, int age) { this.name = name; this.age = age; System.out.println("name: "+name+" age: "+age); } */ @Test public void test_constructor3() throws Exception{ Class tClass = Class.forName("com.hut.djh.Test_Main"); Constructor constructor1 = tClass.getConstructor(String.class,int.class); //得到String、int构造函数 constructor1.newInstance("tomas",58); //用构造方法创建对象,输出name: tomas age: 58 }