Bootstrap

注解和反射

注解和反射

注解

​ Annotation。对程序做出解释,可以被其他程序读取。

​ 格式:

​ @注解名(value=“xxx”)

​ 在哪里使用?

​ package、class、method、field

内置注解

@Override			 //表示一个子类重写超类的一个方法
@Deprecated			//不鼓励程序员使用
@SuppressWarnings	//用来抑制编译时的警告

元注解

​ 作用:负责注解其他注解。用来提供对其他annotation类型作说明。

@Target			//用来描述注解的使用范围
@Retention		//表示再什么级别保存该注解信息(SOURCE < CLASS < RUNTIME)
@Documeneted	//说明该注解被包含在javadoc中
@Inherited		//说明子类可以继承父类中的该注解

自定义注解

​ 使用@interface自定义注解时,自动继承了Annotation接口

注:

​ @interface 用来声明一个注解,其中的每一个方法实际就是声明了一个配置参数

​ 方法的名称就是参数的名称,并且返回值类型就是参数的类型[只能是基本类型、Class、String、enum]

​ 可以通过default来声明默认值。

​ 如果只有一个参数成员,则一般命名为 value

​ 注解元素必须有值,因此时常使用空字符串 或 0 来作为 默认值

eg:

//自定义注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    //注解的参数:参数类型+参数名() 如果不设置默认值,则使用时必须赋值
    String name() default "";
    int age() default 0;
    int id() default -1;
}

//使用
@MyAnnotation(name = "注解测试",age = 10,id = 1)
public class Test  {
    public static void main(String[] args) throws IOException {

    }
}

反射

​ Reflection.反射机制允许程序在执行期间借助于Reflection API来取得任何类的内部信息,并可以直接操作任意对象的内部属性及方法。

​ 原理:

​ 加载完类后,堆内存的方法区回产生Class类型的对象[一个类只有一个Class对象],这个对象包含了完整的类的结构信息。而我们可以通过这个对象看到类的结构、

正常:
	导包->通过new实例化->取得实例化对象
反射:
	实例化对象->getClass()->取得该类

​ 应用:

​ 在运行时,判断任意对象的所属类、任意类的对象、一个类所具有的成员变量和方法、获取泛型信息、调用任意对象的成员变量和方法、处理注解

​ 生成动态代理等…

优缺点:

​ 优:可以实现动态创建对象和编译,增强灵活性

​ 缺:影响性能。

获得反射对象

public class Test  {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("javaEE.Student");
        System.out.println(c1); //class javaEE.Student

        //通过多个对象的hasCode => 一个类在内存中只有一个Class对象
        System.out.println(c1.hashCode());//1067040082
        System.out.println(Class.forName("javaEE.Student").hashCode());//1067040082

    }
}

class Student{
    private String name;
    private int id;
    private int age;

    public Student() {
    }

    public Student(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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;
    }
}

获得Class类

static ClassforName(String name)			//返回指定类名name的Class对象
Object newInstance()					   //通过缺省构造函数,返回Class对象的一个实例
getName()								  //返回此CLass对象所表示的实体(类、接口、数组类、void)的名称
Class getSuperClass()					   //返回当前对象的父类的Class对象
Class[] getInterfaces()					   //获取当前对象的接口
ClassLoader getClassLoader()			   //返回该类的类加载器
Constructor[] getConstructors()			   //返回一个包含某些Constructor对象的数组
Method getMethod(String name,Class..T)	   //返回一个Method对象,该对象形参类型为paramType
Field[] getDeclaredFields()				  //返回Field对象的一个数组

eg:

public class Test  {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person  = new Student();
        System.out.println("This is"+person.name);

        //1.
        Class c1 = person.getClass();
        System.out.println(c1.hashCode()); //1325547227

        //2.
        Class c2 = Class.forName("javaEE.Student");
        System.out.println(c2.hashCode()); //1325547227

        //3.
        Class c3 = Student.class;
        System.out.println(c3.hashCode()); //1325547227

        //4.基本类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);

        //
        Class c5 = c1.getSuperclass();
        System.out.println(c5); //class javaEE.Person
    }
}

class Person{
    String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

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

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

注:

​ 只要类型和维度一致,便是用一个Class

类加载器

​ 作用:作为方法去中类数据的访问入口

​ 类缓存:一旦类被加载至类加载器中,它将维持加载一段时间,直至JVM回收掉它。

eg:

public class Test  {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader); //jdk.internal.loader.ClassLoaders$AppClassLoader@15db9742

        //获取拓展类加载器 ->是 系统类加载器的父类
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent); //jdk.internal.loader.ClassLoaders$PlatformClassLoader@3f99bd52

        //获取根加载器 ->是 拓展类加载器的父类
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1); //null 根加载器无法获取

    }
}

创建运行时 类的对象

​ 通过反射获取运行时 类的完整结构

public class Test  {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("javaEE.User");

        //获取类的名字
        System.out.println(c1.getName()); //javaEE.User 包名+类名
        System.out.println(c1.getSimpleName()); //User  类名

        //获取类的属性
        /*
            //getFields只能找到public属性
            Field[] fields = c1.getFields();
         */
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
            /*
                private java.lang.String javaEE.User.name
                private int javaEE.User.id
                private int javaEE.User.age
             */
        }

        //获取类的方法
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println(method); //获得本类及其父类的public方法
        }

        methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method); //获取本类的方法
        }

        
    }
}

class User{
    private String name;
    private int id;
    private int age;

    public User() {
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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;
    }
}

动态创建对象的方法

eg:

public class Test  {
    public static void main(String[] args) throws Exception {
        //获得Class 对象
        Class c1 = Class.forName("javaEE.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);
        Object tom = constructor.newInstance("Tom", 1, 20);
        System.out.println(tom);//User{name='Tom', id=1, age=20}

        //通过反射调用普通方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user,"Jerry");
        System.out.println(user.getName());//Jerry

        //通过反射操作属性
        Field name = c1.getDeclaredField("name");
        //IllegalAccessException由于是私有的属性,直接调用会报错
        name.setAccessible(true);//暴力反射,允许访问该私有属性
        name.set(user,"Lucy");
        System.out.println(user.getName()); //Lucy
    }
}

反射操作泛型

ParamrterizedType	//表示一种参数化类型
GenericArrayType	//表示元素类型时参数化类型或数组类型
TypeVariable		//各种类型变量的公共父接口
WildcardType		//代表一种通配符类型表达式

eg:

public class Test  {

    public void param(Map<String,User> map,List<User> list){
        System.out.println("param");
    }

    public Map<String,User> paramDemo(){
        System.out.println("paramDemo");
        return null;
    }

    public static void main(String[] args) throws Exception {
        Method param = Test.class.getMethod("param", Map.class, List.class);

        Type[] genericParameterTypes = param.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("gen:"+genericParameterType);
            if (genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }//for
        /*
            gen:java.util.Map<java.lang.String, javaEE.User>
            class java.lang.String
            class javaEE.User
            gen:java.util.List<javaEE.User>
            class javaEE.User
         */

        Method paramDemo = Test.class.getMethod("paramDemo");
        Type genericParameterTypes1 = paramDemo.getGenericReturnType();
        if (genericParameterTypes1 instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterTypes1).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }//for
        }//if
        /*
            class java.lang.String
            class javaEE.User
         */
    }

}

反射操作注解

getAnnotations
getAnnotation

eg:

public class Test  {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("javaEE.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation); //@javaEE.Table(value="db_student")
        }
        //获取注解value的值
        Table table = (Table) c1.getAnnotation(Table.class);
        String value = table.value();
        System.out.println(value); //db_student

        //获得类指定的注解
        Field name = c1.getDeclaredField("name");
        TableField tableField = name.getAnnotation(TableField.class);
        System.out.println(tableField.columnName()); //db_name
        System.out.println(tableField.type()); //varchar
        System.out.println(tableField.length());//8

    }

}

@Table("db_student")
class Student{
    @TableField(columnName = "db_id",type = "int",length = 10)
    private int id;
    @TableField(columnName = "db_age",type = "int",length = 10)
    private int age;
    @TableField(columnName = "db_name",type = "varchar",length = 8)
    private String name;

    public Student() {
    }

    public Student(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", age=" + age +
                ", 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;
    }
}

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

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface TableField{
    String columnName();
    String type();
    int length();

}
;