和我一起迎接明天的太阳吧

klaus08

焦虑源于行动的匮乏

反射和注解

注解


内置注解

  1. @Deprecated

    // @Deprecated 意思是不推荐使用
    @Deprecated
    public static void test(){
    
    }
    

    使用@Deprecated注解的方法在使用时会有这种提示。


  1. @Override

    // @Override 重写父类的方法
    @Override
    public String toString() {
        return super.toString();
    }
    

  2. @SuppressWarnings
    镇压警告

    @SuppressWarnings("all")
    

元注解( meta-annotation )

元注解的作用就是注解其他注解,Java 定义了 4 个标准的 meta-annotation 类型。

  • @Target:描述注解的作用范围
  • @Retention:表示需要在什么级别保存保存该注释信息,用于描述注解的生命周期。
    (Source < Class < Runtime)
  • @Document:说明该注解将被包含在 javadoc 中
  • @Inherited:说明该类的子类可以继承父类的注解

自定义注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    int id();
    String name() default "klaus";
}


反射



一个类在内存中只有一个 Class 对象
一个类被加载后,类的整个结构都被封装在 class 中

package com.klaus.reflection;


// 什么是反射
public class Test extends Object{
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.klaus.reflection.USer");
        Class c2 = Class.forName("com.klaus.reflection.USer");
        Class c3 = Class.forName("com.klaus.reflection.USer");
        Class c4 = Class.forName("com.klaus.reflection.USer");

		// 哈希值相同
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());


    }
}


class USer{
}

获取 class 的方法

package com.klaus.reflection;

public class Test2 {

    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是" + person.name); //这个人是学生

        //1. 通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());//460141958

        //2.forName
        Class c2 = Class.forName("com.klaus.reflection.Student");
        System.out.println(c2.hashCode());//460141958

        //3.通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());//460141958

        //4.基本内置类型有 Type方法
        Class c4 = Integer.TYPE;
        System.out.println(c4);//int

        //5.获得class的父类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);//class com.klaus.reflection.Person
    }

}
class Person{
    String name;

    public Person() {}
}

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

class Teacher extends Person{
    public Teacher(){
        this.name = "老师";
    }
}


类的初始化


类的主动引用一定会发生类的初始化

  • 虚拟机启动,先初始化 main 方法所在的类
  • new 一个对象
  • 使用类的静态成员(除了 final 常量)和静态方法
  • 使用 java.lang.reflect 包的方法进行反射调用
  • 初始化一个类,如果父类没有被初始化,那么先初始化父类

被动引用

  • 访问一个静态域时,只有真正声明它的类才会被初始化
  • 通过数组定义类引用,不会触发此类的初始化(比如说定义了一个对象类型的数组)
  • 引用常量不会触发类的初始化(常量在链接阶段就存入常量池了)


反射的使用


Class c1 = Class.forName("com.klaus.reflection.User");

无参构造动态创建对象

// 无参构造
User user = (User) c1.newInstance();
System.out.println(user); / /USer{name='null', id=0, age=0}

有参构造创建对象

// 有参构造
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User instance =(User) constructor.newInstance("klaus", 12, 2);
System.out.println(instance);// USer{name='klaus', id=12, age=2}

通过反射调用方法

//通过反射调用方法
Method setName = c1.getDeclaredMethod("setName", String.class);// 获得方法
setName.invoke(instance,"Klaus08");
System.out.println(instance);//USer{name='Klaus08', id=12, age=2}

通过反射操作属性

//通过反射操作属性,对于私有属性要关闭 “安全检测”
User user2 =(User) c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);
name.set(user2,"zoe");
System.out.println(user2.getName()); //zoe

全部代码如下:

package com.klaus.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 动态创建对象
public class Test7 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("com.klaus.reflection.User");

        // 无参构造
        User u = (User) c1.newInstance();
        System.out.println(u);

        // 有参构造
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User instance =(User) constructor.newInstance("klaus", 12, 2);
        System.out.println(instance);

        //通过反射调用方法
        Method setName = c1.getDeclaredMethod("setName", String.class);// 获得方法
        setName.invoke(instance,"Klaus08");
        System.out.println(instance);

        //通过反射操作属性,对于私有属性要关闭 “安全检测”
        User user2 =(User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);
        name.set(user2,"zoe");
        System.out.println(user2.getName());

    }
}

setAccessible



反射&注解


通过反射获得注解信息,下面的代码演示了一般 ORM 注解的原理,通过注解获得属性对应列名,使 pojo 和表联系起来。

package com.klaus.reflection;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Test8 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("com.klaus.reflection.Student_");

        //通过反射获得注解
        Annotation[] annotation = c1.getAnnotations();
        for (Annotation annotation1 : annotation) {
            System.out.println(annotation1);//@com.klaus.reflection.TableKlaus(value=stu)
        }

        TableKlaus tableKlaus = (TableKlaus)c1.getAnnotation(TableKlaus.class);
        String value = tableKlaus.value();
        System.out.println(value);//stu

        Field name = c1.getDeclaredField("name");
        ColumnKlaus columnKlaus = name.getAnnotation(ColumnKlaus.class);
        System.out.println(columnKlaus.column());//name
        System.out.println(columnKlaus.type());//type
    }
}

@TableKlaus("stu")
class Student_{
    @ColumnKlaus(column ="name",type = "String")
    String name;
    @ColumnKlaus(column = "id", type = "int")
    int id;
}


// 类的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableKlaus{
    String value();
}

// 属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ColumnKlaus{
    String column();
    String type();
}
posted @ 2021-08-09 23:20  klaus08  阅读(32)  评论(0编辑  收藏  举报