Java基础之反射、注解、代理
反射
笔者对反射的理解就是解剖class文件,来进行一系列操作。
Class类
获取Class类实例的三种方式:
- 类名.class
- 对象.getClass()
static Class forName(String className)
根据类的名称获取类的Class对象(这里的className必须是类的全名)
一般使用第三种方式获取Class对象。
常用成员方法:
Field getField(String name)
获取类中的成员变量的对象String getName()
获取类的全名:包名.类名String getSimpleName()
获取类的简称:类名String getPackageName()
获取包名Field getField(String name)
获取公共成员变量对象Method getMethod(String name, Class<?>... parameterTypes)
获取类中的公共成员函数的对象Constructor<T> getConstructor(Class<?>... parameterTypes)
获取类中的公共构造函数的对象newInstance()
获取该类的实例(JDK 9已过期,使用clazz.getDeclaredConstructor().newInstance() 实例化)
静态:
forName(String className)
加载类
其中成员变量、成员函数、构造函数要素过多,使用了独立的类来描述:
类 | 描述 |
---|---|
Field | 成员变量 |
Method | 成员方法 |
Constructor | 构造方法 |
预定义对象:八中基本类型以及void,其class对象就是其本身
Constructor、Method、Field
Constructor
newInstance(Object... initargs)
获取实例setAccessible(boolean)
是否可以暴力访问,即越过私有权限的检验
setAccessible(boolean)
是其父类的方法,Field、Method、Constructor都可以设置暴力访问私有方法/变量。
Method
Object invoke(Object obj, Object... args)
调用方法,返回值为该方法的返回值(void方法返回null),第一个参数为调用的对象,第二个参数为方法的参数
类加载器
常见的类加载器有三种,每个类加载器负责加载不同位置的类:
加载器 | 说明 |
---|---|
Bootstrap 根类加载器 | Bootstrap是最顶级的类加载器。它加载类文件不是我们自己书写的,负责Java核心类的,比如System,String等。只有所有类加载到内存中,我们才可以使用。(Bootstrap自动加载) |
ExtClassLoader 扩展类加载器 | ExtClassLoader 扩展类加载器,加载的是扩展类的,我们是用不到的,都是jdk内部自己使用的。(ExtClassLoader类被BootStrap加载) |
AppClassLoader 系统/应用类加载器 | AppClassLoader 系统/应用类加载器,是用来加载ClassPath 指定的所有jar或目录,ClassPath表示存放类路径的,我们如果不配置ClassPath,那么就表示当前文件夹,在idea环境下的ClassPath是out目录。在out目录存放的都是我们书写好的class文件,也就是说 AppClassLoader 类加载器是用来加载我们书写的out目录下的class文件。(AppClassLoader类被ExtClassLoader加载) |
默认相对目录(文件路径)为相对项目目录,加载器相对目录为src
注解
JDK 常用注解:
注解 | 用途 |
---|---|
@Override |
重写 |
@SuppressWarnings() |
抑制警告 |
@FunctionalInterface |
函数式接口 |
@SuppressWarnings()
参数关键字列表:
参数 | 描述 |
---|---|
all | to suppress all warnings (抑制所有警告) |
boxing | to suppress warnings relative to boxing/unboxing operations(抑制装箱、拆箱操作时候的警告) |
cast | to suppress warnings relative to cast operations (抑制映射相关的警告) |
dep-ann | to suppress warnings relative to deprecated annotation(抑制启用注释的警告) |
deprecation | to suppress warnings relative to deprecation(抑制过期方法警告) |
fallthrough | to suppress warnings relative to missing breaks in switch statements(抑制确在switch中缺失breaks的警告) |
finally | to suppress warnings relative to finally block that don’t return (抑制finally模块没有返回的警告) |
hiding | to suppress warnings relative to locals that hide variable() |
incomplete-switch | to suppress warnings relative to missing entries in a switch statement (enum case)(忽略没有完整的switch语句) |
nls | to suppress warnings relative to non-nls string literals(忽略非nls格式的字符) |
null | to suppress warnings relative to null analysis(忽略对null的操作) |
rawtypes | to suppress warnings relative to un-specific types when using generics on class params(使用generics时忽略没有指定相应的类型) |
restriction | to suppress warnings relative to usage of discouraged or forbidden references |
serial | to suppress warnings relative to missing serialVersionUID field for a serializable class(忽略在serializable类中没有声明serialVersionUID变量) |
static-access | to suppress warnings relative to incorrect static access(抑制不正确的静态访问方式警告) |
synthetic-access | to suppress warnings relative to unoptimized access from inner classes(抑制子类没有按最优方法访问内部类的警告) |
unchecked | to suppress warnings relative to unchecked operations(抑制没有进行类型检查操作的警告) |
unqualified-field-access | to suppress warnings relative to field access unqualified (抑制没有权限访问的域的警告) |
unused | to suppress warnings relative to unused code (抑制没被使用过的代码的警告) |
自定义注解
声明注解
自定义注解使用@interface
声明
其内可以有属性:public abstract 属性类型 属性名() default 属性的默认值;
注解中public abstract
可以省略,并且属性类型只能是是:基本类型
、String
、Class
、注解
,以及以上类型的一维数组,属性可以没有默认值。
使用注解
注解可以没有属性,如果有属性需要在括号内赋值,有默认值可以不赋值。
相同注解在同一方法只能使用一次。
解析自定义注解
元注解
元注解是用来标记注解的注解。
一共有四种:
@Target
用于确定被修饰的注解使用的位置(主要)@Retention
用于确定被修饰的自定义注解生命周期(主要)@Documented
将此注解包含在Javadoc中@Inherited
允许子类继承父类中的注解
@Target
:表示该注解可以用于什么地方。可能的ElementType参数包括:CONSTRUCTOR
:构造器的生命FIELD
:域声明(包括enum实例)LOCAL_VARIABLE
:局部变量声明METHOD
:方法声明PACKAGE
:包声明PARAMETER
:参数声明TYPE
:类、接口(包括注解类型)和enum声明ANNOTATION_TYPE
:注解声明(与TYPE的区别?专门用在注解上的TYPE)TYPE_PARAMETER
:Java8TYPE_USE
:Java8
@Retention
:
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:SOURCE
:注解将在编译器丢弃CLASS
:注解在class文件中可用,但会被VM丢弃RUNTIME
:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
可以通过反射拿到方法,然后拿到注解,通过拿到的注解便可以拿到注解中的值。
代理
静态代理
代理:代理对象主要用来拦截目标业务对象的访问
- 代理对象要持有真实业务对象。(在代理类中创建被代理类的对象。)
- 代理对象要和真实业务对象,具备相同的行为方法。实现同一个接口。
- 代理对象拦截对真实对象的访问,可以修改访问的参数、返回值,甚至拦截访问。
静态代理使用较少。
动态代理
动态代理:就是在程序运行的过程中,动态的生成一个类,这个类要代理目标业务对象,并且可以动态生成这个代理类的对象。
在Java中当某个类需要被代理的时候,要求这个类中的被代理的方法必须抽取到一个接口中,然后这个类需要实现那个接口,只有在这个接口中的方法,代理类才能代理它。
Proxy类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
:
获得代理类实例,参数:
ClassLoader loader
类加载器,一般给被代理对象的类加载器即可
Class<?>[] interfaces
被代理对象的所有的接口数组
InvocationHandler h
调用处理器,是一个接口。
InvocationHandler
接口有一个静态方法:public Object invoke(Object proxy, Method method, Object[] args)
第一个参数是代理本身,第二个参数是调用的方法,第三个参数是调用方法的参数(在方法中this
是这个接口的实现类,proxy
才是代理本身,通过返回代理本身可以实现链式调用,参考这里)
上个栗子:
@Test
public void proxyTest() throws Exception {
//获取自定义类的Class对象
Class clazz = Class.forName("org.junit.sh.n1.Person");
//获取该类的类加载器
ClassLoader loader = clazz.getClassLoader();
//获取接口数组
Class[] interfaces = clazz.getInterfaces();
// @SuppressWarnings("all")//clazz.newInstance()方法在JDK9中过期了,懒得改了,注解一下
//实例化一个对象作为调用者
Person p = (Person) clazz.newInstance();
//使用Lambda实现InvocationHandler
InvocationHandler h = (proxy, method, args) -> {
if ("show".equals(method.getName())) {
System.out.println("修改方法");
return method.invoke(p, args);
}
return null;
};
//自定义类实现的接口
Showable theProxy = (Showable) Proxy.newProxyInstance(loader, interfaces, h);
//调用方法
theProxy.show();
}
真正理解反射和注解还是得结合框架(。・∀・)ノ
Java基础之反射、注解、代理的更多相关文章
- Java基础笔记 – Annotation注解的介绍和使用 自定义注解
Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 | 被围观 25,969 views+ 1.Anno ...
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- Java基础教程:注解
Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...
- 【Java基础】反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- 学习Spring必学的Java基础知识(2)----动态代理
Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习.Spring AOP使用了两种代理机制:一种是基于JDK的 ...
- Java基础之一反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- Java基础之—反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- java基础篇---反射机制
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
- Java基础教程(16)--注解
一.注解基础知识 1.注解的格式 最简单的注解就像下面这样: @Entity @符号指示编译器其后面的内容是注解.在下面的例子中,注解的名称为Override: @Override void ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
随机推荐
- P1073 多选题常见计分法
P1073 多选题常见计分法 转跳点:
- 2-10 就业课(2.0)-oozie:4、通过oozie执行shell脚本
oozie的配置文件job.properties:里面主要定义的是一些key,value对,定义了一些变量,这些变量往workflow.xml里面传递workflow.xml :workflow的配置 ...
- STM32+Nokia5110LCD
Nokia5110LCD(84*48) lcd.h #ifndef _LCD_H#define _LCD_H #include "sys.h" #include "std ...
- 【微信小程序】数组操作
Page({ data: { list:[{ id:1, name:'应季鲜果', count:1 },{ id:2, name:'精致糕点', count:6 },{ id:3, name:'全球美 ...
- Java程序员学习Go指南(三)
转载:https://www.luozhiyun.com/archives/213 人是否会进步以及进步得有多快,依赖的恰恰就是对自我的否定,这包括否定的深刻与否,以及否定自我的频率如何.这其实就是& ...
- SpringBoot---条件(th:if)
Thymeleaf 的条件判断是 通过 th:if 来做的,只有为真的时候,才会显示当前元素 <p th:if="${testBoolean}" >如果testBool ...
- Java基础学习总结(二)
Java语言的特点: Java语言是简单的 Java语言是面向对象的 Java语言是跨平台(操作系统)的(即一次编写,到处运行) Java是高性能的 运行Java程序要安装和配置JDK jdk是什么? ...
- supervisor的介绍
1.supervisor 简介 Supervisor 是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统.它可以很方便的 ...
- Golang的进制转换实战案例
Golang的进制转换实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.常用进制概述 1>.进制概述 进制也就是进位制,是人们规定的一种进位方法.举个例子:二进制就 ...
- Sass - &引用父选择器
描述: 您可以使用&字符选择父级选择器. 它告诉父选择器应该插入的位置. 例一:&在前 h3 { font-size: 20px margin-bottom: 10px &.s ...