Java基础之反射、注解、代理

反射

笔者对反射的理解就是解剖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();
}

真正理解反射和注解还是得结合框架(。???)ノ

原文地址:https://www.cnblogs.com/lixin-link/p/11116294.html

时间: 2024-10-28 19:18:22

Java基础之反射、注解、代理的相关文章

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

学习Spring必学的Java基础知识(2)----动态代理 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www

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

Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Annotation的工作原理:2.@Override注解:3.@Deprecated注解:4.@SuppressWarnings注解:5.自定义注解:5.1.添加变量:5.2.添加默认值:5.3.多变量使用枚举:5.4.数组变量:6.设置注解的作用范围:6.1.在自定义注解中的使用例子:7.使用反射读取R

Java语言中反射动态代理接口的解释与演示

Java语言中反射动态代理接口的解释与演示 Java在JDK1.3的时候引入了动态代理机制.可以运用在框架编程与平台编程时候捕获事件.审核数据.日志等功能实现,首先看一下设计模式的UML图解: 当你调用一个接口API时候,实际实现类继承该接口,调用时候经过proxy实现. 在Java中动态代理实现的两个关键接口类与class类分别如下: java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 我们下面就通过InvocationHan

Java基础之反射

Java反射是指运行时获取类信息,进而在运行时动态构造对象.调用对象方法及修改对象属性的机制.百度百科的定义:“JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. 一.反射的用途 Java的反射机制可以做3件事:运行时创建对象.运行时调用方法.运行时读写属性.进而实现以下功能:调用一些私有方法,实现黑科技.比如双卡短信发送.设置状态栏颜色.自动挂电

Java基础增强-反射机制

1 反射机制简介 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法.这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制.反射被视为动态语言的关键. 反射这一概念最早由编程开发人员Smith在1982年提出,主要指应用程序访问.检测.修改自身状态与行为的能力.这一概念的提出立刻吸引了编程界的极大关注,各种研究工作随之展开,随之而来引发编程革

java基础篇---反射机制

一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反射.通过反射,Java可以于运行时加载.探知和使用编译期间完全求和的类.生成其对象实体,调用其方法或者对属性设值.所以Java算是一个半动态的语言吧. 反射的概念: 在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方

黑马程序员-Java基础之反射

反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和方法:在运行时调用任意一个对象的方法:生成动态代理. 反射说白了就是可以获得一个类的所有信息,主要包括方法和属性两部分.1.获得方法包括获得方

JAVA基础知识|反射

一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. "运行状态",如何理解? "运行状态"体现了反射的应用场景,当一些类,不需要提前加载进JVM内存,而是在运行时根据需要进行加载的时候,就可以通过反射进行动态加载 1.2.如何理解反射? 学习过java的童鞋,肯定对spring.hibernate一

Java基础之—反射

反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 要想解剖一个类,必须先要获取到该类的字节码文件对象.而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对

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

一.注解基础知识 1.注解的格式 ??最简单的注解就像下面这样: @Entity [email protected]符号指示编译器其后面的内容是注解.在下面的例子中,注解的名称为Override: @Override void superMethod() {...} ??注解可以有若干个属性.可以在使用注解时指定属性的值: @Auther(name = "maconn") class MyClass { ... } ??如果注解只有一个属性,则可以省略属性的名称: @Auther(&q