网站首页 > 精选教程 正文
什么是反射
JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
一般情况下,我们使用类来创建对象都是一开始就知道具体的类型以及类的用途,直接通过类来创建对象
Order order = new Order(new BigDecimal(4.32));
order.getPrice();
而反射是一开始不知道我需要初始化的类是什么,到实际运行的时候才知道具体的类型,此时只能通过反射的API来创建对象
Class clazz = Class.forName("org.kxg.reflection.Order");
Method method = clazz.getMethod("getPrice");
Constructor constructor = clazz.getConstructor(BigDecimal.class);
Object object = constructor.newInstance(new BigDecimal(4.4));
method.invoke(object);
上面两种方式的效果是一样的,都是创建了Order对象,调用Order对象的getPrice()方法,只不过一个是普通调用、一个是反射调用
所以简单来说,反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法
为什么需要反射
Java在不同的时期可以分成两种编译类型:
- 静态编译:就是我们常用的方式,在编译时就确定的类型
- 动态编译:在编译时无法确认类型,到运行才确定类型
动态编译发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性
Java反射是Java被视为动态语言的一个关键性质。
这个机制允许程序在运行时通过反射取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Reflection可以在运行时加载、探知、使用编译期间完全未知的classes。
即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods
反射是解决什么问题?
反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。 在静态语言中,使用一个变量时,必须知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才能保证准确无误;换句话说,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了
一句话概括就是使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现,例如热加载,Tomcat的classloader等等都没法支持
反射常用API
1、反射获取Class对象
//方式一:通过Class.forName()获取Class
Class c1 = Class.forName("org.kxg.reflection.Order");
//方式二:使用.class方法
Class c2 = Order.class;
//方式三:通过getClass()方法
Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
2、通过反射创建类对象
//方式一:通过Class对象的newInstace()方法创建对象
Class c1 = Class.forName("org.kxg.reflection.Order");
Order o1 = (Order) c1.newInstance();
//方式二:通过Constructor对象的newInstance()方法创建对象
Class c2 = Order.class;
Constructor constructor = c2.getConstructor(Order.class);
Order o2 = (Order) constructor.newInstance();
3、获取类的属性
Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
//只能获取除私有以外的属性
Field[] fields = c3.getFields();
//获取所有属性
Field[] fields1 = c3.getFields();
4、获取类方法
Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
Method[] methods = c3.getMethods();
5、获取注解
Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
Annotation[] annotations = c3.getAnnotations();
反射实现动态代理
实现方式:利用Java的反射机制,在java.lang.reflect 包下提供了Proxy类和InvocationHandler 接口来实现动态代理
下面以增加日志的需求来演示一下JDK动态代理的用法
//抽象对象
public interface CustService {
public void editCust();
}
//真实对象
public class CustServiceImpl implements CustService {
public void editCust() {
System.out.println("edit cust ----");
}
}
//日志对象
public class LogService {
public void addLog(){
System.out.println("add log ----");
}
}
//动态代理对象
public class JDKProxyCustService implements InvocationHandler {
private Object target;
private LogService logService = new LogService();
public JDKProxyCustService(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("methodName:" + methodName );
logService.addLog();
Object o = method.invoke(target,args);
logService.addLog();
return o;
}
}
//测试
public class TestJDKProxy {
public static void main(String[] args){
CustService custService = new CustServiceImpl();
Class c = custService.getClass();
ClassLoader classLoader = c.getClassLoader();//目标对象的类加载器
Class[] interfaces = c.getInterfaces();//目标对象实现的所有接口
InvocationHandler h = new JDKProxyCustService(custService);//获取一个InvocationHandler,并将custService对象传入
/**
* 参数说明:
* 1.classLoader表示目标对象的类加载器
* 2.interfaces表示目标对象实现的所有接口
* 3.InvocationHandler接口的实现
*/
CustService proxy = (CustService) Proxy.newProxyInstance(classLoader,interfaces,h);
proxy.editCust();
}
}
运行结果:
methodName:editCust
add log ----
edit cust ----
add log ----
每个动态代理类(JDKProxyCustService)都必须实现InvocationHandler接口,当我们通过代理对象调用方法时,调用会被转到InvocationHandler接口的invoke方法。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
proxy:被代理的真实对象 method:调用真实对象的某个方法 args:调用真实对象某个方法所传的参数
实际上,真正有用的代码是:
Object o = method.invoke(target,args);
利用Java的反射机制,动态的去调用目标对象的方法。 再来看看Proxy类,我们在测试类中真正有用的代码是:
CustService proxy = (CustService) Proxy.newProxyInstance(classLoader,interfaces,h);
Proxy类的作用就是创建一个动态代理对象的类,newProxyInstance方法的作用是创建一个动态代理的对象 参数说明: classLoader:目标对象的类加载器 interfaces:目标对象所实现的所有接口 h:InvocationHandler接口的实现
还有这句:
InvocationHandler h = new JDKProxyCustService(custService);
传入需要代理的真实对象,实现调用的就是真实对象的方法
参考:
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
https://blog.csdn.net/grandgrandpa/article/details/84832343
猜你喜欢
- 2024-11-13 十年Java工程师写下的Java反射使用总结
- 2024-11-13 一起来了解Java中的反射 java反射的步骤原理
- 2024-11-13 Java基础:反射机制,你用得多吗 java反射机制有什么用
- 2024-11-13 每日一点涨薪小知识-JAVA反射 java反射的理解
- 2024-11-13 不是吧,还有人连Java最强大的技术之一:反射还没搞懂?赶紧码住
- 2024-11-13 Java反射的原理以及应用场景 java中反射的实际用法
- 2024-11-13 浅谈java中的反射(恭喜FPX) java里的反射是什么
- 2024-11-13 实操讲解Java的反射机制,你要是再看不懂,神仙都没救了
- 2024-11-13 两分钟学会Java反射 java 反射
- 2024-11-13 三石说:java基础 之 反射 java反射的基石
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)