1 什么是反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取对象信息以及动态调用对象方法的功能称为java语言的反射机制。
说白了,就是从内存中的字节码文件中获取相关信息。
2 反射API
涉及的类:
Class类—描述类的信息,java.lang包下
Field类—描述类的属性的信息
Method类—描述类的方法的信息
Constructor类—描述类的构造方法的信息
2.1 Class
JVM通过.class文件加载类,.class文件是对类的信息的描述,每当JVM加载一个类,就产生对应的Class对象
它的构造函数是私有的,因此我们无法通过new创建Class类型的对象
Java.lang.Class类的常用方法
方法 | |
---|---|
public String getName() | 获得该类的名字 |
public static Class forName(String className) | 加载类 |
public Object newInstance() | 创建某类的一个新实例 |
public Field getDeclaredField(String name) | 返回一个 Field 对象 |
public Field getField(String name) | 返回一个 Field 对象(public) |
public Field[] getDeclaredFields() | 返回 Field类型的一个数组,类的所有属性 |
public Field[] getFields() | 获得Field类型的数组,类的所有公有属性 |
public Method[] getDeclaredMethods() | 获得Method类型的数组,类的所有方法 |
public Method[] getMethods() | 获得Method类型的数组,类的所有公有方法 |
public Method getMethod(String name,Class ... paramTypes ) | 获得某类中的某个方法 |
Constructor<?>[] getDeclaredConstructors() | 返回此Class对象表示的类声明的所有构造方法 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回此Class对象所表示的类或接口的指定构造方法 |
2.1.1 获取Class对象
java
//方法1:对象.getClass()
Student stu = new Student();
Class clazz = stu.getClass();
//方法2:类.class
clazz = Student.class;
clazz = String.class;
//方法3:Class.forName()
clazz = Class.forName("com.glls.reflect.Student");
clazz = Class.forName("java.lang.String");
clazz = Class.forName("java.util.Date");
2.1.2 获取Constructor
java
Class cla = Class.forName("com.glls.reflect.Student");
//得到类中的所有public的构造函数
Constructor[] cons = cla.getConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
System.out.println("--------------------------");
//得到类中所有的构造函数(包括私有的)
cons = cla.getDeclaredConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
//得到默认的构造方法(无参的构造方法)
Constructor c = cla.getConstructor(null);
// 得到带参的构造方法
c = cla.getConstructor(String.class, int.class);
//可以得到私有的(非公有的)构造方法
c = cla.getDeclaredConstructor(int.class);
//设置可以访问
c.setAccessible(true);
2.1.2 通过反射创建对象
java
Class clazz = Class.forName("com.glls.reflect.Student");
Object obj = clazz.newInstance();
java
// 获取带参的构造方法
Constructor con = cla.getConstructor(new Class[ ]{String.class, int.class});
Object obj = con.newInstance(new Object[ ]{"fy", 18});
Object obj2 = con.newInstance("zhangsan", 18);
2.2 Field
Java.lang.reflect.Field类的常用方法:
方法 | |
---|---|
public String getName() | 获得属性名 |
public Class getType() | 获得属性的类型 |
Object get(Object obj) | 返回指定对象上此Field对象字段的值 |
void set(Object obj, Object value) | 将指定对象上此Field对象表示的字段设置为指定的值 |
void setAccessible(boolean flag) | 设置指定对象上此Field对象表示的字段的可见性 |
2.2.1 获取Field对象
java
Class cla = Class.forName("com.glls.reflect.Student");
//得到public的成员变量
Field[] fields = cla.getFields();
for (Field f : fields) {
System.out.println(f);
}
System.out.println("---------------");
//得到所有的成员变量
fields = cla.getDeclaredFields();
for (Field f : fields) {
System.out.println(f);
}
//获得指定名称的成员变量的Field对象
Field f = cla.getField("age");
// 获得私有的变量
f = cla.getDeclaredField("weight");
f.setAccessible(true);
2.2.2 属性的调用
java
Class clazz = Class.forName("com.glls.reflect.Student");
Object obj = clazz.newInstance();
Field field = cla.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "lisi");
field.get(obj); // stu.getName();
2.3 Method
Java.lang.reflect.Method类的常用方法:
方法 | |
---|---|
public String getName() | 获得方法名 |
public Class[] getParameterTypes() | 获得一个存储方法的参数类型的数组 |
public Class getReturnType() | 获得方法的返回值类型 |
public Object invoke(Object obj, Object... args) | 调用方法,第一个参数表示某个对象,后面的参数表示方法的参数值 |
2.3.1 获取Method对象
java
Class cls = Class.forName("com.glls.reflect.Student");
//获取类中所有public的方法,包括父类中的方法
Method[] methods = cls.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("-----------------");
//获得本类中的所有方法
methods = cls.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m);
}
//根据方法名和参数类型,获取Method对象
Method m = cls.getMethod("drink", null);
m = cls.getMethod("eat", int.class);
//获得任意访问权限的方法(包括私有的)
m = cls.getDeclaredMethod("sleep", null);
m.setAccessible(true);
2.3.2 调用方法
java
Obejct stu = cla.newInstance();
Method method1 = cla.getDeclaredMethod("getName", null);
// 调用方法,第一个参数表示方法所在的对象
// 调用无参的方法
method1.invoke(stu, null);
Method method2 = cla.getDeclaredMethod("setName", new Class[]{String.class});
// 调用带参的方法
method2.invoke(stu, new Object[]{"setName is running"});
附录
简单工厂模式的优化
java
public class PayFactory {
private PayFactory(){}
public static IPay getInstance(String className){
try{
return (IPay) Class.forName(className).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}