4.3 通过类的字节文件对象获取类的成员变量
方法介绍
package cn.it.bz.Reflect; public class User { private String name; public int age; …… }
package cn.it.bz.Reflect; import java.lang.reflect.Field; public class GetField { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //获取类的字节文件对象 Class<?> userClass = Class.forName("cn.it.bz.Reflect.User"); //获取被public修饰的成员变量 Field[] fields = userClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("-----------------"); //获取类中全部的成员变量 Field[] declaredFields = userClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("-----------------"); //根据成员变量的名称返回被public修饰的成员变量 Field name = userClass.getField("age"); System.out.println(name); System.out.println("---------------------"); //根据成员变量的名称返回成员变量,忽略修饰符 Field name1 = userClass.getDeclaredField("name"); System.out.println(name1); } }
4.4 操作成员变量
package cn.it.bz.Reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class GetField2 { public static void main(String[] args) throws Exception { Class<User> userClass = User.class; //获取public修饰的叫age的成员变量 Field age = userClass.getField("age"); //向User的实例user的age赋值 User user = new User(); age.set(user,123); //向User的实例user1的age赋值 Constructor<User> constructor = userClass.getConstructor(null);//获取无参数构造方法 User user1 = constructor.newInstance(); age.set(user1,18); //获取成员变量的值 System.out.println("user:"+user.getAge()); System.out.println("user1:"+user1.getAge()); System.out.println("-------或者---------"); System.out.println(age.get(user)); System.out.println(age.get(user1)); } }
4.5 通过类的字节文件对象获取类的方法
package cn.it.bz.Reflect; import java.lang.reflect.Method; public class GetMethod { public static void main(String[] args) throws Exception { User user = new User(); Class<? extends User> aClass = user.getClass(); //获取全部的方法(包含当前User类的全部方法和其继承父类的公共方法) Method[] methods = aClass.getMethods(); for (Method method: methods) { System.out.println(method); } System.out.println("----------------------"); //根据方法名和参数获得指定方法 Method setName = aClass.getMethod("setName", String.class); System.out.println(setName); System.out.println("----------------------"); //获取私有方法 Method getName = aClass.getDeclaredMethod("suibian"); System.out.println(getName); } }
4.6 调用方法
package cn.it.bz.Reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class GetMethod2 { public static void main(String[] args) throws Exception { Class<User> userClass = User.class; //获取方法区(也是字节文件对象)中的方法 Method setName = userClass.getMethod("setName", String.class); //获取无参构造 Constructor<User> constructor = userClass.getConstructor(null); //实例化User类 User user = constructor.newInstance(); //执行setName方法,第一个参数表示是哪个实例的setName方法,第二个参数表示执行该方法需要的参数。 setName.invoke(user, "小明"); //获取成员变量的值 Method getName = userClass.getMethod("getName"); Object invoke = getName.invoke(user);//表示执行user实例的getName方法,返回值是Object实际上是String类型 System.out.println(invoke); } }
4.7 获取类的其他信息
package cn.it.bz.Reflect; public class GetClassInfo { public static void main(String[] args) { Class<User> userClass = User.class; //获取类的类名 String name = userClass.getName(); System.out.println("类的名称:"+name); //获取该类的包名 Package aPackage = userClass.getPackage(); String packageName = aPackage.getName(); System.out.println("该类所在的包名:"+packageName); //获取该类的父类(Java不支持多继承,只有一个父类) Class superclass = userClass.getSuperclass(); String superName = superclass.getName(); System.out.println("该类的父类:"+superName); //获取该类实现的接口(一个类可以实现多个接口) Class[] interfaces = userClass.getInterfaces(); for (Class anInterface: interfaces) { System.out.println("该类实现的接口:"+anInterface.getName()); } } }
五、小案例
需求:根据给定的方法名顺序来决定方法的执行顺序。
向main方法中String数组中传递参数:
package cn.it.bz.Reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; class Reflect{ public void method1(){ System.out.println("method1执行"); } public void method2(){ System.out.println("method2执行"); } public void method3(){ System.out.println("method3执行"); } } public class ReflectDemo { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { Reflect reflect = new Reflect(); if (args.length > 0) { //获取Reflect类的字节文件对象 Class<Reflect> reflectClass = Reflect.class; // 获取Reflect的所有方法 Method[] methods = reflectClass.getMethods(); for (String arg : args) { for (int i = 0; i < methods.length; i++) { if(arg.equalsIgnoreCase(methods[i].getName())){ methods[i].invoke(reflect); //没有参数就不给 } } } }else { reflect.method1(); reflect.method2(); reflect.method3(); } } }
六、反射机制的效率
由于Java反射是要解析字节码,将内存中的对象进行解析,包括了一些动态类型,而JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多!
反射机制的效率测试
package cn.it.bz.Reflect; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { //获取当前时间毫秒数 long l = System.currentTimeMillis(); //实例化对象 User user = new User(); //获取类字节文件对象 Class<? extends User> aClass = user.getClass(); //获取setName方法 Method setNameMethod = aClass.getMethod("setName", String.class); //执行1000次 for (int i = 0; i < 1000000000 ; i++) { setNameMethod.invoke(user, "name"); } long l1 = System.currentTimeMillis(); System.out.println("反射耗时::"+(l1-l)); System.out.println("----------------------"); long l2 = System.currentTimeMillis(); User user1 = new User(); for (int i = 0; i <1000000000;i++ ) { user1.setName("哈哈哈"); } long l3 = System.currentTimeMillis(); System.out.println("非反射射耗时::"+(l3-l2)); } }
七、setAccessible方法
setAccessible是启用和禁用访问安全检查的开关。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查;默认值为false。
由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的。
7.1 默认情况下获取private修饰的成员变量
package cn.it.bz.Reflect; import java.lang.reflect.Field; public class Test2 { public static void main(String[] args) throws Exception { User user = new User(); Class<? extends User> aClass = user.getClass(); //获取private修饰的成员变量name Field name = aClass.getDeclaredField("name"); //向成员变量赋值 name.set(user, "张三"); //返回user对象的name属性 String o =(String) name.get(user); System.out.println(o); } }
7.2 忽略JDK安全检查
package cn.it.bz.Reflect; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test2 { public static void main(String[] args) throws Exception { User user = new User(); Class<? extends User> aClass = user.getClass(); //获取private修饰的成员变量name Field name = aClass.getDeclaredField("name"); //忽略安全检查 name.setAccessible(true); //向成员变量赋值 name.set(user, "张三"); //返回user对象的name属性 String o =(String) name.get(user); System.out.println(o); System.out.println("----------------------"); Method suibianMethod = aClass.getDeclaredMethod("suibian"); //忽略安全检查 suibianMethod.setAccessible(true); //执行suibianM方法 suibianMethod.invoke(user); } }