反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。java
反射机制主要提供了如下功能: sass
在运行时判断任意一个对象所属的类;app
在运行时构造任意一个类的对象;eclipse
在运行时判断任意一个类所具备的成员变量和方法;ide
在运行时调用任意一个对象的方法;函数
生成动态代理。测试
1) 编写一个英雄类,包含英雄的基本信息ui
public abstract class Hero implements Runnable{ public static final String WARRIOR = "Warrior"; public static final String ASSASSIN = "Assassin"; public static final String WIZARD = "Wizard"; //HP private float hitPoint; //MP private float manaPoint; //攻击力下限 private float minAttack; //攻击力上限 private float maxAttack; //护甲 private float armor; //移动速度 private int speed; //级别 private int level = 1; //力量 private float power; //力量成长 private float powerGrow; //敏捷 private float agile; //敏捷成长 private float agileGrow; //智力 private float intelligence; //智力成长 private float intelligenceGrow; //Hero Name protected String name; //英雄职业 private String heroJob; //QWER选手 public abstract void A(); public abstract void Q(); public abstract void W(); public abstract void E(); public abstract void R(); public Hero(String name, String heroJob, float hitPoint ,float manaPoint, float minAttack, float maxAttack, float armor ,int speed, float power, float powerGrow ,float agile, float agileGrow, float intelligence ,float intelligenceGrow){ this.name = name; this.heroJob = heroJob; this.hitPoint = hitPoint; this.manaPoint = manaPoint; this.minAttack = minAttack; this.maxAttack = maxAttack; this.armor = armor; this.speed = speed; this.power = power; this.powerGrow = powerGrow; this.agile = agile; this.agileGrow = agileGrow; this.intelligence = intelligence; this.intelligenceGrow = intelligenceGrow; } //打印基本信息 public void showHeroInfo(){ StringBuilder sb = new StringBuilder(); sb.append("=========INFO========\n") .append("Hero Name : ").append(name).append("\n") .append("Level : ").append(level).append("\n") .append("HP : ").append(hitPoint).append("\n") .append("MP : ").append(manaPoint).append("\n") .append("ATK : ").append(minAttack).append("~").append(maxAttack).append("\n") .append("ARMOR : ").append(armor).append("\n") .append("=========INFO========\n"); System.out.println(sb.toString()); } //升级 private void levelUp(){ if(level >= 25){ System.out.println("已经升至满级"); return; } power += powerGrow; agile += agileGrow; intelligence += intelligenceGrow; //1点力量19点血 hitPoint += powerGrow*19.0f; //1点智力13点魔 manaPoint += intelligenceGrow*13.0f; //7点敏捷1点护甲 armor += agileGrow/7.0f; growUpAttack(); level++; System.out.println("=================Level UP==============="); showHeroInfo(); } //提高攻击力 private void growUpAttack(){ switch(heroJob){ case WARRIOR : minAttack += powerGrow; maxAttack += powerGrow; break; case ASSASSIN : minAttack += agileGrow; maxAttack += agileGrow; break; case WIZARD : minAttack += intelligenceGrow; maxAttack += intelligenceGrow; break; } } //实现升级线程方法 @Override public void run(){ while(level < 25){ levelUp(); try { //10秒升一级 Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
2) 写个光法继承英雄类this
public class Ezalor extends Hero{ public Ezalor(){ super("光之守卫", Hero.WIZARD, 454f, 286f, 38f, 54f, 1.1f, 315 ,14f, 1.8f, 15f, 1.6f, 22f, 2.8f ); } public Ezalor(String heroName){ super(heroName, Hero.WIZARD, 454f, 286f, 38f, 54f, 1.1f, 315 ,14f, 1.8f, 15f, 1.6f, 22f, 2.8f ); } @Override public void A() { System.out.println(name+" 攻击"); } @Override public void Q() { System.out.println(name+" 释放了冲击波"); } @Override public void W() { System.out.println(name+" 释放了法力流失"); } @Override public void E() { System.out.println(name+" 释放了查克拉魔法"); } @Override public void R() { System.out.println(name+" 释放了变身"); } }
3) 经过类名建立光之守卫的实例 -- Class.forName()spa
public class MyTest { public static void main(String[] args) { Class<?> ezalorClazz = null; Ezalor ezalor = null; try { //根据类获取类管理器,若是没有这个类,会抛出ClassNotFoundException ezalorClazz = Class.forName("jeb.Ezalor"); //根据类管理器建立实例,若是没有默认的构造函数会抛出NoSuchMethodException ezalor = (Ezalor) ezalorClazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } //类管理器是单例的吗 Ezalor.class == ezalor.getClass System.out.println("Is Class Manager Singleton : " + ( ezalorClazz == ezalor.getClass()) ); //看下初始属性,放几个技能 ezalor.showHeroInfo(); ezalor.Q(); ezalor.W(); ezalor.E(); ezalor.R(); getClassInfo(ezalorClazz); } //获取类基本信息 private static void getClassInfo(Class<?> clazz){ StringBuilder sb = new StringBuilder(); //clazz.getName()获取类名 sb.append("Class Name : ").append(clazz.getName()).append("\n"); //获取父类,因为Java只容许单向继承,因此仅返回一个Class对象 if(clazz.getSuperclass() != null){ //若是有父类打印父类信息 getClassInfo(clazz.getSuperclass()); } System.out.println(sb.toString()); } }
输出结果:
Is Class Manager Singleton : true
=========INFO========
Hero Name : 光之守卫
Level : 1
HP : 454.0
MP : 286.0
ATK : 38.0~54.0
ARMOR : 1.1
=========INFO========
光之守卫 释放了冲击波
光之守卫 释放了法力流失
光之守卫 释放了查克拉魔法
光之守卫 释放了变身
Class Name : java.lang.Object
Class Name : jeb.Hero
Class Name : jeb.Ezalor
4) 获取类的构造方法,并调用指定构造方法建立实例--getConstructor(Class<?>... arg0)
上面的例子利用了反射,经过光法的类名,调用默认的构造函数,建立了光法的实例。若是但愿使用第二个构造函数建立一个有自定义名称的光法应该怎样呢?
private static void createMyEzalor(){ try { Class<?> ezalorClazz = Class.forName("jeb.Ezalor"); //经过参数类型,查找参数为String的构造函数 Class<?>[] parmType = new Class<?>[]{String.class}; Constructor constructor = ezalorClazz.getConstructor(parmType); //经过制定的构造函数建立实例 Ezalor ezalor = (Ezalor) constructor.newInstance("甘道夫"); ezalor.showHeroInfo(); //启动一个线程开始打怪升级 Thread tr = new Thread(ezalor); tr.start(); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } }
输出结果: 建立了名称为甘道夫的光法,并开始打怪升级
=========INFO========
Hero Name : 甘道夫
Level : 1
HP : 454.0
MP : 286.0
ATK : 38.0~54.0
ARMOR : 1.1
=========INFO========
=================Level UP===============
=========INFO========
Hero Name : 甘道夫
Level : 2
HP : 488.2
MP : 322.4
ATK : 40.8~56.8
ARMOR : 1.3285714
=========INFO========
=================Level UP===============
=========INFO========
Hero Name : 甘道夫
Level : 3
HP : 522.4
MP : 358.8
ATK : 43.6~59.6
ARMOR : 1.5571429
=========INFO========
....
4) 经过反射看看光法类有什么函数--getDeclaredMethods
每10秒钟升一级,做为一个挂逼,来找找光法有什么做弊的可能。
private static void getDeclaredMethods(Ezalor ezalor, Class<?> clazz){ //获取父类方法 if(clazz.getSuperclass()!= null){ getDeclaredMethods(ezalor, clazz.getSuperclass()); } //获取全部方法 Method[] methods = clazz.getDeclaredMethods(); StringBuilder sb = new StringBuilder(); for(Method method : methods){ sb.append("=======================\n") .append("Method Belongs : ").append(clazz.getName()).append("\n") .append("Method Modifiers : ") //获取方法修饰符 .append(Modifier.toString(method.getModifiers())).append("\n") //获取方法返回值 .append("Return Type : ").append(method.getReturnType()).append("\n") .append("Method Name : ").append(method.getName()).append("\n"); Parameter[] params = method.getParameters(); if(params != null && params.length > 0){ sb.append("Method Params : \n"); for(Parameter param : params){ sb.append("Param Name: ").append(param.getName()).append("\n") .append("Param Type: ").append(param.getType().getName()).append("\n"); } } sb.append("=======================\n"); } System.out.println(sb.toString()); }
建立一个实例,调用这个方法
public static void main(String[] args){ Ezalor ezalor = new Ezalor(); getDeclaredMethods(ezalor, ezalor.getClass()); }
输出结果:
... 省略掉了Object的方法 ...
=======================
Method Belongs : jeb.Hero
Method Modifiers : public
Return Type : void
Method Name : run
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public abstract
Return Type : void
Method Name : E
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public abstract
Return Type : void
Method Name : A
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public abstract
Return Type : void
Method Name : R
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public
Return Type : void
Method Name : showHeroInfo
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public abstract
Return Type : void
Method Name : W
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : public abstract
Return Type : void
Method Name : Q
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : private
Return Type : void
Method Name : levelUp
=======================
=======================
Method Belongs : jeb.Hero
Method Modifiers : private
Return Type : void
Method Name : growUpAttack
=======================
=======================
Method Belongs : jeb.Ezalor
Method Modifiers : public
Return Type : void
Method Name : E
=======================
=======================
Method Belongs : jeb.Ezalor
Method Modifiers : public
Return Type : void
Method Name : A
=======================
=======================
Method Belongs : jeb.Ezalor
Method Modifiers : public
Return Type : void
Method Name : R
=======================
=======================
Method Belongs : jeb.Ezalor
Method Modifiers : public
Return Type : void
Method Name : W
=======================
=======================
Method Belongs : jeb.Ezalor
Method Modifiers : public
Return Type : void
Method Name : Q
=======================
输出了Ezalor类及其父类的全部方法。
试试将getDeclaredMethods 换成 getMethods 有什么区别?
getMethods 仅返回当前类的public方法,getDeclaredMethods返回当前类全部方法。
5) 开始做弊了 -- method.invoke(Object target, Object .. args)
=======================
Method Belongs : jeb.Hero
Method Modifiers : private
Return Type : void
Method Name : levelUp
=======================
咱们发现了下面这个方法,看着名字就像是升级。这个方法是private的,没法经过实例直接调用。
可是反射依然是能够暴力调用的 :
private static Method getLevelUpMethod(Ezalor ezalor, Class<?> clazz) throws SecurityException{ //查找名为levelUp的方法 Method lvlupMethod; try { lvlupMethod = clazz.getDeclaredMethod("levelUp", null); } catch (NoSuchMethodException e) { //子类没有这个方法便查找父类 if(clazz.getSuperclass() != null){ lvlupMethod = getLevelUpMethod(ezalor, clazz.getSuperclass()); }else{ return null; } } return lvlupMethod; } private static void whoIsYourDaddy(Ezalor ezalor){ try { //查找升级方法 Method lvlupMethod = getLevelUpMethod(ezalor, ezalor.getClass()); //反射调用方法25次 for(int i = 0; i < 25; i++){ lvlupMethod.invoke(ezalor, null); } } catch ( SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.out.println("Something Wrong !"); e.printStackTrace(); } } public static void main(String[] args){ Ezalor ezalor = new Ezalor(); whoIsYourDaddy(ezalor); }
运行结果:
Something Wrong !
java.lang.IllegalAccessException: Class jeb.MyTest can not access a member of class jeb.Hero with modifiers "private"
因为这个方法是private的,Java的访问检查控制,抛出了没有权限调用方法的异常!
解决方法:
使用 method.setAccessible(true)来禁用访问检查控制。
修改whoIsYourDaddy代码以下:
private static void whoIsYourDaddy(Ezalor ezalor){ try { //查找升级方法 Method lvlupMethod = getLevelUpMethod(ezalor, ezalor.getClass()); //禁用访问权限检查 lvlupMethod.setAccessible(true); //反射调用方法25次 for(int i = 0; i < 25; i++){ lvlupMethod.invoke(ezalor, null); } } catch ( SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.out.println("Something Wrong !"); e.printStackTrace(); } }
运行结果:
...
=================Level UP===============
=========INFO========
Hero Name : 光之守卫
Level : 25
HP : 1274.7998
MP : 1159.6003
ATK : 105.200035~121.20006
ARMOR : 6.5857143
=========INFO========
已经升至满级
是否是很炫酷,做弊升到了满级。可是做为一个开挂狂魔,不能止步于25级,有没有什么办法能直接修改属性值呢?
5) 做弊狂魔,直接获取修改实例私有属性--getDeclaredFields()
private static void whoIsYourGrandPa(Ezalor ezalor, Class<?> clazz) throws IllegalArgumentException, IllegalAccessException{ //获取父类属性 if(clazz.getSuperclass()!= null){ whoIsYourGrandPa(ezalor, clazz.getSuperclass()); } //获取全部属性 Field[] fields = clazz.getDeclaredFields(); for(Field field : fields){ switch (field.getName()){ case "hitPoint" : case "manaPoint" : case "minAttack" : case "maxAttack" : case "armor" : //禁用访问权限检查 field.setAccessible(true); //设置属性值 field.set(ezalor, 9999f); } } } public static void main(String[] args){ Ezalor ezalor = new Ezalor("暴走甘道夫"); try { whoIsYourGrandPa(ezalor, ezalor.getClass()); ezalor.showHeroInfo(); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } }
输出结果:
=========INFO========
Hero Name : 暴走甘道夫
Level : 1
HP : 9999.0
MP : 9999.0
ATK : 9999.0~9999.0
ARMOR : 9999.0
=========INFO========
试试将getDeclaredFields 换成 getFields有什么区别?
与getDeclaredMehods/getMethods类似,getFields仅返回当前类的public属性,getDeclaredFields返回当前类全部属性。
使用getFields方法就不能获得暴走甘道夫了。
6) 贴个完整的测试类
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; public class MyTest { public static void main(String[] args) { Class<?> ezalorClazz = null; Ezalor ezalor = null; try { //根据类获取类管理器,若是没有这个类,会抛出ClassNotFoundException ezalorClazz = Class.forName("jeb.Ezalor"); //根据类管理器建立实例,若是没有默认的构造函数会抛出NoSuchMethodException ezalor = (Ezalor) ezalorClazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } //类管理器是单例的吗 Ezalor.class == ezalor.getClass System.out.println("Is Class Manager Singleton : " + ( ezalorClazz == ezalor.getClass()) ); //看下初始属性,放几个技能 ezalor.showHeroInfo(); ezalor.Q(); ezalor.W(); ezalor.E(); ezalor.R(); getClassInfo(ezalorClazz); //getMethods(ezalor, ezalorClazz); getDeclaredMethods(ezalor, ezalorClazz); //createMyEzalor(); } //获取类基本信息 private static void getClassInfo(Class<?> clazz){ StringBuilder sb = new StringBuilder(); //clazz.getName()获取类名 sb.append("Class Name : ").append(clazz.getName()).append("\n"); //获取父类,因为Java只容许单向继承,因此仅返回一个Class对象 if(clazz.getSuperclass() != null){ //若是有父类打印父类信息 getClassInfo(clazz.getSuperclass()); } System.out.println(sb.toString()); } private static void createMyEzalor(){ try { Class<?> ezalorClazz = Class.forName("jeb.Ezalor"); //经过参数类型,查找参数为String的构造函数 Class<?>[] parmType = new Class<?>[]{String.class}; Constructor constructor = ezalorClazz.getConstructor(parmType); //经过制定的构造函数建立实例 Ezalor ezalor = (Ezalor) constructor.newInstance("甘道夫"); ezalor.showHeroInfo(); //启动一个线程开始打怪升级 Thread tr = new Thread(ezalor); tr.start(); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } private static void getMethods(Ezalor ezalor, Class<?> clazz){ //获取父类方法 if(clazz.getSuperclass()!= null){ getMethods(ezalor, clazz.getSuperclass()); } //获取public方法 Method[] methods = clazz.getMethods(); StringBuilder sb = new StringBuilder(); for(Method method : methods){ sb.append("=======================\n") .append("Method Belongs : ").append(clazz.getName()).append("\n") .append("Method Modifiers : ") //获取方法修饰符 .append(Modifier.toString(method.getModifiers())).append("\n") .append("Return Type : ").append(method.getReturnType()).append("\n") .append("Method Name : ").append(method.getName()).append("\n"); Parameter[] params = method.getParameters(); if(params != null && params.length > 0){ sb.append("Method Params : \n"); for(Parameter param : params){ sb.append("Param Name: ").append(param.getName()).append("\n") .append("Param Type: ").append(param.getType().getName()).append("\n"); } } sb.append("=======================\n"); } System.out.println(sb.toString()); } private static void getDeclaredMethods(Ezalor ezalor, Class<?> clazz){ //获取父类方法 if(clazz.getSuperclass()!= null){ getDeclaredMethods(ezalor, clazz.getSuperclass()); } //获取全部方法 Method[] methods = clazz.getDeclaredMethods(); StringBuilder sb = new StringBuilder(); for(Method method : methods){ sb.append("=======================\n") .append("Method Belongs : ").append(clazz.getName()).append("\n") .append("Method Modifiers : ") //获取方法修饰符 .append(Modifier.toString(method.getModifiers())).append("\n") //获取方法返回值 .append("Return Type : ").append(method.getReturnType()).append("\n") .append("Method Name : ").append(method.getName()).append("\n"); Parameter[] params = method.getParameters(); if(params != null && params.length > 0){ sb.append("Method Params : \n"); for(Parameter param : params){ sb.append("Param Name: ").append(param.getName()).append("\n") .append("Param Type: ").append(param.getType().getName()).append("\n"); } } sb.append("=======================\n"); } System.out.println(sb.toString()); } private static Method getLevelUpMethod(Ezalor ezalor, Class<?> clazz) throws SecurityException{ //查找名为levelUp的方法 Method lvlupMethod; try { lvlupMethod = clazz.getDeclaredMethod("levelUp", null); } catch (NoSuchMethodException e) { //子类没有这个方法便查找父类 if(clazz.getSuperclass() != null){ lvlupMethod = getLevelUpMethod(ezalor, clazz.getSuperclass()); }else{ return null; } } return lvlupMethod; } private static void whoIsYourDaddy(Ezalor ezalor){ try { //查找升级方法 Method lvlupMethod = getLevelUpMethod(ezalor, ezalor.getClass()); //禁用访问权限检查 lvlupMethod.setAccessible(true); //反射调用方法25次 for(int i = 0; i < 25; i++){ lvlupMethod.invoke(ezalor, null); } } catch ( SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.out.println("Something Wrong !"); e.printStackTrace(); } } private static void whoIsYourGrandPa(Ezalor ezalor, Class<?> clazz) throws IllegalArgumentException, IllegalAccessException{ //获取父类属性 if(clazz.getSuperclass()!= null){ whoIsYourGrandPa(ezalor, clazz.getSuperclass()); } //获取全部属性 Field[] fields = clazz.getFields(); for(Field field : fields){ switch (field.getName()){ case "hitPoint" : case "manaPoint" : case "minAttack" : case "maxAttack" : case "armor" : //禁用访问权限检查 field.setAccessible(true); //设置属性值 field.set(ezalor, 9999f); } } } }
7) 最后
Class类中还提供了一些其余的方法,用于获取类/方法/属性注解等功能。这里不所有列出了。
过了打游戏的年纪,怀念下那些年一块儿打过的Dota :)