Java编程思想——第14章 类型信息(二)反射
六、反射:运行时的类信息
我们已经知道了,在编译时,编译器必须知道所有要通过RTTI来处理的类。而反射提供了一种机制——用来检查可用的方法,并返回方法名。区别就在于RTTI是处理已知类的,而反射用于处理未知类。Class类与java.lang.reflect类库一起对反射概念进行支持,该类库包含Field、Method以及Constructor(每个类都实现了Member接口)。这些类型是由JVM运行时创建的,用来表示未知类种对应的成员。使用Constructor(构造函数)创建新的对象,用get(),set()方法读取和修改与Field对象(字段)关联的字段,用invoke()方法调用与Method对象(方法)关联的方法。这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。
其实,当反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,在做其他事情之前必须先加载这个类的Class对象。因此,那个类的.class文件对于JVM来说必须时可获取的(在本地或网络上)所以反射与RTTI的区别只在于:对于RTTI来说,编译器在编译时打开和检查.class文件,而对于反射来说,.class文件在编译时是不可获得的,所以是运行时打开和检查.class文件。反射在需要创建更动态的代码时很有用。
七、动态代理
代理是基本的设计模式:为其他对象提供一种代理,以便控制对象,而在对象前或后加上自己想加的东西。
interface Interface {
void doSomething();
void doSomeOtherThing(String args);
}
class RealObject implements Interface {
@Override
public void doSomething() {
System.out.println("doSomething");
}
@Override
public void doSomeOtherThing(String args) {
System.out.println("doSomeOtherThing" + args);
}
}
class SimpleProxy implements Interface {
private Interface proxyId;
public SimpleProxy(Interface proxyId) {
this.proxyId = proxyId;
}
@Override
public void doSomething() {
//将原有的doSomething 方法添加上了一个输出 这就是代理之后新增的东西
//就好比某公司代理游戏后加的内购
System.out.println("SimpleProxy doSomething");
proxyId.doSomething();
}
@Override
public void doSomeOtherThing(String args) {
proxyId.doSomeOtherThing(args);
//新增的东西可以在原有之前或之后都行
System.out.println("SimpleProxy doSomeOtherThing" + args);
}
}
public class SimpleProxyDemo {
static void consumer(Interface i) {
i.doSomething();
i.doSomeOtherThing(" yi gi woli giao");
}
public static void main(String[] args) {
consumer(new RealObject());
System.out.println("----- ----- -----");
consumer(new SimpleProxy(new RealObject()));
}
}
结果:
doSomething
doSomeOtherThing yi gi woli giao
----- ----- -----
SimpleProxy doSomething
doSomething
doSomeOtherThing yi gi woli giao
SimpleProxy doSomeOtherThing yi gi woli giao
因为consumer()接受的Interface,所以无论是RealObject还是SimpleProxy,都可以作为参数,而SimpleProxy插了一脚 代理了RealObject加了不少自己的东西。
java的动态代理更前进一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Interface {
void doSomething(); void doSomeOtherThing(String args);
} class RealObject implements Interface { @Override
public void doSomething() {
System.out.println("doSomething");
} @Override
public void doSomeOtherThing(String args) {
System.out.println("doSomeOtherThing" + args);
}
} class DynamicProxyHandler implements InvocationHandler {
private Object proxyId; public DynamicProxyHandler(Object proxyId) {
this.proxyId = proxyId;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
if (args != null) {
for (Object arg : args) {
System.out.println(" " + arg);
}
}
return method.invoke(proxyId, args);
}
} public class SimpleProxyDemo {
static void consumer(Interface i) {
i.doSomething();
i.doSomeOtherThing(" yi gi woli giao");
} public static void main(String[] args) {
RealObject realObject = new RealObject();
consumer(realObject);
System.out.println("----- ----- -----");
//动态代理 可以代理任何东西
Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject));
consumer(proxy);
}
}
结果:
doSomething
doSomeOtherThing yi gi woli giao
----- ----- -----
**** proxy:class $Proxy0, methodpublic abstract void Interface.doSomething(), args:null
doSomething
**** proxy:class $Proxy0, methodpublic abstract void Interface.doSomeOtherThing(java.lang.String),
args:[Ljava.lang.Object;@7ea987ac yi gi woli giao
doSomeOtherThing yi gi woli giao
通过Proxy.newProxyInstance()可以创建动态代理,这个方法需要三个参数:
1. 类加载器:可以从已经被加载的对象中获取其类加载器;
2. 你希望该代理实现的接口列表(不可以是类或抽象类,只能是接口);
3. InvocationHandler接口的一个实现;
在 invoke 实现中还可以根据方法名处对不同的方法进行处理,比如:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
if (args != null) {
for (Object arg : args) {
System.out.println(" " + arg);
}
}
if (method.getName().equals("doSomething")) {
System.out.println("this is the proxy for doSomething");
}
return method.invoke(proxyId, args);
}
还可以对参数或方法进行更多的操作因为 你已经得到了他们 尽情的使用你的代理权吧 ~~ 先加它十个内购。
九、接口与类型信息
interface关键字的一种重要目标就是允许程序员隔离构件,进而降低耦合。反射,可以调用所有方法,甚至是private。唯独final是无法被修改的,运行时系统会在不抛任何异常的情况接受任何修改尝试,但是实际上不会发生任何修改。
void callMethod(Object a, String methodName) throws Exception {
Method method = a.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(a);
}
Java编程思想——第14章 类型信息(二)反射的更多相关文章
- Java编程思想——第14章 类型信息(一)
运行时类型信息使得你可以在程序运行时发现和使用类型信息.Java是如何让我们在运行时识别对象和类的信息得呢? 主要有两种方式:1.传统RTTI,他假定我们在编译期间已经知道了所有类型:2.反射,它允许 ...
- Java编程思想之十四 类型信息
第十四章 类型信息 运行时类型信息使得你可以在程序运行时发现和使用类型信息 14.1 为什么需要RTTI 面向对象编程中基本的目的是:让代码只操作对基类的引用. 多态: import java.uti ...
- thinking in java学习笔记:14章 类型信息
14.2 Class 对象 https://github.com/zhaojiatao/javase 1.什么是Class对象,Class对象是用来做什么的? Class对象是java程序用来创建类的 ...
- Java编程思想——第17章 容器深入研究(two)
六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...
- Java编程思想 第21章 并发
这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ...
- Java编程思想——第17章 容器深入研究 读书笔记(三)
七.队列 排队,先进先出. 除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: ad ...
- Java编程思想读书笔记--第14章类型信息
7.动态代理 代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象.这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色. 什么是代理模式? ...
- Java编程思想(第一章 对象入门)总结
面向对象编程(oop) 1.1抽象的进步 所有编程语言的最终目的都是提供一种“抽象”方法. 难点是 在机器模型(位于“方案空间”)和实际解决问题模型(位于“问题空间”)之间,程序员必须建立起一种联 ...
- Java编程思想-第四章练习题
练习1:写一个程序,打印从1到100的值 public class Print1To100{ public static void main(String args[]){ for(int i = 1 ...
随机推荐
- MakeDownPad2基本使用
一.安装 1.1.MakeDownPad2下载安装 MakeDownPad2从官网下载安装包直接安装即可 1.2.依赖安装 MakeDownPad2支持html代码,如果要使用预览功能就需要安装awe ...
- ssh-keygen创建证书
ssh-keygen安装请参考以下内容:https://blog.csdn.net/a419419/article/details/80021684 (可能我已经安装过git了,所以不需要安装,具体细 ...
- 1,下载和部署开发环境--AutoCAD二次开发
环境需求为: AutoCAD 2020版 ObjectARX SDK 下载地址:https://www.autodesk.com/developer-network/platform-technolo ...
- EFK教程 - EFK快速入门指南
通过部署elasticsearch(三节点)+filebeat+kibana快速入门EFK,并搭建起可用的demo环境测试效果 作者:"发颠的小狼",欢迎转载与投稿 目录 ▪ 用途 ...
- Spring 源码阅读之 深入理解 finishBeanFactoryInitialization
源码入口 上篇博文中我们看到了将Spring环境中的 BeanPostProcessor找出来,添加到BeanFactory中的beanPostProcessors中,统一维护,本片博文继续往下拓展, ...
- 通过一个生活中的案例场景,揭开并发包底层AQS的神秘面纱
本文导读 生活中案例场景介绍 联想到 AQS 到底是什么 AQS 的设计初衷 揭秘 AQS 底层实现 最后的总结 当你在学习某一个技能的时候,是否曾有过这样的感觉,就是同一个技能点学完了之后,过了一段 ...
- 百万年薪python之路 -- 文件操作
1.文件操作: f = open("zcy.txt" , mode="r" , encoding="UTF-8") open() 打开 第一 ...
- ggstatsplot绘图|统计+可视化,学术科研神器
本文首发于“生信补给站”公众号,https://mp.weixin.qq.com/s/zdSit97SOEpbnR18ARzixw 更多关于R语言,ggplot2绘图,生信分析的内容,敬请关注小号. ...
- python3 requests_html 爬取智联招聘数据(简易版)
PS重点:我回来了-----我回来了-----我回来了 1. 基础需要: python3 基础 html5 CS3 基础 2.库的选择: 原始库 urllib2 (这个库早些年的用过,后来淡忘了) ...
- EFCore--->> CodeFirst (Vs2019 Core3.0)的简单使用
直接上干货 EFCore--->> CodeFirst (Vs2019 Core3.0) 1: 安装下面3个对应的package(在Nuget控制台或者直接NuGet包查询点击下载,我喜欢 ...