1、反射概述
2、反射的使用
在另一个包中新建一个类,用于体验反射的效果:
package kfk.test.JavaLearning.reflectClass;
public class ReflectClass {
public String name;
public float hp;
private int moveSpeed;
public ReflectClass() {
System.out.println("无参数构造器");
}
public ReflectClass(String name){
this.name = name;
System.out.println("有一个参数的构造器");
}
public ReflectClass(String name, float hp){
this.hp = hp;
System.out.println("有多个参数的构造器");
}
public int getMoveSpeed() {
return moveSpeed;
}
public void setMoveSpeed(int moveSpeed) {
this.moveSpeed = moveSpeed;
}
}
2.1 获取类对象
反射有三种获取类对象的方式:
- Class.forName()(常用)
- Hero.class
- new Hero().getClass()
package kfk.test.JavaLearning.reflectTest;
import kfk.test.JavaLearning.reflectClass.ReflectClass;
public class ReflectTest {
public static void main(String[] args) {
String className = "kfk.test.JavaLearning.reflectClass.ReflectClass";
try{
//获取类对象的第一种方式
Class pClass1 = Class.forName(className);
//获取类对象的第二种方式
Class pClass2 = ReflectClass.class;
//获取类对象的第三种方式
Class pClass3 = new kfk.test.JavaLearning.reflectClass.ReflectClass().getClass();
System.out.println(pClass1==pClass2);//输出true
System.out.println(pClass1==pClass3);//输出true
}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}
一般来说常用的是第一种方法,第二种方法要引入包,第三种方法已经生成了实例对象,就没必要得到类对象了,类对象就是用于得到实例对象。
2.2 反射创建实例对象
基本步骤:
- 1、获取类对象:
Class clazz = Class.forName("包名.类名")
- 2、获取对象构造器:
Constructor con = clazz.getDeclaredConstructor(形参.class ...)
- 3、获取实例对象:
类名 实例名 = con.newInstance(实参 ...)
,如果是私有的构造器,要先con.setAccessible(true)
获取类对象的方法如上所示,下面是获取构造器和新建
clazz.getConstructors()
:获取所有公有的构造器clazz.getDeclaredConstructors()
:获取所有的构造器clazz.getConstructor(形参类型.class ...)
:获取指定的公有构造器clazz.getDeclaredConstructor(形参类型.class ...)
:获取指定的任意一个构造器
前两个得到的是一个Constructor的数组,后面两个则是得到特定的构造器
例子:
package kfk.test.JavaLearning.reflectTest;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args) throws Exception{
String className = "kfk.test.JavaLearning.reflectClass.ReflectClass";
Class clazz = Class.forName(className);
Constructor con = clazz.getDeclaredConstructor(String.class, float.class);
System.out.println(con);
Object obj = con.newInstance("赵云", 100);
// 输出:
// public kfk.test.JavaLearning.reflectClass.ReflectClass(java.lang.String,float)
// 有多个参数的构造器
}
}
2.3 获取成员变量及使用
基本步骤:
- 1、获取类对象 clazz
- 2、获取对象的属性
Field f1 = clazz.getDeclaredField("属性名")
- 3、修改属性:
f1.set(clazz,实参)
,如果是私有的也要先用setAccessible的方法
其中:
- getField 只能获取public的,包括从父类继承来的字段。
- getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
示例:
package kfk.test.JavaLearning.reflectTest;
import kfk.test.JavaLearning.reflectClass.ReflectClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args) throws Exception{
String className = "kfk.test.JavaLearning.reflectClass.ReflectClass";
Class clazz = Class.forName(className);
Constructor con = clazz.getDeclaredConstructor(String.class, float.class);
System.out.println(con);
Object obj = con.newInstance("赵云", 100);
ReflectClass obj1 = (ReflectClass)obj;
obj1.hp = 99;
Field f1 = obj1.getClass().getDeclaredField("moveSpeed");
f1.setAccessible(true);
f1.set(obj1, 10);
System.out.println(((ReflectClass)obj).getMoveSpeed());
}
}
2.4 获取成员方法及使用
基本步骤:
与获取成员变量的方法基本一致:
- 1、获取类对象 clazz
- 2、获取对象的方法
Method m1 = clazz.getDeclaredMethod("方法名", 形参的类型 ... )
- 3、调用对象方法:m1.invoke(对象, 实参…)
同样:
- getMethod 只能获取public的,包括从父类继承来的方法。
- getDeclaredMethod 可以获取本类所有的方法,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
例子:
package kfk.test.JavaLearning.reflectTest;
import kfk.test.JavaLearning.reflectClass.ReflectClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args) throws Exception{
String className = "kfk.test.JavaLearning.reflectClass.ReflectClass";
Class clazz = Class.forName(className);
Constructor con = clazz.getDeclaredConstructor(String.class, float.class);
System.out.println(con);
Object obj = con.newInstance("赵云", 100);
ReflectClass obj1 = (ReflectClass)obj;
Method m1 = obj1.getClass().getDeclaredMethod("setMoveSpeed", int.class);
m1.setAccessible(true);
m1.invoke(obj1, 20);
System.out.println(obj1.getMoveSpeed());
}
}
2.5 获取main方法及使用
与获取方法一样:
try {
//1、获取HeroPlus对象的字节码
Class clazz = Class.forName("className");
Method methodMain = clazz.getMethod("main", String[].class);
//第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
//这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。所以需要将它强转。
methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
} catch (Exception e) {
e.printStackTrace();
}
3、反射的用处
4、反射源码及性能问题
https://www.jianshu.com/p/3ea4a6b57f87
后续深入了解后补