苦行僧 Java 笔记之《浅谈Java反射》

2017-01-13 15:03:59来源:csdn作者:baidu_36779925人点击

第七城市
java反射1、什么是反射? JAVA 反射机制是在运行状态中,对与一个类或者对象,都能获取并操作它所有的属性和方法。
2、反射用来干什么? 判断任意一个对象所属的类;调用其构造方法构造类的实例;获取、操作任意一个类所具
有的成员变量和方法;在运行时调用任意一个对象的方法等。
3、怎么用呢?

首先我们先创建一个普通的 Demo 类。

package com.wenka.reflect;
public class Demo {
public Demo() {
}
}
3.1 获取 Class

三种方式获取 Class 对象:

Class<?> demo1 = null;
Class<?> demo2 = null;
Class<?> demo3 = null;
① 通过 Class 类的静态方法 forName(String className),参数为需要获取 Class 的类的全类名。
demo1 = Class.forName("com.wenka.reflect.Demo");

注意:这里 ClassNotFoundException异常需要处理,由于我们只是测试用,所以在这里选择上抛。 -② 从此类的实例中获取

demo2 = new Demo().getClass();

-② 从类名中获取

demo3 = Demo.class;

-输出结果:

demo1:class com.wenka.reflect.Demo
demo2:class com.wenka.reflect.Demo
demo3:class com.wenka.reflect.Demo3.2 获取到 Class 有什么用呢??

相信对于初学者也如当初的我一样,不知道接下来能干什么?这时,我们看一下 JavaAPI:java.lang.Class<T> 这个类。没错,我们可以通过它获取各种方法、各种属性等。


① 在此之前先创建一个 Person 类方便测试
package com.wenka.reflect;public class Person {//两个私有属性
private String name;
private Integer age;//两个私有属性的 getter/setter 方法
public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public Integer getAge() {
return age;
}public void setAge(Integer age) {
this.age = age;
}//重写 toString() 方法输出测试。
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}//写了四个构造方法:一个两参的,一个public一参的,一个private一参的,一个无参的。
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}public Person(String name) {
this(name, 20);
}@SuppressWarnings("unused")
private Person(Integer age) {
this("zhangsan", age);
}public Person() {}//两个私有方法:有参 work(int hours)、 无参 salary()
@SuppressWarnings("unused")
private void work(int hours) {
System.out.println(name + "工作了" + hours + "个小时");
}@SuppressWarnings("unused")
private double salary() {
return 5000;
}
}

② 获取构造方法

获取 ClassClass<?> demo = Class.forName("com.wenka.reflect.Person");通过 API 发现有两个获取所有构造参数的方法。 getConstructors() 和 getDeclaredConstructors()通过对比发现:getConstructors():不能获取到类的私有构造方法,而 getDeclaredConstructors() 则可以获取到所有的构造方法。
获取到指定的构造方法:

getConstructor(Class<?>… parameterTypes) 和 getConstructor(Class<?>… parameterTypes)参数列表为想要的获取的那个构造方法所对应的参数列表 楼主在此获取得到 public 参数列表为 String 的构造方法。通过调用 Constructor<T> 中的 newInstance(Object… initargs)方法创建实例。此方法的参数列表就是对应的构造方法的参数列表的实参。

Person person =(Person) demo.getConstructor(String.class).newInstance("wangwu");


在此就有了疑问,既然我们可以通过 getDeclaredConstructor(Class<?>… parameterTypes) 获取到 私有的方法,那我们是不是也能通过此种办法,使得我们可以利用私有构造方法来创建实例?

Constructor<?> constructor = demo.getDeclaredConstructor(Integer.class);

没错,我们通过此方法获取到了私有构造方法,但是我们直接通过此创建实例会有异常:

java.lang.IllegalAccessException: Class com.wenka.reflect.MainClass can not access a member of class com.wenka.reflect.Person with modifiers "private"

意思是说:这个构造方法是 “private”的,我们不能访问。但是,不要灰心,自习看了一下 Constructor<T> 类,Field、Method 和 Constructor 对象的基类为 AccessibleObject 类,这个类是干什么呢? 它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。哦,原来这个类可以取消 Java 语言的访问控制检查的能力啊。这就好办了。我们讲刚得到的私有构造方法 调用 setAccessible(boolean flag) 方法。将此方法设置为 false,使其取消反射的对象实施 Java 语言访问检查。

constructor.setAccessible(true);

到此:

Object newInstance = constructor.newInstance(20);
System.out.println(newInstance);

输出:

Person [name=zhangsan, age=20]

如果只能通过无参的构造方法来创建实例就比较简单了:当然前提是一定要有无参构造。

Person person = (Person) Demo.newInstance();
person.setAge(20);
person.setName("A");
System.out.println(person);

③ 获取字段

获取所有字段,与获取构造方法类似。调用 getDeclaredFields() 或者 getFields()
获取指定字段并赋值。getDeclaredField(String name) 参数:字段名。 Field field = demo.getDeclaredField("age"); field.setAccessible(true); 为字段设置新值: Person person = new Person("AAAAAA");
//field.set(obj, value);给 obj 对象的此属性设置 value 新值
field.set(person, 100);
System.out.println(person)

④ 获取方法

获取所有方法:getMethods()和 getDeclaredMethods();
获取指定的方法:(在此依旧是获取 private 的方法,其它方法类似。) 当初我们创建的实体类中有 两个私有方法:有参 work(int hours)、 无参 salary()

getDeclaredMethod(String name, Class<?>… parameterTypes):参数列表为:1.方法名,2. 对应方法的参数列表的类型,0个 或者 多个。 Method work = demo.getDeclaredMethod("work", int.class); System.out.println(work); work.setAccessible(true); Person person = new Person("AAAA"); // invoke(Object obj, Object... args)work.invoke(person, 10); 输出结果:

private void com.wenka.reflect.Person.work(int)
AAAA工作了10个小时

Method 类中的 invoke(Object obj, Object… args) 方法,对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 参数:1.指定对象 2.对应参数列表的实参。

倘若方法有返回值,则直接返回:

Method salary = demo.getDeclaredMethod("salary"); salary.setAccessible(true); Object invoke = salary.invoke(person); System.out.println("得到了工资:" + invoke);

结果为:

得到了工资:5000.0

致此:反射的简单用法都已经写完了,可以发现,反射很强大的,我们甚至可以通过反射使 单例 不再单例,通过反射获取注释,接口等关于此类的所有信息,并从底层操作。未来学习的框架都运用了反射的原理来实现。


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台