反射

笔者对反射的理解就是解剖class文件,来进行一系列操作。

Class类

获取Class类实例的三种方式:

  1. 类名.class
  2. 对象.getClass()
  3. 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可以省略,并且属性类型只能是是:基本类型StringClass注解,以及以上类型的一维数组,属性可以没有默认值。

使用注解

注解可以没有属性,如果有属性需要在括号内赋值,有默认值可以不赋值。

相同注解在同一方法只能使用一次。

解析自定义注解

元注解

元注解是用来标记注解的注解。

一共有四种:

  1. @Target 用于确定被修饰的注解使用的位置(主要)
  2. @Retention 用于确定被修饰的自定义注解生命周期(主要)
  3. @Documented 将此注解包含在Javadoc中
  4. @Inherited 允许子类继承父类中的注解
  • @Target:表示该注解可以用于什么地方。可能的ElementType参数包括:

    1. CONSTRUCTOR:构造器的生命
    2. FIELD:域声明(包括enum实例)
    3. LOCAL_VARIABLE:局部变量声明
    4. METHOD:方法声明
    5. PACKAGE:包声明
    6. PARAMETER:参数声明
    7. TYPE:类、接口(包括注解类型)和enum声明
    8. ANNOTATION_TYPE:注解声明(与TYPE的区别?专门用在注解上的TYPE)
    9. TYPE_PARAMETER:Java8
    10. TYPE_USE:Java8
  • @Retention:

    表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

    1. SOURCE:注解将在编译器丢弃
    2. CLASS:注解在class文件中可用,但会被VM丢弃
    3. RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息

可以通过反射拿到方法,然后拿到注解,通过拿到的注解便可以拿到注解中的值。

代理

静态代理

代理:代理对象主要用来拦截目标业务对象的访问

  1. 代理对象要持有真实业务对象。(在代理类中创建被代理类的对象。
  2. 代理对象要和真实业务对象,具备相同的行为方法。实现同一个接口。
  3. 代理对象拦截对真实对象的访问,可以修改访问的参数、返回值,甚至拦截访问。

静态代理使用较少。

动态代理

动态代理:就是在程序运行的过程中,动态的生成一个类,这个类要代理目标业务对象,并且可以动态生成这个代理类的对象。

在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基础之反射、注解、代理的更多相关文章

  1. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Anno ...

  2. 黑马程序员:Java基础总结----反射

    黑马程序员:Java基础总结 反射   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...

  3. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  4. 【Java基础】反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  5. 学习Spring必学的Java基础知识(2)----动态代理

    Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习.Spring AOP使用了两种代理机制:一种是基于JDK的 ...

  6. Java基础之一反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  7. Java基础之—反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  8. java基础篇---反射机制

    一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...

  9. Java基础教程(16)--注解

    一.注解基础知识 1.注解的格式   最简单的注解就像下面这样: @Entity   @符号指示编译器其后面的内容是注解.在下面的例子中,注解的名称为Override: @Override void ...

  10. JAVA基础知识|反射

    一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...

随机推荐

  1. P1073 多选题常见计分法

    P1073 多选题常见计分法 转跳点:

  2. 2-10 就业课(2.0)-oozie:4、通过oozie执行shell脚本

    oozie的配置文件job.properties:里面主要定义的是一些key,value对,定义了一些变量,这些变量往workflow.xml里面传递workflow.xml :workflow的配置 ...

  3. STM32+Nokia5110LCD

    Nokia5110LCD(84*48) lcd.h #ifndef _LCD_H#define _LCD_H #include "sys.h" #include "std ...

  4. 【微信小程序】数组操作

    Page({ data: { list:[{ id:1, name:'应季鲜果', count:1 },{ id:2, name:'精致糕点', count:6 },{ id:3, name:'全球美 ...

  5. Java程序员学习Go指南(三)

    转载:https://www.luozhiyun.com/archives/213 人是否会进步以及进步得有多快,依赖的恰恰就是对自我的否定,这包括否定的深刻与否,以及否定自我的频率如何.这其实就是& ...

  6. SpringBoot---条件(th:if)

    Thymeleaf 的条件判断是 通过 th:if 来做的,只有为真的时候,才会显示当前元素 <p th:if="${testBoolean}" >如果testBool ...

  7. Java基础学习总结(二)

    Java语言的特点: Java语言是简单的 Java语言是面向对象的 Java语言是跨平台(操作系统)的(即一次编写,到处运行) Java是高性能的 运行Java程序要安装和配置JDK jdk是什么? ...

  8. supervisor的介绍

    1.supervisor 简介 Supervisor 是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统.它可以很方便的 ...

  9. Golang的进制转换实战案例

    Golang的进制转换实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.常用进制概述 1>.进制概述 进制也就是进位制,是人们规定的一种进位方法.举个例子:二进制就 ...

  10. Sass - &引用父选择器

    描述: 您可以使用&字符选择父级选择器. 它告诉父选择器应该插入的位置. 例一:&在前 h3 { font-size: 20px margin-bottom: 10px &.s ...