反射
反射机制
初识反射
反射:指的是对象的反响处理。根据对象倒退类的组成
在默认情况下,先要导入一个包,而后才能产生类的实例化对象,处理流程根据包名.类名找到类
而这里的“反”就是对象来取得对象的来源信息,反射的核心类Class类(专门描述其他类的组成)
Objectlei中取得对象的class对象
1
public final native Class<?> getClass();
- Class描述接口与类的组成,Class对象由JVM在第一次加载类的产生,并且全局唯一
范例:
1
2
3
4
5
6public class mytest {
public static void main(String[] args) throws ClassNotFoundException{
Class<?> cls=Class.forName("java.util.Date");
System.out.println(cls.getName());
}
}
在反射的世界中,看重的不再时一个对象,而是对象身后的组成(类,构造,普通,成员等)
取得任意类Class对象的三种方法:
- 调用对象 .getClass()取得Class对象,由Object类提供
- 类名调用 .class取得Class对象
- Class.forName(类全名称)取得Class对象
在三中方法中只有第一种方法会产生类的实例化对象之外,其他两种均不会产生实例化对象。取得Class对象,可以通过反射实例化对象,在Class类中定义如下方法:
1
2public T newInstance()
throws InstantiationException,IllegalAccessException范例:反射实例化对象
1
2
3
4
5
6
7public class mytest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> cls=Class.forName("java.util.Date");
Object obj=cls.newInstance(); //实例化对象,等价于new java.util,Date()
System.out.println(obj);
}
}
反射与工厂模式
在传统的工厂模式中,每当我们增加一个接口的子类都需要去修改工厂类,为了解决该类问题,可以通过反射来处理,Class类可以使用newInstance()实例化对象,而Class.for通过Name()能够接收类名称。这样一来就避免了直接实例化(new)带来的问题,而是直接通过接收类名去实例化对象,避免了对工厂类的频繁修改。
范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48/**
* 反射与工厂模式
*/
package www.Dyson;
interface IFruit{
public void eat();
}
class Orange implements IFruit{
public void eat() {
System.out.println("eat an orange");
}
}
class Apple implements IFruit{
public void eat() {
System.out.println("eat an apple");
}
}
class fruitFactroy{
//使用static修饰,当主方法中调用该方法通过反射实例化一个对象时
//使用过静态方法调用的,所以getInstance方法必须也是静态方法,否则
//会报无法从静态上下文中引用非静态方法的错误
public static IFruit getInstance(String fruitName){
IFruit iFruit=null;
try {
//通过.forName取得class对象
Class<?> cls=Class.forName(fruitName);
try {
//通过反射取得实例化对象
iFruit = (IFruit) cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return iFruit;
}
}
public class ReflectAndFactory {
public static void main(String[] args)throws Exception{
IFruit iFruit=fruitFactroy.getInstance("www.Dyson.Apple");
iFruit.eat();
}
}在主方法中调用该方法通过反射实例化一个·对象,而主方法是一个静态方法,所以该方法也必须为静态方法。
反射与类操作
取得父类&父接口信息
取得类的包名称:
1
public Package getPackage();
取得父类的Class对象:
1
public native Class<? super T> getSuperclass();
取得实现的父接口:
1
public Class<?>[] getInterfaces();
通过反射可以取得类结构上的所有关键信息
以上所有父类:只能取得子类直接继承的父类
反射与构造方法 – Constructor(描述类构造方法信息)只能取得本类中的构造方法,与集成无关
取得类中指定参数构造方法
取得类中权限只有public的指定构造方法
1
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
取得类中任意权限的指定构造方法
1
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
取的类中所有构造方法 —— 重要 ——
取得类中所有权限为public的构造方法
1
public Constructor<?>[] getConstructors() throws SecurityException
取得类中所有权限构造方法
1
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
Class类的newInstance()实际调用的是类中的无参构造。若类中没有无参构造或者权限不是public,则无法使用Class类调用!!!
Constructor类的如下方法
1
public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
- 如果类中没有无参构造,则只能调用Constructor类提供的newInstance方法使用有参构造来实例化对象
范例:通过Constructor类实例化对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package Dyson;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Person_p{
private String name="Dyson";
private int age=18;
public Person_p(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class mytest {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> cls=Person_p.class;
Constructor<?> con=cls.getConstructor(String.class,int.class);
System.out.println(con.newInstance("Dyson",18));
}
}
反射调用普通方法(核心 – Method)—— 重要 ——
取得类中指定名称与参数的普通方法
1 | public Method getMethod(String name,Class<?>... parameterTypes) |
1 | public Method getDeclaredMethod(String name,Class<?>... parmeterTypes) |
取得类中所有普通方法
取得本类以及父类所有权限为public的普通方法(包含静态方法)
1
public Method[] getmethods() throws SecurityException
取得本类中所有方法(包含private方法)
1
public Method[] getDeclaredmethods() throws SecurityException
调用 – 通过invoke可以取得和设置属性信息,不再局限于某一个具体的对象,而是可以通过Object类型进行对所有类的方法调用。
1
2
3
4
5
6/**
*反射调用普通对象
*obj类的实例化对象
*args普通方法参数
*/
public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
反射调用类中属性(Field)
取得类中指定名称属性
1 | public Field getField(String name) 父类 |
1 | public Field getDeclaredField(String name) 本类 |
取得类中所有属性 – 同Meyhod一样
1 | public Field[] getFields throws SecurityException() 父类 |
1 | public Field[] getDeclaredFields throws SecurityException() 本类 |
设置与取得值 – 属性值为public
设置属性值
1
2
3
4
5/**
*obj类的实例化对象
*value所有设置的值
*/
public void set(Object obj, Object value)取得属性值
1
2
3
4/**
*obj类的实例化对象
*/
public Object get(Object obj)取得属性值
1
public Class<?> getType()
动态破坏封装(反射特性)可以处理private权限的属性 – 只是在一次JVM进程中破坏,且只能通过反射来调用
Constuctor,Method,Field类都继承AccessibleObject类,此类中只有一个破坏的方法
1
public void setAccessible(boolean flag) throws SecurityException
范例:通过反射操作private权限的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package Dyson;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
class Person_p{
private String name;
}
public class mytest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<?> cls=Class.forName("Dyson.Person_p");
//实例化对象
Object obj=cls.newInstance();
//取得要操纵的属性
Field field=cls.getDeclaredField("name");
//破坏封装
field.setAccessible(true);
//设置属性内容
field.set(obj,"Dyson");
//取得属性
System.out.println(field.get(obj));
}
}