反射对JAVA这种具有动态性(java有动态性但不是动态语言,js和python是动态语言)的语言也有着巨大的使用价值。一下为java反射机制的学习总结。
什么是反射
反射的“反”是相对于普通运行时对象的引用来说的。在正常使用一个类时,我们需要提前了解这个类有什么方法,有哪些属性。而利用反射我们在运行时才了解该类有什么方法和属性。
@Test
public void TestThree() throws Exception{
//正常调用
Person person1 = new Person();
System.out.println(person1);
//通过Class反射调用
Class c2 = Person.class;
Person person2 = (Person) c2.newInstance();
System.out.println(person2);
}
通过反射,我们可以在程序中访问已经装载在JVM中的java对象,实现访问,检测,修改java对象本身的功能。
反射的使用
通过反射获取类对象的三种方式
public void TestTwo() throws Exception{
//通过persion实例获取
Person preson1 = new Person();
Class c1 = preson1.getClass();
System.out.println(c1.getName());
//通过presion类直接获取,不会执行静态代码块
Class c2 = Person.class;
System.out.println(c2);
//通过Class的静态方法获取
String classname = "com.company.Person";
Class c3 = Class.forName(classname);
System.out.println(c3);
}
以上为常用的利用反射获取对象的三种方式,其中通过Person.class直接获取时不会执行静态代码块,以下代码将对此进行测试。
public class Person {
public String name;
public int age;
static {
int a = 0;
System.out.println(a);
}
在Person类中添加静态代码块
/----------------------------------------------/
@Test
public void TestTwo() throws Exception{
// //通过presion实例获取
// Person preson1 = new Person();
// Class c1 = preson1.getClass();
// System.out.println(c1.getName());
//通过presion类直接获取,不会执行静态代码块
Class c2 = Person.class;
System.out.println(c2+"c2");
//通过Class的静态方法获取
String classname = "com.company.Person";
Class c3 = Class.forName(classname);
System.out.println(c3+"c3");
}
在通过.class调用时并未输出0,没用执行静态代码块,通过.forName调用时执行了静态代码块,并且静态代码块只会执行一次。
在程序运行时JVM中只有一个运行时类对象,也就是说上面的C1,C2,C3都是相等的。
通过反射获取构造方法
通过反射主要有两种方式获取构造方法。具体代码如下
public void TestFour() throws Exception{
Class c1 = Person.class;
//通过Class的newInstance获取构造函数(只能获取无参构造函数)
Person person1 = (Person)c1.newInstance();
//通过Constructor的newInstance获取构造函数(可以获取有参构造并传值)
Constructor constructor = c1.getConstructor(String.class);
Person person2 = (Person)constructor.newInstance("王二狗");
}
其中通过Class直接获取时只能获得无参构造方法。使用Constructor获取构造方式时可以传入参数类型指定获取对应的构造方法。
通过反射获取属性
@Test
public void TestFive()throws Exception{
Class c = Person.class;
Person person = (Person) c.newInstance();
//获取属性名称.传入的参数为属性名称(不能获取私有属性)
Field field = c.getField("name");
//为属性设置值
field.set(person,"张三");
System.out.println(field.get(person));
}
通过以上方法只能获取非私有属性的值并赋值,要想获取私有属性的值需要用到
Field field1 =c.getDeclaredField("name");
获取方法
public void TestSix() throws Exception{
Class c = Person.class;
Person person = (Person) c.newInstance();
//获取方法,参数为方法名称(不能获取私有方法)
Method method = c.getMethod("show1");
//调用方法
method.invoke(person);
//获取含有参数的方法,参数为方法名称和参数类型
Method method1 = c.getMethod("show3", int.class);
//调用方法,参数为Object和传入的参数
method1.invoke(person,10);
}
调用有参和无参方法的方式如上代码所示,当调用私有方法时利用
Method method = c.getDeclaredMethod("show1");
以上为反射的简单介绍和基础使用演示,对于反射还有更高级的内省,动态代理等运用,将在以后文章中介绍。如上述有错误请在评论中指出。