10-javase-注解反射-笔记

10-javase-注解&反射-ydl学习笔记


文章目录

  • 10-javase-注解&反射-ydl学习笔记
  • 一、注解
    • 1. 注解(Annotation)的定义
      • 1.1 定义注解并使用
      • 1.2 添加默认值
      • 1.3 方法名字定义为value()
    • 2. 注解(Annotation)组成部分
      • 2.1 Annotation.java
      • 2.2 ElementType.java
      • 2.3 RetentionPolicy.java
    • 3. java自带的 注解(Annotation)
      • 3.1 内置的注解
      • 3.2 常用的注解
    • 4. 注解(Annotation)的作用
  • 二、反射
    • 1.反射入门
    • 2. 获取类对象的方法
      • 2.1 获取方式
      • 2.2 对类对象操作
    • 3. 对成员变量的操作
      • 3.1 获取成员变量
      • 3.2 获取对象属性
      • 3.3 设置对象d1属性
    • 4. 对方法的操作
      • 4.1 获取方法
      • 4.2 调用方法
    • 5. 对构造器的操作
      • 5.1 获取构造器对象
      • 5.2 获取无参构造器
      • 5.3获取有参构造器并且实力化对象
    • 6. 对注解的操作
    • 7. 利用类加载器获取资源
  • 三、案例


一、注解

概念:
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种机制。Java语言中的类、方法、变量、参数和包等都可以被标注。

1. 注解(Annotation)的定义

1.1 定义注解并使用

定义的格式是:String name();

在这里插入图片描述

代码如下(示例):

public @interface MyAnnotation {String name();
}

在这里插入图片描述

代码如下:

public class Dog {private String name;private int age;@MyAnnotation(name = "小黄")public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

1.2 添加默认值

可以有默认值,也可以没有,如果没有默认值在使用的时候必须填写对应的值。默认值使用default添加。

在这里插入图片描述
在这里插入图片描述

1.3 方法名字定义为value()

如果想在使用的时候不指定具体的名字,方法名字定义为value() 即可。
注意:如果有多个参数时必须指定具体名字
在这里插入图片描述
在这里插入图片描述

2. 注解(Annotation)组成部分

我们使用javap查看生成的注解类:
在这里插入图片描述
在这里插入图片描述

F:\develop\SSM\Spring\donglijiedian_spring\spring\d3-ioc-homework\target\classes\com\it\Annotation>javap -v MyAnnotation.class
Classfile /F:/develop/SSM/Spring/donglijiedian_spring/spring/d3-ioc-homework/target/classes/com/it/Annotation/MyAnnotation.classLast modified 2022-3-9; size 260 bytesMD5 checksum 113ec4cabaa9715f2aaba823edd7bb69Compiled from "MyAnnotation.java"// 我们发现字节码中注解其实也是一个接口统一继承字java.lang.annotatoin.Annotation
public interface com.it.Annotation.MyAnnotation extends java.lang.annotation.Annotationminor version: 0major version: 52flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
Constant pool:#1 = Class              #12            // com/it/Annotation/MyAnnotation#2 = Class              #13            // java/lang/Object#3 = Class              #14            // java/lang/annotation/Annotation#4 = Utf8               name#5 = Utf8               ()Ljava/lang/String;#6 = Utf8               AnnotationDefault#7 = Utf8               小黑#8 = Utf8               value#9 = Utf8               ()I#10 = Utf8               SourceFile#11 = Utf8               MyAnnotation.java#12 = Utf8               com/it/Annotation/MyAnnotation#13 = Utf8               java/lang/Object#14 = Utf8               java/lang/annotation/Annotation
{// 生成了两个抽象方法public abstract java.lang.String name();descriptor: ()Ljava/lang/String;flags: ACC_PUBLIC, ACC_ABSTRACTAnnotationDefault:default_value: s#7public abstract int value();descriptor: ()Iflags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "MyAnnotation.java"F:\develop\SSM\Spring\donglijiedian_spring\spring\d3-ioc-homework\target\classes\com\it\Annotation>

java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:

2.1 Annotation.java

package java.lang.annotation;
public interface Annotation {boolean equals(Object obj);int hashCode();String toString();Class<? extends Annotation> annotationType();
}

2.2 ElementType.java

在这里插入图片描述

ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。大白话就是,说明了我的注解将来要放在哪里。

package java.lang.annotation;public enum ElementType {// 类、接口(包括注释类型)或枚举声明TYPE,          //  字段声明(包括枚举常量FIELD,       //  方法声明METHOD,       //  参数声明PARAMETER,      //  构造方法声明CONSTRUCTOR,     //  局部变量声明LOCAL_VARIABLE,  //   注释类型声明ANNOTATION_TYPE,   //  包声明PACKAGE      
}

2.3 RetentionPolicy.java

在这里插入图片描述

RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。

1.若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,“@Override” 就没有任何作用了。

2. 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。

3. 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。

package java.lang.annotation;
public enum RetentionPolicy {//Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了SOURCE,       //编译器将Annotation存储于类对应的.class文件中。但不会加载到JVM中。默认行为 CLASS,       // 编译器将Annotation存储于class文件中,并且可由JVM读入,因此运行时我们可以获取。RUNTIME       
}

3. java自带的 注解(Annotation)

Annotation 实现类的语法定义:

3.1 内置的注解

Java 定义了一套注解,共有10 个,6个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

(1)作用在代码的注解是
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java8 开始支持,标识某注解可以在同一个声明上使用多次。

(2)作用在其他注解的注解(或者说 元注解)是:
@Retention -标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented -标记这些注解是否包含在用户文档中。
@Target - 标记这个注解可以修饰哪些 Java 成员。
@Inherited -如果一个类用上了 @Inherited修饰的注解,那么其子类也会继承这个注解

3.2 常用的注解

通过上面的示例,我们能理解:@interface 用来声明 Annotation,@Documented 用来表示该 Annotation 是否会出现在 javadoc 中, @Target 用来指定 Annotation 的类型,@Retention 用来指定 Annotation 的策略。

@Documented 标记这些注解是否包含在用户文档中。

@Inherited

@Inherited 的定义如下:加有该注解的注解会被子类继承,注意,仅针对类,成员属性、方法并不受此注释的影响。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

@Deprecated

@Deprecated 的定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}

说明:@Deprecated 所标注内容,不再被建议使用。

在这里插入图片描述
加上这个注解在使用或者重写时会有警告:
在这里插入图片描述

@SuppressWarnings

@SuppressWarnings 的定义如下:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {String[] value();
}

说明:
​ SuppressWarnings 的作用是,让编译器对"它所标注的内容"的某些警告保持静默,用于抑制编译器产生警告信息。。例如,“@SuppressWarnings(value={“deprecation”, “unchecked”})” 表示对"它所标注的内容"中的 "SuppressWarnings 不再建议使用警告"和"未检查的转换时的警告"保持沉默

在这里插入图片描述

在这里插入图片描述

关键字用途
all抑制所有警告
boxing抑制装箱、拆箱操作时候的警告
fallthrough抑制在switch中缺失breaks的警告
finally抑制finally模块没有返回的警告
rawtypes使用generics时忽略没有指定相应的类型
serial忽略在serializable类中没有声明serialVersionUID变量
unchecked抑制没有进行类型检查操作的警告
unused抑制没被使用过的代码的警告

4. 注解(Annotation)的作用

(1)Annotation 具有"让编译器进行编译检查的作用“,这个讲了很多了。

(2)利用反射,和反射配合使用能产生奇妙的化学反应。

二、反射

1.反射入门

我们都知道光是可以反射的,我们无法直接接触方法区中一个类的方法、属性、注解等,那就可以通过一面镜子观察它的全貌,这个镜子就是JDK给我们提供的Class类。
在这里插入图片描述

​ 首先我们看一下Class这个类,初步简单的分析一下。我们发现这个类并没有什么成员变量,仅仅存在许多的方法,还有不少是本地方法。通过这些方法的名字我们大致能猜出,这个类能帮我们获取方法、构造器、属性、注解等。

代码如下(示例):

public final class Class<T>  {// 获得他实现的接口public Class<?>[] getInterfaces() {ReflectionData<T> rd = reflectionData();if (rd == null) {// no cloning requiredreturn getInterfaces0();} else {Class<?>[] interfaces = rd.interfaces;if (interfaces == null) {interfaces = getInterfaces0();rd.interfaces = interfaces;}// defensively copy before handing over to user codereturn interfaces.clone();}}private native Class<?>[] getInterfaces0();   // 获得方法@CallerSensitivepublic Method[] getMethods() throws SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);return copyMethods(privateGetPublicMethods());}// 获得他的构造器@CallerSensitivepublic Constructor<?>[] getConstructors() throws SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);return copyConstructors(privateGetDeclaredConstructors(true));}// 获得他的属性@CallerSensitivepublic Field getField(String name)throws NoSuchFieldException, SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);Field field = getField0(name);if (field == null) {throw new NoSuchFieldException(name);}return field;}
}

我们已经学过了类的加载过程,这里我们要介绍的是,每一个类加载完成后会在方法区生成一个Class类型的对象,辅助我们访问这个的方法、构造器、字段等。这个对象是Class的子类,每个类【有且仅有】一个Class类,也叫类对象。
在这里插入图片描述

2. 获取类对象的方法

2.1 获取方式

在这里插入图片描述
在这里插入图片描述
代码如下(示例):

public class Test {public static void main(String[] args) throws ClassNotFoundException {// 1、使用类名Class<Dog> dogClass1 = Dog.class;// 2、使用对象Dog dog = new Dog();Class<? extends Dog> dogClass2 = dog.getClass();// 3、formName使用全限定名Class<?> dogClass3 = Class.forName("com.it.Annotation.Dog");System.out.println(dogClass1 == dogClass2);System.out.println(dogClass2 == dogClass3);}
}

2.2 对类对象操作

在这里插入图片描述

代码如下(示例):

import com.it.Annotation.Dog;
import org.junit.Before;public class ReflectTest {Class<Dog> dogClass = null;@Beforepublic void before(){dogClass = Dog.class;}

在这里插入图片描述
代码如下(示例):

@Testpublic void createTest() throws InstantiationException, IllegalAccessException {//获取类名字String name = dogClass.getName();//获取类加载器ClassLoader classLoader = dogClass.getClassLoader();//获取资源URL resource = dogClass.getResource("");//得到父类Class superclass = dogClass.getSuperclass();//判断一个类是不是接口,数组等等boolean array = dogClass.isArray();boolean anInterface = dogClass.isInterface();//重点,使用class对象实例化一个对象Object instance = dogClass.newInstance();}

3. 对成员变量的操作

在java中万物皆对象成员变量也是对象,他拥有操作一个对象的成员变量的能力。

3.1 获取成员变量

getFields只能获取被public修饰的成员变量,当然反射很牛,我们依然可以使用getDeclaredFields方法获取所有的成员变量。

代码如下(示例):

// 这个方法只能拿到public修饰的成员变量Field[] fields = dogClass.getFields();for (Field field : fields) {System.out.println(field.getName());}// 这个方法可以获取所有的成员变量Field[] fields1 = dogClass.getDeclaredFields();for (Field field : fields1) {System.out.println(field.getName());}

3.2 获取对象属性

代码如下(示例):

// 这个方法可以获取所有的成员变量Field[] fields1 = dogClass.getDeclaredFields();for (Field field : fields1) {System.out.println(field.getName());}

当然你要是明确类型你还能用以下方法:
代码如下(示例):

Int i = age.getInt(dog);
xxx.getDouble(dog);
xxx.getFloat(dog);
xxx.getBoolean(dog);
xxx.getChar(dog);
//每一种基本类型都有对应方法

3.3 设置对象d1属性

代码如下(示例):

// 成员变量的本质就是赋值和取值,现在的问题是给谁赋值Dog dog = new Dog();Field name = dogClass.getDeclaredField("name");// 直接设置值,不能是private// 暴力注入name.setAccessible(true); // 打开权限name.set(dog, "xiaohei");System.out.println(name.get(dog));

当然如果你知道对应的类型,我们可以这样:

xxx.setBoolean(dog,true);
xxx.getDouble(dog,1.2);
xxx.getFloat(dog,1.2F);
xxx.getChar(dog,'A');
//每一种基本类型包装类都有对应方法

4. 对方法的操作

4.1 获取方法

在这里插入图片描述
代码如下(示例):

        // 获取所有的方法Method[] methods = dogClass.getDeclaredMethods();for (Method method : methods) {System.out.println(method.getName());}// 获取某一个方法Method getName = dogClass.getDeclaredMethod("getName");Method getNam2 = dogClass.getDeclaredMethod("main", String[].class);

4.2 调用方法

在这里插入图片描述
在这里插入图片描述
代码如下(示例):

// 方法而言只有一个核心方法,就是调用Method eat = dogClass.getDeclaredMethod("eat", String.class);Dog dog = new Dog();eat.setAccessible(true);eat.invoke(dog,"骨头😝");

5. 对构造器的操作

5.1 获取构造器对象

在这里插入图片描述
代码如下(示例):

// 获取构造器对象Constructor<Dog> constructor = dogClass.getDeclaredConstructor();System.out.println(constructor.getName());

5.2 获取无参构造器

代码如下(示例):

        // 获取无参构造器对象并且构造对象Constructor<Dog> constructor = dogClass.getDeclaredConstructor();Dog dog = constructor.newInstance(); // 这行代码与 new Dog(); 是一样的

5.3获取有参构造器并且实力化对象

在这里插入图片描述
代码如下(示例):

        // 获取有参构造器并且实例化对象Constructor<Dog> constructor1 = dogClass.getDeclaredConstructor(String.class);Dog dog1 = constructor1.newInstance("🐕二哈");System.out.println(dog1.getName());

6. 对注解的操作

在这里插入图片描述
在这里插入图片描述
代码如下(示例):

		// 元注解 要加上runtime// 类上MyAnnotation declaredAnnotation = dogClass.getDeclaredAnnotation(MyAnnotation.class);String name1 = declaredAnnotation.name();System.out.println("name1 = " + name1);Annotation[] annotation = dogClass.getAnnotations();// 字段上Field name = dogClass.getDeclaredField("name");Annotation[] annotation1 = name.getAnnotations();// 方法上Method eat = dogClass.getDeclaredMethod("eat", String.class);Annotation[] annotation2 = eat.getAnnotations();

代码如下(示例):

7. 利用类加载器获取资源

在这里插入图片描述

public class ClassLoderTest {@Testpublic void test1() throws IOException {// ①:创建properties实列Properties properties = new Properties();// ②:通过反射获取Class --> 在获取类加载器 --> 通过类加载器获取资源IO流InputStream stream =ClassLoderTest.class // 通过类名进行反射获取大Class.getClassLoader()    // getClassLoader() 获取这个类的加载器.getResourceAsStream("com/it/jdbc.properties"); // 以IO流的形式获取资源 返回的就是一个流// ③:使用properties 的 load() 方法加载 IO流properties.load(stream);  // properties 通过 load() 方法加载,刚好需要一个流// ④:通过key获取值String user = properties.getProperty("user");String password = properties.getProperty("password");System.out.println("user = " + user);System.out.println("password = " + password);}
}

在这里插入图片描述

在这里插入图片描述

三、案例


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部