围绕一个通过代码来动态的创建对象并执行对象方法的实例来了解反射
一、首先通过代码来动态的创建对象
平时都是在代码编译执行前 在编辑器 通过 Object obj = new Object();的方式来声明对象的创建
这次通过java 反射来动态的创建一个对象
准备工作:先创建好类结构
/**
* 声明一个冒险家类
*/
public class Explorer{
private String name;
private int Hp;
private int Mp;
private int hurt;
public Explorer(){}
public Explorer(String name,int Hp,int Mp,int hurt){
this.name = name;
this.Hp = Hp;
this.Mp = Mp;
this.hurt = hurt;
}
/**
* 自定义方法 超必杀打击
* @param monsterName 怪物名称
* @param monsterHp 怪物血量
*/
public void maxSuperkill(String monsterName,int monsterHp){
int hp = monsterHp-this.hurt;
System.out.println(this.name+" 放超必杀打 "+monsterName+" "+monsterName+"的血量还剩下"+hp);
}
@Override
public String toString() {
return "Explorer{" +
"name='" + name + '\'' +
", Hp=" + Hp +
", Mp=" + Mp +
", hurt=" + hurt +
'}';
}
}
平常创建类的方法的时候都是通过 方式运行的
public class Demo7 {
public static void main(String[] args) {
Explorer explorer = new Explorer("赛利亚",100,100,20);
explorer.maxSuperkill("哥布林",1000);//赛利亚放超必杀打哥布林哥布林的血量还剩下980
}
}
现在改为通过java反射来动态的执行这个maxSuperkill(String monsterName,int monsterHp )
- 首先先创建对象实例
获取对象类好多方式
方式一:
Explorer explorer = new Explorer(“赛利亚”,100,100,20);
Class c = explorer.getClass();
方式二:
Class c1 = Explorer.class;
方式三:(例子将以这种方式展开)
Class c2 = Class.forName(“com.ltx.Explorer”);
public class Demo8 {
public static void main(String[] args){
try {
// 你要创建对象所属类 的 全称类限定名
String url = "com.ltx.Explorer";
//通过 "com.ltx.Explorer" 来获取描述类名为 “com.ltx.Explorer” 的Class对象
Class ce = Class.forName(url);
// 通过 描述类名为 “com.ltx.Explorer”的Class对象 来实例化 Explorer对象
Object obj = ce.newInstance(); //这个是Explorer的默认构造函数(无参构造函数)
System.out.println(obj);// 打印结果 Explorer{name='null', Hp=0, Mp=0, hurt=0}
//获取类的域 其实就是对象的属性
Field field1 = ce.getDeclaredField("name");
Field field2 = ce.getDeclaredField("hurt");
// 打印结果 我们还需要给对象创建默认值
//因为我把Explorer的name,hp,mp,hurt的修饰符都设置的是private
//这里需要 .setAccessible(true)设置为true表示屏蔽Java的访问检查,使对象的私有属性也会被访问和设置
field1.setAccessible(true);
field2.setAccessible(true);
field1.set(obj,"赛利亚");
field2.set(obj,20);
System.out.println(obj); // Explorer{name='赛利亚', Hp=0, Mp=0, hurt=20}
//还有一种通过有参构造函数创建对象的
Object[] objects = {"赛利亚",100,100,20};
//这个 ce.getConstructors() 返回的是Constructor[] 类型的数组 就是你这个类的构造数们
// Object[]类型的参数传入就会 调用 类的有参构造方法来创建对象了
// 这种比较方便的是创建对象的时候可以初始化值了
Object obj1 = ((ce.getConstructors())[1]).newInstance(objects);
System.out.println(obj1);// 打印结果 Explorer{name='赛利亚', Hp=100, Mp=100, hurt=20}
//注意下异常处理
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
这里需要注意
Field field1 = ce.getDeclaredField("name");
Field field2 = ce.getDeclaredField("hurt");
Class.getDeclaredField(“xxx”)表示 获取类的属性 叫做“xxx”的 不包含从超类继承的属性
Class.getField(“xxx1”) 表示 获取类的修饰符为 public 的属性(其中包含从超类中继承过来的属性)
如果你把例子 改成 Field field2 = ce.getField(“hurt”); 这里就会报java.lang.NoSuchFieldException
异常因为 我在Explorer类中 将hurt设置的为 private,getFiel()表示 获取类的修饰符为 public 的属性 所有找不到
二、执行对象方法
public class Demo8 {
public static void main(String[] args){
try {
//通过 "com.ltx.Explorer" 来获取描述类名为 “com.ltx.Explorer” 的Class对象
Class ce = Class.forName("com.ltx.Explorer");
// 通过 描述类名为 “com.ltx.Explorer”的Class对象 来实例化 Explorer对象
Object obj = ce.newInstance();
System.out.println(obj);
//获取类的域 其实就是对象的属性
Field field1 = ce.getDeclaredField("name");
Field field2 = ce.getDeclaredField("hurt");
//因为我把Explorer的name,hp,mp,hurt的修饰符都设置的是private 这里需要 .setAccessible(true)设置为true表示屏蔽Java的访问检查,使对象的私有属性也会被访问和设置
field1.setAccessible(true);
field2.setAccessible(true);
field1.set(obj,"赛利亚");
field2.set(obj,20);
System.out.println(obj); // Explorer{name='赛利亚', Hp=0, Mp=0, hurt=20}
//还有一种通过有参构造函数创建对象的
Object[] objects = {"赛利亚",100,100,20};
//这个 ce.getConstructors() 返回的是Constructor[] 类型的数组 就是你这个类的构造数们
// Object[]类型的参数传入就会 调用 类的有参构造方法来创建对象了
Object obj1 = ((ce.getConstructors())[1]).newInstance(objects);
System.out.println(obj1);
//先获取你要执行的方法 getMethod(String name,Class<?>... parmTypes)
// 第一个参数表示方法名称 第二个参数就是方法参数类型数组
Method method = ce.getMethod("maxSuperkill", String.class, int.class);
//传入一个 Class[] 类型的数组也是可以的
Class[] types = new Class[2];
types[0] = String.class;
types[1] = int.class;
Method method1 = ce.getMethod("maxSuperkill", types);
//方法已经找到了就执行方法吧 invoke(Object obj, Object... args)
// 第一个参数方法对象,第二个参数方法需要传入的参数
//执行方法
method.invoke(obj,"哥布林",1000);
//传入一个 Object[] 类型的数组也是可以的
Object[] parms = new Object[2];
parms[0] = "安图恩";
parms[1] = 100000000;
//执行方法
method1.invoke(obj1,parms);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
这里的
getMethod(String name,Class<?>… parmTypes) 表示该类的和从超类继承下来的 所有public修饰的方法
getDeclaredField(xx,xx) 表示该类的所有的方法(不包括存父类继承下来的方法)。
Method method = ce.getMethod("maxSuperkill", String.class, int.class);