java 反射学习:
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。
在运行时获取类的对象;
在运行时访问java对象的属性,方法,构造方法等。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
一. 反射机制概念
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。
二. 反射机制的作用
在运行时判断任意一个对象所属的类;在运行时获取类的对象;
在运行时访问java对象的属性,方法,构造方法等。
三. 反射机制的优点与缺点
首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
四. 反射机制的示例
package cfanshe; class notMainMethord { private void testForMain() { System.out.println("demo1"); } } public class ReflectTestDemo{ public static void main(String[] args) { //通过对象获取完整的包名和类名 notMainMethord rtd = new notMainMethord(); System.out.println(rtd.getClass().getName());//cfanshe.notMainMethord //三种实例化Class类的方法 Class<?> demo1 = null; Class<?> demo2 = null; Class<?> demo3 = null; try { demo1 = Class.forName("cfanshe.notMainMethord"); } catch (Exception e) { e.printStackTrace(); } demo2 = new notMainMethord().getClass(); demo3 = notMainMethord.class; System.out.println("demo1: "+demo1); System.out.println("demo2: "+demo2); System.out.println("demo3: "+demo3); //通过Class实例化其他类的对象 Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } Student stu = null; try { stu = (Student)demo.newInstance(); } catch (Exception e) { e.printStackTrace(); } stu.setAge(28); stu.setName("SELECT_BIN"); System.out.println(stu); } }
package cfanshe; public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "["+this.name+" "+this.age+"]"; } }但是注意一下,当我们把Student中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:
比如定义了一个构造函数:
public Student(String name, int age) { this.age=age; this.name=name; }然后继续运行上面的程序,会出现:
java.lang.InstantiationException: cfanshe.Student at java.lang.Class.newInstance(Unknown Source) at cfanshe.ReflectTestDemo.main(ReflectTestDemo.java:36) Caused by: java.lang.NoSuchMethodException: cfanshe.Student.<init>() at java.lang.Class.getConstructor0(Unknown Source) ... 2 more Exception in thread "main" java.lang.NullPointerException at cfanshe.ReflectTestDemo.main(ReflectTestDemo.java:40)
所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数。
调用其它类中的构造函数:
package cfanshe; public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student() { } public Student(int age) { this.age=age; } public Student(String name) { this.name=name; } public Student(String name, int age) { this.age=age; this.name=name; } @Override public String toString() { return "["+this.name+" "+this.age+"]"; } }
package cfanshe; import java.lang.reflect.Constructor; public class ReflectTestDemo{ public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } Student stu1 = null; Student stu2 = null; Student stu3 = null; Student stu4 = null; //取得全部的构造函数 Constructor<?> cons[] = demo.getConstructors(); try { stu1 = (Student)cons[0].newInstance(28); stu2 = (Student)cons[1].newInstance("SELECT_BIN"); stu3 = (Student)cons[2].newInstance("SELECT_BIN",28); stu4 = (Student)cons[3].newInstance(); } catch (Exception e) { e.printStackTrace(); } System.out.println(stu1); System.out.println(stu2); System.out.println(stu3); System.out.println(stu4); } }
这里获取构造器列表的时候每个构造器使用是由顺序的,至于顺序怎么排的,待会再说,
顺序怎么确定,一个笨一点的办法,用debug可以看到cons里面的内容:
[public cfanshe.Student(int), public cfanshe.Student(java.lang.String), public cfanshe.Student(java.lang.String,int), public cfanshe.Student()]
运行结果:
[null 28] [SELECT_BIN 0] [SELECT_BIN 28] [null 0]
返回实现类的接口:
package cfanshe; public interface China { public static final String name = "binguo"; public static int age=16; public void sayChina(); public void sayHello(String name, int age); }
package cfanshe; public class Student implements China{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public void sayChina() { System.out.println("hello ,china"); } @Override public void sayHello(String name, int age) { System.out.println(name+" "+age); } }
package cfanshe; import java.lang.reflect.Constructor; public class ReflectTestDemo{ public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } //保存所有的接口 Class<?> inters[] = demo.getInterfaces(); //取得父类(因为是单继承,所以只有一个) Class<?> objs = demo.getSuperclass(); for(Class inter : inters) { System.out.println("实现的接口 :: "+inter); } System.out.println("继承的父类为 :: "+objs); //获取其他类中的全部构造函数 Constructor<?> cons[] = demo.getConstructors(); for(Constructor con : cons) { System.out.println("构造方法: "+con); } } }
控制台输出:
实现的接口 :: interface cfanshe.China 继承的父类为 :: class java.lang.Object 构造方法: public cfanshe.Student(int) 构造方法: public cfanshe.Student(java.lang.String) 构造方法: public cfanshe.Student(java.lang.String,int) 构造方法: public cfanshe.Student()
获取其他类的全部属性,并将这些类整理在一起,也就是通过反射获取这些类的全部属性
package cfanshe; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class ReflectTestDemo{ public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } System.out.println("===============本类属性========================"); //取得本类的全部属性 Field[] fields = demo.getDeclaredFields(); for(Field field:fields) { //权限修饰符 int mo = field.getModifiers(); String priv = Modifier.toString(mo); //属性类型 Class<?> type = field.getType(); System.out.println(priv + " " + type.getName() + " " + field.getName() + ";"); } System.out.println("===============实现的接口或者父类的属性========================"); //取得实现的接口和父类的属性 Field field1[] = demo.getFields(); for(Field field:field1) { //权限修饰符 int mo = field.getModifiers(); String priv = Modifier.toString(mo); //属性类型 Class<?> type = field.getType(); System.out.println(priv + " " + type.getName() + " " + field.getName() + ";"); } } }
控制台输出:
===============本类属性======================== private java.lang.String name; private int age; ===============实现的接口或者父类的属性======================== public static final java.lang.String name; public static final int age;
通过反射调用其他类的方法
package cfanshe; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class ReflectTestDemo{ public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } try { //调用Student类中的sayChina方法; Method method = demo.getMethod("sayChina"); method.invoke(demo.newInstance()); //调用Student类中的sayHello方法; method = demo.getMethod("sayHello",String.class,int.class); method.invoke(demo.newInstance(), "binguo",25); } catch (Exception e) { e.printStackTrace(); } } }
控制台输出:
hello ,china binguo 25
调用其他类中的get、set方法
package cfanshe; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class ReflectTestDemo { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } Object obj = null; try { obj = demo.newInstance(); } catch (Exception e) { e.printStackTrace(); } setter(obj, "Name", "起司", String.class); getter(obj, "Name"); } /** * @param obj * 操作的对象 * @param att * 操作的属性 */ public static void getter(Object obj, String att) { try { Method method = obj.getClass().getMethod("get" + att); System.out.println(method.invoke(obj)); } catch (Exception e) { e.printStackTrace(); } } /** * @param obj * 操作的对象 * @param att * 操作的属性 * @param value * 设置的值 * @param type * 参数的属性 */ public static void setter(Object obj, String att, Object value, Class<?> type) { try { Method method = obj.getClass().getMethod("set" + att, type); method.invoke(obj, value); } catch (Exception e) { e.printStackTrace(); } } }
输出:起司;
注意这里面obj.getClass().getMethod("set" + att, type);是拼的方法名,因此要注意大小写
通过反射操作属性:
package cfanshe; import java.lang.reflect.Field; public class ReflectTestDemo { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("cfanshe.Student"); } catch (Exception e) { e.printStackTrace(); } Object obj = null; try { obj = demo.newInstance(); Field field = demo.getDeclaredField("name"); //打开通道 field.setAccessible(true); field.set(obj, "起司"); System.out.println(field.get(obj)); } catch (Exception e) { e.printStackTrace(); } } }
控制台输出:起司
通过反射取得并修改数组的值:
package cfanshe; import java.lang.reflect.Array; public class ReflectTestDemo { public static void main(String[] args) { int[] temp = { 1, 2, 3, 4, 5 }; Class<?> demo = temp.getClass().getComponentType(); System.out.println("数组类型: " + demo.getName()); System.out.println("数组长度 " + Array.getLength(temp)); System.out.println("数组的第一个元素: " + Array.get(temp, 0)); Array.set(temp, 0, 100); System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0)); } }
打印:
数组类型: int 数组长度 5 数组的第一个元素: 1 修改之后数组第一个元素为: 100
很好的贴子推荐:
https://www.cnblogs.com/Eason-S/p/5851078.html
https://blog.csdn.net/sinat_38259539/article/details/71799078