栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

10-javase-注解&反射-笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

10-javase-注解&反射-笔记

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

文章目录

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

1. 注解(Annotation)的定义

1.1 定义注解并使用1.2 添加默认值1.3 方法名字定义为value() 2. 注解(Annotation)组成部分

2.1 Annotation.java2.2 ElementType.java2.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. 对注解的操作 三、案例


一、注解

概念:
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:developSSMSpringdonglijiedian_springspringd3-ioc-homeworktargetclassescomitAnnotation>javap -v MyAnnotation.class
Classfile /F:/develop/SSM/Spring/donglijiedian_spring/spring/d3-ioc-homework/target/classes/com/it/Annotation/MyAnnotation.class
  Last modified 2022-3-9; size 260 bytes
  MD5 checksum 113ec4cabaa9715f2aaba823edd7bb69
  Compiled from "MyAnnotation.java"
  // 我们发现字节码中注解其实也是一个接口统一继承字java.lang.annotatoin.Annotation
public interface com.it.Annotation.MyAnnotation extends java.lang.annotation.Annotation
  minor version: 0
  major version: 52
  flags: 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_ABSTRACT
    AnnotationDefault:
      default_value: s#7
  public abstract int value();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "MyAnnotation.java"

F:developSSMSpringdonglijiedian_springspringd3-ioc-homeworktargetclassescomitAnnotation>

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

2.1 Annotation.java
package java.lang.annotation;
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class 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  {

    // 获得他实现的接口
    public Class[] getInterfaces() {
        ReflectionData rd = reflectionData();
        if (rd == null) {
            // no cloning required
            return getInterfaces0();
        } else {
            Class[] interfaces = rd.interfaces;
            if (interfaces == null) {
                interfaces = getInterfaces0();
                rd.interfaces = interfaces;
            }
            // defensively copy before handing over to user code
            return interfaces.clone();
        }
    }

    private native Class[] getInterfaces0();   

    // 获得方法
    @CallerSensitive
    public Method[] getMethods() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyMethods(privateGetPublicMethods());
    }

    // 获得他的构造器
    @CallerSensitive
    public Constructor[] getConstructors() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyConstructors(privateGetDeclaredConstructors(true));
    }

    // 获得他的属性
    @CallerSensitive
    public 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 dogClass1 = Dog.class;

        // 2、使用对象
        Dog dog = new Dog();
        Class 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 dogClass = null;

    @Before
    public void before(){
        dogClass = Dog.class;
    }


代码如下(示例):

@Test
    public 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 constructor = dogClass.getDeclaredConstructor();
        System.out.println(constructor.getName());
5.2 获取无参构造器

代码如下(示例):

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


代码如下(示例):

        // 获取有参构造器并且实例化对象
        Constructor 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();

代码如下(示例):

三、案例
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/760500.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号