注解和反射

本文详细介绍了Java注解(Annotation)的概念、用途、元注解及其作用,以及如何使用反射机制(Reflection)访问和操作类的结构。涵盖了自定义注解、内置注解如@Override和SuppressWarnings,以及如何通过反射动态创建对象和操作注解。
摘要由CSDN通过智能技术生成

注解和反射

  1. 注解 Annotation ,为程序提供的可读性信息(被注解的部分,让程序知道它是干干什么用的)
Annotation的作用:对程序作出解释,可以被其他程序认识读取;
Annotation的格式:注释以 @注释名称 形式在代码中存在,还可以添加一些参数值,例如:@SuppressWarnings(value="unchecked")
Annotation在哪里使用:可以附加在 packageclass、method、field 等上面,相当于给他们添加了额外的辅助信息,我们通过反射机制编程实现对这些元数据的访问。

  1. 内置注解

    @Override:此注解只适用于修辞方法,表示一个方法声明打算重写一个超类中的另一个方法声明;

    @SuppressWarnings:用来抑制编译时的警告信息,添加后置参数例如:(“unchecked”)

    @SuppressWarnings("all")//将警告抹平注解,不显示
    public class test1 extends Object{
        @Override//重写方法注解
        public String toString() {
            return super.toString();
        }
        public static void test(){
            String testStr = "1";
        }
    }
    

  1. 元注解
  • 作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation 类型作说明。

    @Target :用于描述注解的使用范围(即:被描述的注解可以用在什么地方);

    //测试元注解
    @MyAnnotation1 //注释只能用在类上,所有会报错
    @MyAnnotation2 //可用
    public class Test2 {
        @MyAnnotation1//可用
        @MyAnnotation2//可用
        public void test(){
            System.out.println("ok");
        }
    }
    //定义一个注解
    @Target(value = ElementType.METHOD)//注解说明,这个接口只在方法上可用
    @interface  MyAnnotation1{
    }
    @Target(value = {ElementType.TYPE, ElementType.METHOD})//注解说明,这个接口可以用在类和方法上
    @interface MyAnnotation2{
    }
    

    @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期 RUNTIME;

    @Document:说明该注解将被包含在javadoc中;

    @Inherited:说明子类可以继承父类中的该注解;

    //测试元注解
    //@MyAnnotation1 //注释只能用在类上,所有会报错
    @MyAnnotation2 //可用
    public class Test2 {
        @MyAnnotation1//可用
        @MyAnnotation2//可用
        public void test(){
            System.out.println("ok");
        }
    }
    //定义一个注解
    //注解说明,这个接口只在方法上可用
    @Target(value = ElementType.METHOD)
    @interface  MyAnnotation1{
    }
    //注解说明,这个接口可以用在类和方法上
    @Target(value = {ElementType.TYPE, ElementType.METHOD})
    //Retention 表示我们的注解在什么地方有效 RUNTIME > Class > Sources
    @Retention(value = RetentionPolicy.RUNTIME)
    //表示是否将我们的注解生成在JavaDoc中
    @Documented
    //表示子类可以继承父类的注解
    @Inherited
    @interface MyAnnotation2{
    }
    

  1. 自定义注解:使用@interface自定义注解时,自动继承了Annotation接口
  • 声明格式:public @interface 注解名 { 定义内容};
  • 定义内容中的每一个方法,实际上是声明了一个配置参数;
  • 方法的名称,就是参数的名称;
  • 返回值类型,就是参数的类型(返回值只能是基本类型Class、String、enum);
  • 可以通过default 来声明参数的默认值;
  • 如果只有一个参数成员,最好使用value作为参数名;
  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0 作为默认值;
//自定义注解
public class Test3 {
    //注解可以显示赋值,如果没有显示,那么必须设置默认值
    @MyAnnotation3(name="小韩",sex ="男",eye=2)//其他参数因为有默认值,可以省略
    public void test1(){}
    @MyAnnotation4("爱你")// 因为只有一个注解,参数名为value,可以省略,不为value则不能省略
    public void test2(){}
}
//自定义注解3 (多个注解参数)
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    //注解的参数 :返回值类型(参数类型)+ 参数名称+()
    //通过default 可以设置默认值
    String name() default "";
    int age() default 0;
    String sex();
    int eye();
    String[] address() default {"北京","上海"};
}
//自定义注解4 (单个注解参数)只有一个注解参数时,将参数名使用value
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation4{
    String value();
}

  1. 反射机制 Reflection(反射)
  • Java反射机制:Java不是动态语言,但是被称为“准动态语言”,既Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性,让编程的时候更加灵活。

    val x = "123";
    eval(x);  //eval函数可以执行某些参数。
    
  • Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在运行期间借助于Reflection Api取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

    Class c = Class.forName("java.lang.String");
    
  • 程序运行,类加载完之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过它看到类的结构,所有我们形象的称之为反射。


  1. 获得反射的对象
  • Java反射机制提供的功能:
    • 在运行时判断任意一个对象所属哪个类、类中所具有的成员变量和方法、调用任意一个对象成员变量和方法;构造任意一个类的对象;获取泛型信息;处理注解;生成动态代理。
    • 优点:实现动态创建对象和编译,体现出很大的灵活性
    • 缺点:性能有影响,反射是一种解释操作,我们告诉Jvm,它去给做,这种操作比正常new缓慢。

  1. 获得Class对象的几种方式
//测试Class类的创建方式
public class TestRefelction {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是:" + person.name);
        //方式一:
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        //方式二:
        Class c2 = Class.forName("com.han.study.refelction.Student");
        System.out.println(c2.hashCode());
        //方式三:
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
        //方式四:
        Class c4 = c1.getSuperclass();
        System.out.println(c4);
        //特别的,内置类型包装类 Type属性
        Class type = Integer.TYPE;
        System.out.println(type);

    }
}
class Person{
    public String name;
    public Person() {
    }
    public Person(String name) {
        this.name = name;
    }
}
class Student extends Person{
    public Student() {
        this.name = "学生";
    }
}

  1. 哪些类型可以有Class对象

    class:外部类,成员(内部类,静态内部类),局部内部类,匿名内部类。

    interface:接口

    []:数组

    enum:枚举

    annotation:注解@interface

    primitive type:基本数据类型

    void


  1. Java内存分析。类加载
public class TestRefelction01 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
        /*
         1.加载代码到内存,产生一个Class对象
         2.将各项代码链接,链接完成后给m赋初始化值 m=0
         3.初始化静态代码(static常量顺序加载)
            <clinit> {
                m = 100;
                System.out.println("静态代码块初始化");
                m = 300;
            }
         */
    }
}
class A{
    static int m = 100;
    static {
        System.out.println("静态代码块初始化");
        m = 300;
    }
    public A(){
        System.out.println("构造器初始化");
    }
}
//JVM加载过程(服务启动)
1.加载TestRefelction01类(方法区,指向到堆)
    静态变量,静态方法,常量,业务代码
2.加载 A 类(方法区,指向到堆)
    静态变量,静态方法,常量,业务代码

当执行Main方法时,在堆中new A() 对象。获取m=300的值,传递回栈中。

  1. 类何时进行初始化
  • 类的主动引用(一定会发生的初始化)

    当虚拟机启动,先初始化主方法所在的类;

    new 一个类的对象;

    调用类的静态成员(除了final 常量)和静态方法;

    使用reflect包的方法对类进行反射调用;

    初始化一个类,如果其父类没有被初始化,则先初始化它的父类;

  • 类的被动引用(不会发生类的初始化)

    当访问一个静态域时,只有真正声明这个域的类才能被初始化。如:当通过子类引用父类的引用父类的静态变量,不会导致子类初始化;

    通过数组定义类引用,不会触发此类的初始化;

    引用常量不会触发此类的初始化(常量在连接阶段就存入调用类的常量池中了)


  1. 获取类的运行结构(了解)
User user = new User();
Class c1 = user.Class();//反射获取User的各种结构
//获取类的属性 (两种:全部或者 只有public

//获取类中的方法(两种:全部或者 只有public

//获取构造器
    

  1. 反射的方式动态创建Class对象
//动态的创建对象,通过反射
public class Test06 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        //获取Class对象
        Class c1 = person.getClass();
        //构造一个对象
        person = (Person)c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke 激活的意思
        //(对象,“方法的值”)
        setName.invoke(person, "zhangopw");
        System.out.println(person.getName());

        //通过反射获取操作属性
        Person person1 = (Person)c1.newInstance();
        Field age = c1.getDeclaredField("age");
        //不能直接操作私有属性,需要设置不检测
        age.setAccessible(true);
        age.set(person1,23);
        System.out.println(person1.getAge());
    }
}

  1. 练习反射操作注解
//练习反射操作注解
public class Test004 {
    public static void main(String[] args) throws Exception{
        Class c1 = Class.forName("com.han.study.Student4");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获取注解的value值
        TableHan annotation = (TableHan)c1.getAnnotation(TableHan.class);
        System.out.println(annotation.value());
        //获得类指定的注解
        Field name = c1.getDeclaredField("name");
        FieldHan annotation1 = name.getAnnotation(FieldHan.class);
        System.out.println(annotation1.col());
        System.out.println(annotation1.type());
        System.out.println(annotation1.len());

    }
}
//创建实体类
@TableHan("Db_student")
class Student4 {
    @FieldHan(col = "db_id", type = "int", len = 64)
    private int id;
    @FieldHan(col = "db_age", type = "int", len = 10)
    private int age;
    @FieldHan(col = "db_name", type = "varchar", len = 128)
    private String name;
    public Student4() {
    }
    public Student4(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student4{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}';
    }
}
//类名注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableHan{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldHan{
    String col();
    String type();
    int len();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值