IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java学习笔记18_反射、注解 -> 正文阅读

[Java知识库]java学习笔记18_反射、注解

学习内容

反射

将类的各个组成部分封装为其他对象的过程叫反射。

好处

  1. 可以在程序运行中操作这些对象
  2. 可以解耦,提高程序的可扩展性

Class 对象

获取 Class 对象的三种方式

  1. 类名.class

    多用于参数的传递。

  2. 对象名.getClass()

    多用于对象的获取字节码。

  3. Class.forName(类的全名)

    多用于配置文件

Class 对象的功能

  1. 获取成员变量
    1. Field[] getFields():获取所有 public 修饰的成员变量。
    2. Field getField(String fieldName):获取指定的,public 修饰的成员变量。
    3. Field getDeclaredFields() :获取所有的成员变量,不考虑修饰符。
    4. Field getDeckaredField(String fieldName) :获取指定的成员变量,不考虑修饰符。
    5. setAccessible(true):将访问权限打开,打开之后可以忽略修饰符的安全检查,从而访问所有修饰符修饰的字段,也称暴力反射。
  2. 获取构造方法
    1. Constructor<?>[] getConstructors() :获取所有的 public 构造器。
    2. Constructor<?>[] getDeclaredConstructors() :获取所有的构造器。
    3. Constructor<T> getConstructor(类<?>... parameterTypes) :获取指定的,public 修饰的构造器。
    4. Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) :获取指定的构造器,不考虑修饰符。
  3. 获取成员方法
    1. Method[] getMehods() :获取所有的 public 方法。
    2. Method[] getMehod(String name, 类<?>... parameterTypses) : 获取指定的的 public 方法。
    3. Method[] getDeclaredehods() :获取所有方法。
    4. Method[] getDeclaredMehod(String name, 类<?>... parameterTypses)
  4. 执行获取的成员方法
    1. (Method 对象).invoke(实例对象);

Field:成员变量

  • 操作:

    1. 设置值
    • void set(Object obj, Object value)
    1. 获取值
    • get(Object obj)
    1. 忽略访问权限修饰符的安全检查
    • setAccessible(true) :暴力反射

Constructor:构造方法

  • 创建对象:
    • T newInstance(Object... initargs)
    • 如果使用空参数构造方法创建对象,操作可以简化:Class 对象的 newInstance 方法

Method :方法对象

  • 执行方法:

    • Object invoke(Object obj, Object... args)
  • 获取方法名称:

    • String getName:获取方法名

注解

概念

注解(Annotation),也叫元数据。一种代码级别的说明。可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。但这种注释不是给人看的,是给计算机看的。

使用方式

@注解名称

作用

  1. 编写文档:通过代码里标识的注解生成文档
  2. 代码分析:通过代码里标识的注解对代码进行分析
  3. 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查

JDK 中一些预定义注解

@Override

检测被标注的方法是否是继承自父类的。

@Deprecated

该注解标注的内容已过时(就不推荐你使用这个内容,但是用了也不会出错)。

调用@Deprecated 标注的方法,方法会有一道横线划掉。例如 deprecatedMethod

@SuppressWarinings

压制警告:使编译器对于被标注内容的警告不再提示。一般会传递参数 (“all”)。

注解的本质

本质是一个接口,默认继承了 Annotation 接口。

public interface 注解名 extends java.lang.annotation.Annotation{}

属性

属性:接口中的抽象方法

  • 要求:
    1. 属性的返回值类型有下列取值
    • 基本数据类型
    • String
    • 枚举
    • 注解
    • 以上类型的数组
    1. 在使用属性时,需要给属性赋值。
      1. 在定义属性时,可以后接 default 以设置默认初始化值,这样使用注解时就可以不用赋值。
      2. 如果只有一个属性需要赋值,并且属性的名称是 value ,则 value 可以省略,直接定义值即可。
      3. 数组赋值时,值使用 {} 包裹。如果数组中只有一个值,则 {} 可以省略

元注解

用于描述注解的注解

常用元注解

1.@Target:描述注解能够作用的位置

  • ElementType取值:
    • TYPE:可以作用于类上
    • METHOD:可以作用于方法上
    • FIELD:可以作用于成员变量上
  1. @Retention:描述注解被保留的阶段
    • @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到。
    • SOURCE:
    • CLASS:类对象阶段
  2. @Documented:描述注解是否被抽取到api文档中
  3. @Inherited:描述注解是否被子类继承

自定义注解

格式

  • 元注解
  • public @interface 注解名称{}

工作内容

反射任务

任务1

使用反射解析某个你创建的类,把类中所有的属性、方法、接口都提取出来。要求:

通过三种不同的方式获取 Class 对象;

修改解析出来的类的属性值,然后再给类添加新的属性;

调用类方法(包括私有方法、静态方法和构造方法),执行后打印结果;

解析出该类的父类对象,并同样修改其父类的属性值并调用父类的方法。

答:

  1. 先定义类,及其方法、属性。

//定义 Animal 类
public class Animal {
    int weight ;
    public void sleep(){
        System.out.println("动物在睡觉");
    }
}
//定义 Cat 类
class Cat extends Animal {
  public String name;
  public int age;
  public int count;

  //重写public 方法 sleep
   @Override
  public void sleep() {
    System.out.println("猫在睡觉");
  }
  
  //静态方法 stop
  public static void stop(){
    System.out.println("静态方法,发呆,什么都不做");
  }

  //私有方法 catchMouse
  private void catchMouse() {
    System.out.println("抓老鼠");
  }

  //构造方法 3个
  public void Cat(String name) {
    this.name = name;
  }
  
  public void Cat(int age) {
    this.age = age;
  }

  public void Cat(String name, int age) {
    this.name = name;
    this.age = age;
  }
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
}
  1. 用三种方法获取 Class 对象

//第一种获取 Class 对象的方式
Class cls1 = Cat.class;

//第二种获取 Class 对象的方式
Cat cat2 = new Cat();
Class cls2 = cat2.getClass();

//第三种获取 Class 对象的方式
Class cls3 = Class.forName("com.xxm.Mission8.Cat");
  1. 修改解析出来的类的属性值,然后再给类添加新的属性;

Class cls4 = Cat.class;
//声明 Field 对象 field,让其cls4类对象的 "name" 字段。
Field field = cls4.getDeclaredField("name");
//创建一个实例对象
Cat cat4 = new Cat();

//field 对象调用get方法,并赋值给 value
Object value = field.get(cat4);

//打印此时的 cat4.name 和 value,因为都未赋值,所以都是 null。
System.out.println(cat4.name); 
System.out.println(value);

//field 对象调用 set 方法,将 cat4 对象的值设为 "field猫"
field.set(cat4, "field猫");

//再打印此时的 cat4.name,变为了 "field猫"
System.out.println(cat4.name);
  1. 调用类方法(包括私有方法、静态方法和构造方法),执行后打印结果;

Class cls5 = Cat.class;
Cat cat5 = new Cat();

//普通 public 方法
Method eatMethod = cls5.getMethod("sleep");
eatMethod.invoke(cat5);	//结果:打印出了睡觉"

//静态方法
Method stopMethod = cls5.getDeclaredMethod("stop");
stopMethod.invoke(cat5);	//结果:打印出了"静态方法,发呆,什么都不做"

//private 方法
Method catMouseMethod = cls5.getDeclaredMethod("catchMouse");
catMouseMethod.setAccessible(true);
catMouseMethod.invoke(cat5);	//结果:打印出了抓老鼠

//调用构造器
Constructor constructor = cls5.getConstructor(lass);
System.out.println(constructor);	//结果:																																																						
  1. 解析出该类的父类对象,并同样修改其父类的属性值并调用父类的方法。

Class cls6 = cls5.getSuperclass();
System.out.println(cls6);   //结果:class com.xxm.mission8.Animal

Method animalSleepMethod = cls6.getDeclaredMethod("sleep");
animalSleepMethod.invoke(cat5); //结果:打印出了"猫在睡觉"

Animal animal1 = new Animal();
animalSleepMethod.invoke(animal1);  //结果:打印出了"动物在睡觉"

这里有一个很有意思的现象,在我使用 invoke指令时,由于忘记重新创建一个 Animal 类的实例对象,我的invoke 方法传入的参数为前面创建的 cat5 ,结果调用的是在 Cat 类中被覆写过的 sleep 方法。可以得出 Method 对象的获取方法的方法,确实是根据传入的字符串来判断的,而实际调用的时候,会根据传入参数的类来决定调用哪个方法。

注解任务

任务1

  1. 自定义一个 ElementType 类别为 METHOD,RetentionPolicy 类别为 RUNTIME 的注解,任务要求:

    • 创建一个类,类的方法使用自定义的注解;

    答:

    创建自定义注解 MyAnno1

    package com.xxm.mission9;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = {ElementType.METHOD})
    
    public @interface MyAnno1 {
        String value() default "这是MyAnno1的默认注解内容";
    } 
    

创建类 Cat

package com.xxm.mission9;

public class Cat {
@MyAnno1
public void eat(){
 System.out.println("猫猫吃猫粮");
}
}
  • 通过反射解析类注解,判断该方法是否有注解,如果有则打印出注解的内容。

答:

//获取类对象
Class class1 = Cat.class;

//获取方法
Method m = class1.getMethod("eat");

//获取注解对象
MyAnno1 anno1 = m.getAnnotation(MyAnno1.class);

//打印注解
System.out.println(anno1.value());	//结果:这是MyAnno1的默认注解内容

?

  1. 自定义一个 ElementType 类别为 FIELD,RetentionPolicy 类别为 CLASS 的注解,任务要求:

    • 创建一个类,给类的某个字段使用自定义的注解;

    答:

    创建自定义注解 MyAnno2

    package com.xxm.mission9;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnno2 {
        String className();
    
        String fieldName();
    
        String value() default "这是 MyAnno2 的默认内容";
    }
    

    ?

    将上一题中的 Cat 类添加字段,并添加自定义注解:

    ?

package com.xxm.mission9;
public class Cat {
  @MyAnno1(className = "com.xxm.mission9.Cat", methodName = "eat")
  public void eat() {
    System.out.println("猫猫吃猫粮");
  }
  
  @MyAnno2(className = "com.xxm.mission9.Cat", fieldName = "name")
  public int name;
}
  • 通过反射解析类注解,判断该方法是否有注解,如果有则打印出注解的内容。

    Class class2 = Cat.class;
    Field f = class1.getDeclaredField("name");
    MyAnno2 anno2 = f.getAnnotation(MyAnno2.class);
    System.out.println(anno2.value());
    //结果:这是 MyAnno2 的默认内容
    

    ?

  1. 模仿上面的嵌套注解,除了可以字段类型的注解外,再加上字段长度和是否可以为空的注解,并加入到@TableColumn 注解中去。

    答:

    字符串长度:

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ColumnLength {
        int value() default 0;
    }
    

    字符串是否为空:

    public @interface ColumnEmptyOrNot {
        @Target(ElementType.FIELD)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface ColumnLength {
            boolean value() default true;
        }
    }
    

    添加后的 @TableColumn

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TableColumn {
        ColumnType columntype() default @ColumnType;
        ColumnLength columnlength() default  @ColumnLength;
        ColumnEmptyOrNot columnEmptyOrNot() default @ColumnEmptyOrNot;
    }
    

    ?

  2. 自定义嵌套注解,用来描述用户类中的「岗位」字段。

    • 第一层注解定义岗位所在的部门;
    • 第二层注解定义岗位名称和描述。

答:

岗位名称注解:

package com.xxm.advanced_camp.mission9.Task4;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author xxm
 * 注解:岗位名称
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PostName {
    String postName() default "";
}

岗位描述注解:

package com.xxm.advanced_camp.mission9.Task4;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author xxm
 * 注解:岗位描述
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PostDescription {
    String postDescription() default "";
}

部门注解:

package com.xxm.advanced_camp.mission9.Task4;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author xxm
 * 注解:岗位所在部门
 */

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Department {
    String departmentName() default "";

    PostName postName() default @PostName;

    PostDescription postDescription() default @PostDescription;
}

应用嵌套注解:

package com.xxm.advanced_camp.mission9.Task4;


public class Position {
    @Department(postName = @PostName, postDescription = @PostDescription)

    private String postName;
    private String postDescription;
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-28 12:16:13  更:2021-10-28 12:17:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/20 0:41:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码