反射

笔者对反射的理解就是解剖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. 5G时代能携号转网,你会提前换新手机吗?

    每一次网络制式的变革,总能引发业界和大众的强烈关注.毕竟网络制式的迭代,能为社会的方方面面带来极大嬗变.而5G时代即将开启,必然会出现更多弄潮儿,也会带来让人心动的美好生活.不过,鉴于5G本身的特殊性 ...

  2. 数学软件实训2-MATLAB程序综合设计及应用

    数学软件实训任务二 一 题目:MATLAB程序综合设计及应用 二 目的:熟练掌握MATLAB程序设计的基本方法,会根据MATLAB程序设计的 三 要求: 1 熟练掌握控制流的基本语法结构. 2 会熟练 ...

  3. java内部类 2.19

    1.定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( ); //外部类HelloWorld publi ...

  4. Mongoose使用

    文章来自 Mongoose基础入门 Mongoose的API Mongoose模式扩展 指南之查询 指南之验证 mongoose方法很多,很乱,版本不一样,有些方法可能都过时了,所以整理了很久 连接数 ...

  5. 微信小程序是什么

    官方的开发文档 微信小程序写的不多,随便写写 创建项目,分析工具 微信小程序有专门的编辑工具,去官网下载 然后申请一个小程序项目,获得一个appId,然后进入编辑工具就可以直接开发了 编辑工具可以设置 ...

  6. 使用 json 模块,使json数据格式与Python字典dict数据格式互相转换,获取数据更加方便

    一.定义 JSON 是一种数据格式 使用 javaScript (Java 死鬼破特)对象表示法 二.特点 1.JSON 与 XML格式数据的区别 ====== 两种格式的数据,都是跨语言,跨平台 c ...

  7. 012-PHP创建一个多维数组

    <?php $Cities = array( //二维数组array() "华北地区"=>array( "北京市", "天津市" ...

  8. Live555 的一个缺陷–例子不能支持多线程(已经修改成支持多线程)

    我对Live555进行了一次封装,但是Live555 是单线程的,里面定义的全局变量太多,我封装好dll库后,在客户端调用,因为多个对话框中要使用码流,我就定义了多个对象从设备端接收码流,建立多个连接 ...

  9. TX2开发板Ubuntu16.04设置静态IP

    TX2开发板Ubuntu16.04设置静态IP  https://www.cnblogs.com/qilai/p/11285445.html 首先打开一个Terminal输入 ifconfig 查看自 ...

  10. Spark tungsten 项目阅读笔记

    Spark tungsten 项目阅读笔记 Spark tungsten 项目的宣言就是:Bringing Apache Spark closer Bare Metal. 我的理解就是不要让硬件成为S ...