前言
在Java语言中,Java的反射机制是它的一个重要特性。
Java的反射机制是指在运行状态中,对于任意一个类都能够调用方法知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意方法和属性。这种在运行状态中获取类或对象的动态信息的功能被称为反射。
反射的功能
- 获取类的各种信息:反射可以获取一个类中的各种信息,包括类名、父类、实现的接口、类中定义的属性、方法、构造方法等。
- 创建对象:通过Class对象的newInstance()方法动态创建对象,而不需要在编写代码时事先知道创建的具体对象类型。
- 调用方法:在运行状态时动态调用一个对象的方法,包括公有、私有、静态方法等。
- 生成动态代理:在运行时创建代理类实例,由代理类来代理另外一个类的方法调用。
反射机制获取对象信息
1、获取类型信息
在编译期间确定对象类型的代码如下
String str = new String();
在运行期间确定对象类型,反射机制中有三种方法
-
通过Class类的静态方法forName得到
String str = Class.forName("String").newInstance();
-
通过实例化访问
String str = "";
Class stringCls = str.getClass();
-
通过类名访问
Class stringCls1 = String.class;
注:以上这三种方法在一个main中输出的哈希值相同,因为哈希值只会重复输出首次获取。
2、获取接口信息
//实现的接口
Class[] interfacecls = cls.getInterfaces();
System.out.println("当前类实现的接口:");
for (Class iclass : interfacecls) {
System.out.println(iclass);
}
3、获取构造方法
//此处Example为一个自己创建的类
Class cls = Example.class;
//只能访问公有的构造方法
System.out.println("所有的构造方法");
//Constructor[] constructors = cls.getConstructors();//不包括私有
Constructor[] constructors = cls.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取一个私有的构造方法
Constructor privateConstruct = cls.getDeclaredConstructor(String.class);
//调用私有的构造方法
privateConstruct.setAccessible(true);
Example ex = (Example) privateConstruct.newInstance("just");
System.out.println(ex);
System.out.println("---------");
//调用无参构造方法(根据数据类型、数据个数进行调用)
Constructor construct1 = cls.getConstructor();
Constructor construct2 = cls.getConstructor(int.class);
Constructor construct3 = cls.getConstructor(int.class,double.class);
4、Instanceof运算符和isAssignableFrom运算符
Instanceof运算符:判断引用和类型之间的关系
isAssignableFrom运算符:判断两个类型之间的关系
实现代码如下:
//Instanceof运算符:判断引用和类型之间的关系
Object obj = Double.valueOf(324);
System.out.println("是否为Double类型?"+(obj instanceof Double));
System.out.println("是否为Integer类型?"+(obj instanceof Integer));
System.out.println("是否为Character类型?"+(obj instanceof Character));
System.out.println("是否为RandomAccess接口?"+(obj instanceof RandomAccess));
System.out.println("是否为Comparable接口?"+(obj instanceof Comparable));
//isAssignableFrom运算符:判断两个类型之间的关系
System.out.println("Intager <= Intager ?"+Integer.class.isAssignableFrom(Integer.class));
System.out.println("Intager <= Double ?"+Integer.class.isAssignableFrom(Double.class));
System.out.println("Intager <= RandomAccess ?"+Integer.class.isAssignableFrom(RandomAccess.class));
System.out.println("Serializable <= Intager ?"+Serializable.class.isAssignableFrom(Integer.class));
System.out.println("Intager <= Number ?"+Integer.class.isAssignableFrom(Number.class));
System.out.println("Number <= Intager ?"+Number.class.isAssignableFrom(Integer.class));
输出结果如下:
5、访问成员变量
//Book为自己创建的类
Class c = Book.class;
//Field[] fields = c.getFields();//父类子类的公用成员变量都能拿到
Field[] fields = c.getDeclaredFields();//获取本类的所有成员变量
for (Field field : fields) {
System.out.println("成员访问修饰符int:"+field.getModifiers());
System.out.println("成员访问修饰符:"+Modifier.toString(field.getModifiers()));
System.out.println("成员变量类型:"+field.getType());
System.out.println("成员变量名称:"+field.getName());
System.out.println("-------");
}
6、添加成员变量的值
//运行期
//使用反射的方式完成成员变量变值
Class cls = Book.class;//获取class类型的对象
Object obj = cls.newInstance();//通过反射创建Book类的对象
//按照字段名称,获取指定成员变量
Field field = cls.getDeclaredField("BookName");
//参数1:目标Book对象
//参数2:存入变量中的值
field.set(obj, "哈哈哈");
Field field2 = cls.getDeclaredField("stock");
field2.set(obj, 90);
Field field3 = cls.getDeclaredField("sale");
field3.setAccessible(true);//访问私有成员变量
field3.set(obj, 0.8);
System.out.println(obj);
7、获取类中所有方法
Class cls = Book.class;
//获取所有Public方法(包括父类)
//Method[] methods = cls.getMethods();
//获取所有定义的方法
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
System.out.println("方法的访问修饰符"+Modifier.toString(method.getModifiers()));
System.out.println("方法的返回值类型"+method.getReturnType());
System.out.println("方法的名称"+method.getName());
//获取所有的参数类型
//Class[] paramTypes = method.getParameterTypes();
//获取所有参数对象
Parameter[] params = method.getParameters();
for (Parameter p : params) {
System.out.println(p.getName());
System.out.println(p.getType());
System.out.println("--------------");
}
System.out.println();
}
-
获取方法对象
//反射获取class对象
Class cls = Base.class;
Object obj = cls.newInstance();
//按照方法名称和参数类型获取method方法对象
//create()
//Method method = cls.getMethod("create",int.class);
Method method = cls.getMethod("create", int.class);
//Method对象的invoke()作用
//以反射的方式执行create()方法
int r = (int) method.invoke(obj, 1000);
System.out.println(r);
//Base类
class Base{
public int create() {
return create(100);
}
public int create(int x) {
return (int) (Math.random()*x);
}
}
注:如果是调用一个类中的方法其中它的子类也覆写了这个方法,父类.class获取的Method,作用于Student实例时,调用的方法是子类的方法。实现代码如下:
//main
Method method = PersonS.class.getMethod("hello");
method.invoke(new Student());//目标对象调用方法归属
//类
class PersonS{
public void hello() {
System.out.println("hello");
}
}
class Student extends PersonS{
public void hello() {
System.out.println("你好");
}
}
//输出为>>你好
Class类中的主要方法有:
- getName():获取类的全限定名
- getSimpleName():获取类的简单类名
- getFields():获取类中的所有public属性
- getDeclaredFields():获取类声明中的所有属性,包括private属性、protect属性
- getMethods():获取类中所有public方法,包括从父类中继承来的方法
- getDeclaredMethods():获取类中声明的所有方法,包括private方法
- getConstructors():获取类中的所有public构造方法
- getDeclaredConstructors():获取类中声明的所有构造方法,包括private方法
- newInstance():通过Class对象动态创建对象
- isAssignableFrom(Class<?> cls):判断当前class对象是否可以从指定的Class对象进行赋值操作
- getInterfaces():获取当前类实现的接口
- getSuperclass():获取当前类的父类
除此之外还有很多动态获取信息操作以及判断方法,上文只是列出来一部分内容。
最重要的静态代理:
代理模式有两种:静态代理、动态代理。是根据字节码的创建时机来分类的。
静态是指在程序运行之前我们就已经知道代理类和真实角色的关系
动态是指在运行期间由JVM根据反射等动态机制的生成,在运行之前不知道代理类和真实角色的关系。
代理角色有三种:
- Subject(抽象主题角色):定义代理类和真实主题的公告对外方法,通常类型是接口
- RealSubject(真实主题校色):真正实现业务逻辑的类
- proxy(代理主题角色):用来代理和封装真实主题
静态代理案例实现:
public class client {
public static void main(String[] args) {
subject subject = new subjectproxy();
subject.request();
UserService service = new UserServiceProxy();
service.select();
service.update();
}
}
public class Realsubject implements subject{
public void request() {
System.out.println("逻辑1");
System.out.println("逻辑2");
System.out.println("逻辑3");
}
}
public interface subject {
void request();
}
public class subjectproxy implements subject{
private subject target;
public subjectproxy() {
target = new Realsubject();
}
@Override
public void request() {
System.out.println("begin-----------");
target.request();
System.out.println("end-----------");
}
}
静态代理案例详细实现2:
public interface UserService {
void select();
void update();
}
public class UserServiceImpl implements UserService {
@Override
public void select() {
System.out.println("select * ..................");
System.out.println("数据库中完成用户信息的查询执行!");
}
@Override
public void update() {
System.out.println("update ...................");
System.out.println("数据库中用户状态的更新执行!");
}
}
public class UserServiceProxy implements UserService{
private UserService target;
public UserServiceProxy() {
target = new UserServiceImpl();
}
@Override
public void select() {
begin();
target.select();
end();
}
@Override
public void update() {
begin();
target.update();
end();
}
private void begin() {
System.out.println("开始");
}
private void end() {
System.out.println("结束");
}
}
public class client {
public static void main(String[] args) {
UserService service = new UserServiceProxy();
service.select();
service.update();
}
}
动态代理案例实现:
public interface UserService {
void select();
void update();
}
public class UserServiceImpl implements UserService {
@Override
public void select() {
System.out.println("select * ..................");
System.out.println("数据库中完成用户信息的查询执行!");
}
@Override
public void update() {
System.out.println("update ...................");
System.out.println("数据库中用户状态的更新执行!");
}
}
//InvocationHandler接口实现类:代理类中扩展逻辑抽取封装
public class LogInvocationHandlerImpl implements InvocationHandler {
private Object target;
public LogInvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("方法%s开始执行\n",method.getName());
//执行目标对象的目标方法
Object ReturnValue =method.invoke(target, args);
System.out.printf("方法%s结束执行\n",method.getName());
return ReturnValue;
}
}
public class client {
public static void main(String[] args) {
LogInvocationHandlerImpl handler1 = new LogInvocationHandlerImpl(new UserServiceImpl());
UserService proxy1 = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[] {UserService.class},
handler1);
proxy1.select();
proxy1.update();
}
}
以上为部分方法实现案例
静态代理的优缺点:
-
优点:
- 可以在不修改目标对象的情况下增强目标对象的功能,实现了业务的分离,降低了系统的耦合度。
- 可以让代理对象在不影响目标对象的前提下对目标对象进行扩展。
- 可以对目标对象进行访问控制,增加系统的安全性。
-
缺点
- 每一个代理类只能为一个接口服务,增加了系统中类的数量,复杂度增加。
- 代理类和目标对象实现了相同的接口,当接口发生改变时,代理类和目标对象都需要同时进行修改,增加了系统的维护成本。
- 如果目标对象的方法很多,那么代理类也需要实现相同数量的方法,代码量相当大,实现起来比较麻烦。
动态代理的优缺点:
-
优点:
- 动态代理可以实现接口中所有方法的代理,不需要像静态代理一样手动为每个方法创建代理类。
- 动态代理可以在不修改源码的情况下,对目标对象进行增强,非常灵活。
- 动态代理可以通过使用 InvocationHandler 接口,在代理对象方法执行前后添加额外的逻辑。
-
缺点:
- 动态代理代理的接口必须是已知的,如果被代理的对象实现的接口不确定,则无法使用动态代理。
- 动态代理在运行期间生成代理类的过程比较消耗时间,如果实例化频繁,可能会影响系统性能。
- 动态代理只能代理接口,无法代理实现类的方法。