注解与反射

1 Annotation&Reflection

注解:Annotation , 注释:Comment

since JDK5.0. 注解可以被编译器读取

格式:@注释名

例如:@Override(重写) @Deprecated (废弃)@SuppressWarnings(“all”)(镇压警告)

1.1 元注解

   @Retention:注解的保留位置         

    @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含

    @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,

    @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

 @Target:注解的作用目标        

    @Target(ElementType.TYPE) //接口、类、枚举、注解

    @Target(ElementType.FIELD) //字段、枚举的常量

    @Target(ElementType.METHOD) //方法

    @Target(ElementType.PARAMETER) //方法参数

    @Target(ElementType.CONSTRUCTOR) //构造函数

    @Target(ElementType.LOCAL_VARIABLE)//局部变量

    @Target(ElementType.ANNOTATION_TYPE)//注解

    @Target(ElementType.PACKAGE) ///包

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

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

image-20210128150839995

image-20210128151446146

1.2 自定义注解

image-20210128174347859

package com.hujesse.Annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class SelfDefineAnno {
    //注解可以显示赋值
    @MyAnnotation(age=4,name = "123")
    public void test(){ }
    // 当只要一个值并且参数名为value时可以省略
    @Myannotation2("fuck")
    public void tet(){ }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    // 注解的参数:参数类型+参数名();
    String name() default "";
    int age();
    String [] schools() default {"jialidun"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Myannotation2{
    String value();
}

2 Reflection

java是静态语言(还有c,c++),有了反射java变成了准动态语言.

根据类名创建实例(类名可以从配置文件读取,不用new,达到解耦)

new创建对象是静态编译,而反射创建对象是动态编译的过程。动态和静态分别代表的就是运行阶段和编译阶段。

  1. 【核心定义】java反射机制就是对于任意一个未知的类,都能够创建其对象,调用其方法。
  2. 反射和new的区别:new只能针对编译阶段已经存在的类,如果在编译时这个类不存在,就无法创建对象,因为你都不知道该new谁。而使用反射,在编译阶段这个类不需要存在,只要在运行时要创建对象的时候存在即可。简单来说,new只能为已知的类创建对象,反射可以为未知的类创建对象。

博文:https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html 写的很棒

image-20210128180649463

假如你写了一段代码:Object o=new Object();

运行了起来!

首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进JVM的内存中,你的类Object加载到方法区中,创建了Object类的Class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个Class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的Class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。

img

反射相关的主要API

image-20210129112141285

一个加载的类在JVM中只会有一个Class实例

        Class<?> c1 = Class.forName("com.hujesse.ReflectionTest.user");
        Class<?> c2 = Class.forName("com.hujesse.ReflectionTest.user");
        Class<?> c3 = Class.forName("com.hujesse.ReflectionTest.user");
        Class<?> c4 = Class.forName("com.hujesse.ReflectionTest.user");
        // 一个类在内存中只有一个Class对象
        // 一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());
// hashcode是一样的,只有一个Class对象

Class类的常用方法

image-20210129113610852

2.1获取Class类的实例

image-20210129114849181

package com.hujesse.ReflectionTest;
public class demo02 {
    public static void main(String[] args) throws ClassNotFoundException{
        User stu = new student();
        System.out.println(stu.name);
        //方式一:通过对象获得
        Class c1 = stu.getClass();
        //方式二:forname获得
        Class c2 = Class.forName("com.hujesse.ReflectionTest.student");
        // 方式三:通过类名.class
        Class c3=student.class;
        //方式四 ;基本内置类型的包装类都有一个TYPE属性
        Class c4 = Integer.TYPE;
        // 获取父类类型
        Class superclass = c1.getSuperclass();
    }
}
class User{
    public String name;
    public int age;
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public User() {
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class student extends User{
    public student(){
        this.name="student";
    }
}

class teacher extends User{
    public teacher(){
        this.name="teacher";
    }
}

2.2 那些类型可以有Class对象?

image-20210129115125642

package com.hujesse.ReflectionTest;
import java.lang.annotation.ElementType;
public class demo03 {
    public static void main(String[] args) {
        Object c1 = Object.class;  //类
        Class c2 = Runnable.class;  //接口
        Class c3 = String.class;   //一维数组
        Class c4 = int[][].class; // 二维数组
        Class c5 =Override.class;  //注解
        Class c6 =ElementType.class;  // 枚举
        Class c7 = Integer.class;  //基本数据类型 primitive type
        Class c8 = void.class;   // void
        Class c9 = Class.class;   // Class
    }
}

2.3 Java内存分析

image-20210129135000700

img

2.4 类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对改类进行初始化

image-20210129165452189

image-20210129170549519

2.5类的初始化

package com.hujesse.ReflectionTest;
public class demo04 {
    static {
        System.out.println("main被应用");
    }
    public static void main(String[] args) throws Exception{
        //1 主动引用
        //son s = new son();

        //2 反射
        //Class.forName("com.hujesse.ReflectionTest.son");

        //3 不会产生类的引用的方法
        System.out.println(son.b);
        son[] array = new son[5];
        System.out.println(son.M);
    }
}
class father{
    static int b = 2;
    static {
        System.out.println("father被加载");
    }
}
class son extends father{
    static int m =100;
    static{
        m = 3000;
        System.out.println("son被加载");
    }
    static final int M = 4;
}

2.6 类加载器

image-20210129172043893

image-20210129172056776

核心库:rt.jar

package com.hujesse.ReflectionTest;
public class demo06 {
    public static void main(String[] args) throws Exception{
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        // 获取系统加载器的父类加载器 -- 》 拓展加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取拓展加载器的父类加载器 -- 》根加载器
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
        // 测试当前类是那个加载器加载的
        ClassLoader classLoader = Class.forName("com.hujesse.ReflectionTest.User").getClassLoader();
        System.out.println(classLoader);
        //测试jdk下的类是那个加载器加载的(rt.jar下的根)
        ClassLoader classLoader2 = Class.forName("java.lang.String").getClassLoader();
        System.out.println(classLoader2); }}

2.7 获取运行时类的完整结构

image-20210129173518776

package com.hujesse.ReflectionTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo07 {
    public static void main(String[] args) throws Exception{
        Class c = Class.forName("com.hujesse.ReflectionTest.User");
        //1获得类的名字
        System.out.println(c.getName()); // 完整路径
        System.out.println(c.getSimpleName());
        //2 获得类的属性
        Field[] fields = c.getFields();   // 只能找到public属性
        for (Field field : fields) {
            System.out.println(field);
        }
        Field[] declaredFields = c.getDeclaredFields();  // 得到全部的属性
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        // 获得类的方法
        Method[] methods = c.getMethods(); // 获得本类和父类的所以public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        Method[] declaredMethods = c.getDeclaredMethods(); // 获得本类的所有方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        // 获得指定的方法
       // Method getname = c.getMethod("getname", null);
        //Method setname = c.getMethod("setname", String.class);
        System.out.println("=============");
        // 获得指定的构造器
        Constructor[] constructors = c.getConstructors();  // 获得public构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = c.getDeclaredConstructors(); //获得全部的构造方法包含private的
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
    }}

2.8通过反射创建对象

image-20210129181126652

package com.hujesse.ReflectionTest;

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

//通过反射创建对象
public class demo08 {
    public static void main(String[] args) throws Exception{
        // 获得Class对象
        Class c1 = Class.forName("com.hujesse.ReflectionTest.User");

        // 构造一个对象
        User user = (User) c1.newInstance(); //本质调用了无参构造
        System.out.println(user);
        
        // 通过反射获取一个方法
        Method setname = c1.getDeclaredMethod("setname", String.class);
        setname.invoke(user,"hujaja"); //invoke 激活
        System.out.println(user.getName());
        // 通过反射操作属性
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); // 关掉安全检查可以访问到private的属性
        name.set(user,"hujaja2");
        System.out.println(user.name);

        //通过构造器创建对象
        Constructor declaredConstructors = c1.getDeclaredConstructor(String.class,int.class);
        User user2 = (User)declaredConstructors.newInstance("hujesse", 12);
        System.out.println(user2);
    }}

setAccessible 作用是启动和禁用访问安全检查的开关

image-20210129181325549

3 获取注解信息

ORM:object relationship Mapping 对象关系映射

package com.hujesse.ReflectionTest;
import java.lang.annotation.*;
import java.lang.reflect.Field;
// 练习反射操作注解
public class deomolast {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.hujesse.ReflectionTest.student2");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        // 获取注解value的值
        TableHu tableHu = (TableHu)c1.getAnnotation(TableHu.class);
        String value = tableHu.value();
        System.out.println(value);
        // 获取类指定的注解
        Field name = c1.getDeclaredField("name");
        FieldHu fieldHu = name.getAnnotation(FieldHu.class);
        System.out.println(fieldHu.columnName());
        System.out.println(fieldHu.length());
        System.out.println(fieldHu.type());
    }
}
@TableHu("db_student")
class student2{
    @FieldHu(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldHu(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldHu(columnName = "db_name",type = "int",length = 10)
    private String name;

    public student2() {
    }

    public student2(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 "student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
// 类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableHu{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldHu{
    String columnName();
    String type();
    int length();
}

posted @ 2021-03-14 23:00  能借我十块钱吗  阅读(74)  评论(0编辑  收藏  举报