反射

笔者对反射的理解就是解剖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. P1065 单身狗

    P1065 单身狗 转跳点:

  2. redis学习记录1 特性与优点

    1.存储结构:字符串.散列.列表.集合.有序集合. redis存储结构的优势:数据在redis中的储存方式和其在程序中的储存方式相近:redis对不同数据类型提供非常方便的操作方式,如使用集合类型储存 ...

  3. linux 域名

    Linux 安装好后,其默认的主机名是 localhost.   1.修改 /etc/sysconfig/network  配置文件 vi  /etc/sysconfig/network 修改HOST ...

  4. 微信小程序自定义组件-下拉框

    这个是网址https://www.cnblogs.com/zjjDaily/p/9548433.html 微信小程序之自定义select下拉选项框组件 知识点:组件,animation,获取当前点击元 ...

  5. R 误差自相关与DW检验

    R语言进行DW检验: library(lmtest) dw = dwtest(fm1) > dw Durbin-Watson test data: fm1 DW = 2.4994, p-valu ...

  6. PHP: isset与empty的区别

    PHP的isset()函数 一般用来检测变量是否设置 功能:检测变量是否设置 返回值: 若变量不存在则返回 FALSE 若变量存在且其值为NULL,也返回 FALSE 若变量存在且值不为NULL,则返 ...

  7. 自己写个tween

    public Vector3 begin,end;//起始终止坐标 public float BtoE_time;//用时 float timer,lerp;//计时器和进度值 void Update ...

  8. hadoop ozone入门

    简介 众所周知,HDFS是大数据存储系统,并在业界得到了广泛的使用.但是无论大集群还是小集群其扩展性都受NameNode的限制,虽然HDFS可以通过Federation进行扩展,但是依然深受小文件和4 ...

  9. kali linux终端快捷键设置

    kali里面是没有终端快捷键的,需要自己设置. 打开设置->设备->keyboard,拉到最下面点击加号来新建一个快捷键. 名称:打开终端 命令:gnome-terminal 快捷键:Ct ...

  10. UVA - 1423 Guess (拓扑排序)

    题意:已知矩阵S,求序列a.已知矩阵Sij = “ + ” if ai + . . . + aj > 0; Sij = “ − ” if ai + . . . + aj < 0; and ...