Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射相关的主要API:
package reflection;
public class TestClass {
public static void main(String[] args) {
Person p = new Person();
Class cla = p.getClass();
// Class extends Person> cla = p.getClass();
}
}
反射可以得到的信息包括:某个类的构造器、属性、方法、实现的接口。 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
方法 | 意义 |
---|---|
static Class forName(String name) | 根据类的全名(包名+类名)获取Class对象 |
Object newInstance() | 创建目标类的对象 |
getName() | 获取类的全名(包名+类名) |
Class getSuperclass() | 获取所有父类的Class对象 |
Class[ ] getInterfaces() | 获取所有实现的接口 |
ClassLoader getClassLoader() | 获取类的类加载器 |
Constructor[ ] getConstructors() | 获取类的所有构造器 |
Field[ ] getDeclaredFields() | 获取类的所有属性 |
Method getMethod(String name, Class… paramTypes) | 获取类的指定方法 |
一般常用forName()获取Class对象。
package reflection;
public class TestClass {
public static void main(String[] args) {
Person p = new Person();
//第一种:已知具体的类
Class c1 = Person.class;
//第二种:已知类的实例
Class c2 = p.getClass();
//第三种:已知类的全名(包名+类名)
try {
Class c3 = Class.forName("reflection.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意:
1.调用私有构造器、属性、方法后,要用 setAccessible(true); 解除private限制。
2.缺省、私有、受保护修饰的都要使用Declared。
Constructor类中:
package reflection;
public class Person {
String name;
int age;
public Person() {}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
package reflection;
public interface Move {
void move();
}
package reflection;
public interface Work {
void work();
}
package reflection;
public class Student extends Person implements Move, Work{
String school;
public Student() {}
@SuppressWarnings("unused")
private Student(String name, String school) {
super(name);
this.school = school;
}
public Student(String name, int age, String school) {
super(name, age);
this.school = school;
}
@Override
public void work() {
System.out.println("Study");
}
@Override
public void move() {
System.out.println("By bus");
}
@SuppressWarnings("unused")
private void printInfo(int i, int s) {
System.out.println(i + s);
}
public void showInfo(String str, int i) {
System.out.println(str + i);
}
public String returnInfo(String str, int i, Student stu) {
return str + i + stu.name;
}
}
package reflection;
import java.lang.reflect.Constructor;
public class TestClass {
public static void main(String[] args) {
try {
Class cla = Class.forName("reflection.Student");//获取Class对象
Class superCla = cla.getSuperclass();//获取全部的父类Class对象
System.out.println("父类:" + superCla.getName());//父类:reflection.Person
Class[] impleInter = cla.getInterfaces();
for(Class c : impleInter) {
System.out.println("实现的接口:" + c.getName());//实现的接口:reflection.Move
} //实现的接口:reflection.Work
Constructor[] con1 = cla.getConstructors();//获取public构造器
for(Constructor c : con1) {
System.out.println("构造器名称:" + c.getName() + "\t修饰符:" + c.getModifiers());
}//构造器名称:reflection.Student 修饰符:1
Constructor[] con2 = cla.getDeclaredConstructors();//获取所有构造器
for(Constructor c : con2) {
System.out.println("构造器名称:" + c.getName() + "\t修饰符:" + c.getModifiers());
//构造器名称:reflection.Student 修饰符:1 //构造器名称:reflection.Student 修饰符:2
Class[] clazz = c.getParameterTypes();//获取构造器参数类型
for(Class c1 : clazz) {
System.out.println("参数类型:" + c1.getName());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.使用反射机制创建对象
package reflection;
import java.lang.reflect.Constructor;
/**
* 使用反射机制创建对象
* 无参构造器
* @author MCC
*
*/
public class TestClass {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("reflection.Student");
Constructor<?> con = clazz.getConstructor();//调用无参构造器
Object obj = con.newInstance();//无参构造器新建对象 ,不能传入参数
Student stu = (Student)obj;
stu.name = "XiaoMing";
stu.age = 21;
stu.school = "阳光中学";
System.out.println(stu.name + " " + stu.age + " " + stu.school);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package reflection;
import java.lang.reflect.Constructor;
/**
* 使用反射机制创建对象
* 有参构造器
* @author MCC
*
*/
public class TestClass {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("reflection.Student");
Constructor<?> con = clazz.getConstructor(String.class, int.class, String.class);//调用三个参数构造器
Object obj = con.newInstance("XiaoMing", 21, "阳光中学");//使用上述构造器新建对象并赋值,若不赋值则初始化为默认值
Student stu = (Student)obj;
System.out.println(stu.name + " " + stu.age + " " + stu.school);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package reflection;
import java.lang.reflect.Constructor;
/**
* 使用反射机制创建对象
* 私有构造器
* @author MCC
*
*/
public class TestClass {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("reflection.Student");
Constructor<?> con = clazz.getDeclaredConstructor(String.class, String.class);//调用两个参数的私有构造器
con.setAccessible(true);//解除private限制
Object obj = con.newInstance("XiaoMing", "阳光中学");
Student stu = (Student)obj;
System.out.println(stu.name + " " + stu.age + " " + stu.school);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Field类中:
Method类中:
package reflection;
import java.lang.reflect.*;
public class TestClass {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("reflection.Student");
//获取全部属性
// Field[] fd = clazz.getFields();
Field[] fd = clazz.getDeclaredFields();
for(Field f : fd) {
System.out.println("名称:" + f.getName() + "修饰符:" + f.getModifiers() + "类型:" + f.getType());
}
//获取全部方法
Method[] me = clazz.getMethods();
for(Method m : me) {
System.out.println("名称:" + m.getName() + "修饰符:" + m.getModifiers() + "返回值类型:" + m.getReturnType());
Class<?>[] ms = m.getParameterTypes();
// if(ms != null && ms.length > 0) {//不输出空参数
for(Class<?> mc : ms) {
System.out.println("参数类型:" + mc.getName());
}
// }
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package reflection;
import java.lang.reflect.*;
try {
Class<?> clazz = Class.forName("reflection.Student");
// System.out.println(clazz.getPackageName());
Package pac = clazz.getPackage();
System.out.println(pac.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通过反射,调用类中的方法,通过Method类完成。步骤:
注意:
Object invoke(Object obj, Object … args)
代码
package reflection;
import java.lang.reflect.*;
public class AppointMethod {
public static void main(String[] args) {
try {
//调用指定的普通方法
Class<?> clazz = Class.forName("reflection.Student");
Constructor<?> con = clazz.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("小明", 21, "阳光中学");//有参构造器实例化对象
//获取指定方法
Method m = clazz.getMethod("showInfo", String.class, int.class);
m.invoke(obj, "lalala", 123);//lalala123
//调用指定的私有方法
Constructor<?> con1 = clazz.getConstructor();
Object obj1 = con1.newInstance();//无参构造器实例化对象
//获取指定方法
Method m1 = clazz.getDeclaredMethod("printInfo", int.class, int.class);
//私有方法使用前一定要设置可访问
m1.setAccessible(true);
m1.invoke(obj1, 2, 1);//3
//调用无参方法
Method m2 = clazz.getMethod("move");//无参时,第2个参数不写
m2.invoke(obj);//无参,因此不用初始化,参数2不写 //By bus
//调用重载方法
//重载方法参数名相同,但参数列表不同,只需将参数列表改动为想要调用的方法即可
//调用有返回值方法
Method m3 = clazz.getMethod("returnInfo", String.class, int.class, Student.class);
// String str = (String) m3.invoke(obj, "xyz", 2, (Student)obj);
String str = (String) m3.invoke(obj, "xyz", 2, obj);
System.out.println(str);//xyz2小明
} catch (Exception e) {
e.printStackTrace();
}
}
}
完整代码
package reflection;
import java.lang.reflect.*;
/**
* 反射机制调用指定方法、属性
* @author MCC
*先获取所有方法,再调用其中的一个指定方法,若已知指定方法,可以直接调用
*/
public class AppointMethod {
public static void main(String[] args) {
try {
System.out.println("=============方法=============");
Class<?> clazz = Class.forName("reflection.Student");
//获取所有方法
Method[] me = clazz.getDeclaredMethods();
for(Method m : me) {
System.out.println("方法名:" + m.getName() + "\t修饰符:" + m.getModifiers());
Class<?>[] cla = m.getParameterTypes();
for(Class<?> c : cla) {
System.out.println("参数类型" + c.getName());
}
}
System.out.println("=============构造器=============");
/**
* 运行结果:
* 方法名:move 修饰符:1
* 方法名:work 修饰符:1
* 方法名:printInfo 修饰符:2
* 参数类型int
* 参数类型reflection.Student
* 方法名:showInfo 修饰符:1
* 参数类型java.lang.String
* 参数类型int
*/
//获取所有构造器,目的:挑选合适的构造器实例化对象
Constructor<?>[] co = clazz.getDeclaredConstructors();
for(Constructor<?> c : co) {
System.out.println("构造器名:" + c.getName() + "\t修饰符:" + c.getModifiers());
Class<?>[] cla = c.getParameterTypes();
for(Class<?> ca : cla) {
System.out.println("参数类型:" + ca.getName());
}
}
/**
* 运行结果:
* 构造器名:reflection.Student 修饰符:1
* 参数类型:java.lang.String
* 参数类型:int
* 参数类型:java.lang.String
* 构造器名:reflection.Student 修饰符:2
* 参数类型:java.lang.String
* 参数类型:java.lang.String
* 构造器名:reflection.Student 修饰符:1
*/
//调用指定构造器实例化对象
// Object obj = clazz.getConstructor(String.class, int.class, String.class).newInstance("小明", 21, "阳光中学");
// Student stu = (Student)obj;
//调用指定方法
//接下来可以使用stu进行操作,或者进行如下操作
Constructor<?> con = clazz.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("小明", 21, "阳光中学");//有参构造器实例化对象
//获取指定方法
Method m = clazz.getMethod("showInfo", String.class, int.class);
m.invoke(obj, "lalala", 123);
//调用指定的私有方法
Constructor<?> con1 = clazz.getConstructor();
Object obj1 = con1.newInstance();//无参构造器实例化对象
//获取指定方法
Method m1 = clazz.getDeclaredMethod("printInfo", int.class, int.class);
//私有方法使用前一定要设置可访问
m1.setAccessible(true);
m1.invoke(obj1, 2, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的 set() 和 get() 方法就可以完成设置和取得属性内容的操作。
在Field中:
注:在类中属性都设置为private的前提下,在使用 set() 和 get() 方法时,首先要使用Field类中的 setAccessible(true) 方法将需要操作的属性设置为可以被外部访问。public void setAccessible(true) 访问私有属性时,让这个属性可见。
package reflection;
import java.lang.reflect.*;
public class AppointField {
public static void main(String[] args) {
try {
//反射机制创建一个对象
Class<?> clazz = Class.forName("reflection.Student");
Object obj = clazz.getConstructor().newInstance();
// Student stu = (Student)obj;
//访问指定属性
Field f = clazz.getDeclaredField("school");
//如果是私有属性,要设置权限
// f.setAccessible(true);
f.set(obj, "阳光中学");
String str = (String)f.get(obj);
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
需求:一个Java项目包括100个类,每个类有10个方法,一共有1000个方法,现在要在每个方法执行的开始和结束增加一个输出语句,即,在方法执行前输出:开始执行,在方法执行结束后输出:执行完毕。我们要手动更改这1000个方法吗?因为每个方法要增加的内容相同,有没有一个统一的处理办法呢?
动态代理步骤:
注意:如果一个类想要通过 Proxy.newProxyInstance()的方法被代理,那么该类一定要实现了某些接口,没有实现接口的类,不能被动态代理。
package reflection.proxy;
/**
* 接口
* @author MCC
*
*/
public interface Inter {
void showInfo();
double count();
}
package reflection.proxy;
/**
* 实现类
* @author MCC
*
*/
public class ImpInter implements Inter{
double fnum;
double lnum;
public ImpInter() {}
public ImpInter(double fnum, double lnum) {
this.fnum = fnum;
this.lnum = lnum;
}
@Override
public void showInfo() {
System.out.println("fnum:" + this.fnum + "\tlnum:" + this.lnum);
}
@Override
public double count() {
double res = this.fnum + this.lnum;
return res;
}
}
package reflection.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类:代理的实际是接口
* @author MCC
*
*/
public class DynamicProxy implements InvocationHandler{
Object obj;//被代理对象
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " 开始执行!");
Object res = method.invoke(this.obj, args);
System.out.println(method.getName() + " 执行完毕!");
return res;
}
}
package reflection.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// Inter test = new ImpInter();
// InvocationHandler handler = new DynamicProxy(new ImpInter());
InvocationHandler handler = new DynamicProxy(new ImpInter(1.21, 3.62));
// Inter it = (Inter)Proxy.newProxyInstance(handler.getClass().getClassLoader(), new ImpInter().getClass().getInterfaces(), handler);
Inter it = (Inter)Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new ImpInter().getClass().getInterfaces(), handler);
it.showInfo();
it.count();
}
}