Java注解和反射学习笔记

观看B站狂神说的注解与反射总结的笔记
链接https://www.bilibili.com/video/BV1p4411P7V3

注解(java.Annotation)

@Override 重写

@Deprecated 废弃的,不推荐使用的

@SuppressWarnings 镇压警告,需要传参数

@Target 用于描述使用范围

@Retention 表示注解在那个等级的时候有效

(SOURCE < CLASS < RUNTIME

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

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

@interface 自定义注解

自定义注解

public class Test01 {
    @MyAnnotation(name = "dong",age = 18,schools = {"交院"})
    public void test(){}
}
//指定使用范围
@Target({ElementType.TYPE,ElementType.METHOD})
//指定注解的有效范围
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    //注解的参数:参数类型+参数名()
    String name() default "";
    int age() default 0;
    int id() default -1;//默认值为-1,代表不存在
    String[] schools() default {"西部开源","清华大学"};
}

反射(java.Reflection)

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

优点:可以实现动态创建对象和编译,体现出很大的灵活性

缺点:对性能有影响。使用反射基本上一种解释操作,这类操作总是慢于直接执行相同的操作。

public class test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的Class对象
        Class c1 = Class.forName("com.kuang.reflection.User");
        System.out.println(c1);//class com.kuang.reflection.User
        Class c2 = Class.forName("com.kuang.reflection.User");
        Class c3 = Class.forName("com.kuang.reflection.User");
        Class c4 = Class.forName("com.kuang.reflection.User");
        //一个类在内存中只有一个Class对象
        System.out.println(c2.hashCode());//1163157884
        System.out.println(c3.hashCode());//1163157884
        System.out.println(c4.hashCode());//1163157884
    }
}
//实体类
class User{
 //省略内部代码
}

Class类

  • Class本身也是一个类
  • Class对象只能由系统创建
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得对应的Class对象

Class类的常用方法

  • ClassforName(String name)返回指定类名name的Class对象
  • newInstance()调用缺省构造函数,返回Class对象的一个实例
  • getName()返回该Class对象所表示的实体(类,接口,数组类或viod)的名称
  • getSuperClass()返回当前Class对象的父类的Class对象
  • getinterfaces()过去当前Class对象的接口
  • getClassLoader()返回该类的加载器
  • getConstructors()返回一个包含某些Constructor对象的数组
  • getMethed(String name,Class… T)返回一个Method对象,此对象的形参类型为paramType
  • getDeclaredFields()返回Field对象的一个数组

获取Class类

  1. 通过具体类 . class属性获取,这种方法最安全可靠,程序性能最高

  2. 通过实例的getClass( )方法获取Class对象

  3. 已知类的全类名,可以通过Class类的静态方法forName( )获取,会抛出异常

  4. 基本数据类型可以直接用类名 . Type

  5. 还可以使用ClassLoader

    public class test03 {
        public static void main(String[] args) throws ClassNotFoundException {
            Person person = new Person();
            System.out.println("这个人是"+person.name);
    
            //方式一 通过具体类 . class属性获取
            Class c1 = person.getClass();
            System.out.println(c1.hashCode());
    
            //方式二 通过实例的getClass( )方法获取Class对象
            Class c2 = Class.forName("com.kuang.reflection.Student");
            System.out.println(c2.hashCode());
    
            //方式三 可以通过Class类的静态方法forName( )获取
            Class c3 = Student.class;
            System.out.println(c3.hashCode());
    
            //方式四 基本数据类型可以直接用类名 . Type
            Class c4 = Integer.TYPE;
            System.out.println(c4);
    
            //获得父类
            Class c5 = c1.getSuperclass();
            System.out.println(c5);
        }
    }
    class Person{
        public 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对象

  • class:外部类,成员(成员内部类,静态内部类),局部外部类,匿名内部类
  • interface:接口
  • [ ]:数组
  • enum:枚举
  • annotation:注解
  • primitive type:基于基本数据类型
  • void
Class c1 = Object.class; //类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //void
Class c9 = Class.class; //Class

类的加载过程

  1. 类的加载(Load)

    将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由加载器完成。

  2. 类的链接(Link)

    将类的二进制数据合并到JRE中

    • 验证:确保加载的类信息符合JVM规范,没有安全方面得到问题
    • 准备:正式为类变量(static)分配内存,分配内存并不设置类变量默认初始值的阶段,这些内存都将在方法去中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
  3. 类的初始化(Initialize)

    JVM负责对类进行初始化

    • 执行类构造器()方法的过程。(类构造器是构造类信息的,不是构造该类对象的构造器)
    • 当初始化一个类的时候,如果发现他的父类没有进行初始化,则需要先初始化他的父类
    • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步

什么时候会发生类的初始化

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

  • 当虚拟机启动时,先初始化main方法所在的类

  • new一个类的对象

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

  • 对类进行反射调用

  • 当初始化一个类时,如果其父类没有被初始化,则会先初始化它的父类

    public static void main(String[] args) throws ClassNotFoundException {
        //1.主动引用(new)
        Son son = new Son();
        //2.反射也会产生主动引用
        Class.forName("com.kuang.reflection.Son");
    }
    

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

  • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。

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

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

    public static void main(String[] args) throws ClassNotFoundException {
        //通过子类读取父类的常量,子类不会被初始化
         System.out.println(Son.b);
        //通过数组定义类的使用,不会触发类的初始化
        Son[] array = new Son[5];
        //调用常量(final)不会发生初始化
        System.out.println(Son.M);
    }
    

类加载器

public class test07 {
    public static void main(String[] args) {
        //获取系统加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //获取系统加载器的父加载器 -> 拓展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@4554617c

        //过去拓展类加载器的父加载器 -> 根加载器(C/C++写的java读取不到)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);//null
    }
}
public static void main(String[] args) throws ClassNotFoundException {
        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("com.kuang.reflection.test07").getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
        //测试JDK内部类是哪个加载器加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);//null
        //如何获取系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
//        C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;
//         C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;
//         G:\IDEA\zhujie\out\production\zhujie;
//         C:\IJ\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar
    }

创建运行时类的对象

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
    Class c1 = Class.forName("com.kuang.reflection.User");
    //获得类的名字
    System.out.println(c1.getName());//com.kuang.reflection.User
    //获得类的简单名字
    System.out.println(c1.getSimpleName());//User
    //获得类的属性
    Field[] declaredFields = c1.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField);
    }
    /*
     private java.lang.String com.kuang.reflection.User.name
     private int com.kuang.reflection.User.age
     */
    //获取指定属性的值
    Field name = c1.getDeclaredField("name");
    System.out.println(name);//private java.lang.String com.kuang.reflection.User.name
    //获得类的方法
    Method[] methods = c1.getMethods();//获取本类及其父类的所有public方法
    for (Method method : methods) {
        System.out.println(method);
    }
    /*
    public java.lang.String com.kuang.reflection.User.toString()
    public java.lang.String com.kuang.reflection.User.getName()
    public void com.kuang.reflection.User.setName(java.lang.String)
    public int com.kuang.reflection.User.getAge()
    public void com.kuang.reflection.User.setAge(int)
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    public boolean java.lang.Object.equals(java.lang.Object)
    public native int java.lang.Object.hashCode()
    public final native java.lang.Class java.lang.Object.getClass()
    public final native void java.lang.Object.notify()
    public final native void java.lang.Object.notifyAll()

    */
    Method[] declaredMethods = c1.getDeclaredMethods();//获取本类的所有方法(可以打印私有private方法)
    for (Method declaredMethod : declaredMethods) {
        System.out.println(declaredMethod);
    }
    /*
    *   public java.lang.String com.kuang.reflection.User.toString()
        public java.lang.String com.kuang.reflection.User.getName()
        public void com.kuang.reflection.User.setName(java.lang.String)
        public int com.kuang.reflection.User.getAge()
        public void com.kuang.reflection.User.setAge(int)
    * */

    //查询指定方法
    //应为Java有重载,所以要指定参数
    Method getName = c1.getMethod("getName", null);
    Method setName = c1.getMethod("setName", String.class);
    System.out.println(getName);//public java.lang.String com.kuang.reflection.User.getName()
    System.out.println(setName);//public void com.kuang.reflection.User.setName(java.lang.String)

    //获取所有构造器
    Constructor[] constructors = c1.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
    /*
    *   public com.kuang.reflection.User()
        public com.kuang.reflection.User(java.lang.String,int)
    * */
    //获取所有构造器
    Constructor[] declaredConstructors = c1.getDeclaredConstructors();
    for (Constructor declaredConstructor : declaredConstructors) {
        System.out.println(declaredConstructor);
    }
    /*
    *   public com.kuang.reflection.User()
        public com.kuang.reflection.User(java.lang.String,int)
     * */
    //根据参数获得指定构造器
    Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
    System.out.println(declaredConstructor);//public com.kuang.reflection.User(java.lang.String,int)
    
}

有了Class对象,能做什么

  • 创建类的对象:调用Class对象的newInstance()方法

    1. 类必须有无参构造器
    2. 类的构造器访问权限需要足够
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
            //获得Class对象
            Class c1 = Class.forName("com.kuang.reflection.User");
    
            //通过反射,构造一个对象
            User user = (User) c1.newInstance();//本质调用了无参构造
            System.out.println(user);
    
    
            //通过构造器创建对象
            Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);
            User use2 = (User) constructor.newInstance("东", 123);
            System.out.println(use2);
    
            //通过反射调用普通方法
            User user3 = (User) c1.newInstance();
            //通过反射获取一个方法
            Method setName = c1.getDeclaredMethod("setName", String.class);
        	//执行set方法
            setName.invoke(user3, "狂神");
            System.out.println(user3);
    
            User user4 = (User) c1.newInstance();
        	//通过反射获得属性
            Field name = c1.getDeclaredField("name");
            //关闭安全检测(可以对peivate属性进行更改)
            name.setAccessible(true);
            name.set(user4,"东2");
            System.out.println(user4.getName());
    
    
        }
    

性能分析

public static void test01(){
    User user = new User();
    long start = System.currentTimeMillis();
    for (int i = 0; i <1000000000 ; i++) {
        user.getName();
    }
    long end = System.currentTimeMillis();
    System.out.println("普通方法执行10亿次"+(end-start)+"ms");
}
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    User user = new User();
    Class c1 = user.getClass();
     Method getName = c1.getDeclaredMethod("getName",null);
    long start = System.currentTimeMillis();
    for (int i = 0; i <1000000000 ; i++) {
        getName.invoke(user, null);
    }
    long end = System.currentTimeMillis();
    System.out.println("反射方法执行10亿次"+(end-start)+"ms");
}
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    User user = new User();
    Class c1 = user.getClass();
    Method getName = c1.getDeclaredMethod("getName",null);
    getName.setAccessible(true);
    long start = System.currentTimeMillis();
    for (int i = 0; i <1000000000 ; i++) {
        getName.invoke(user, null);
    }
    long end = System.currentTimeMillis();
    System.out.println("反射方法关闭检测执行10亿次"+(end-start)+"ms");
}

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    test01();//普通方法执行10亿次8ms
    test02();//反射方法执行10亿次5054ms
    test03();//反射方法关闭检测执行10亿次2027ms
}

反射操作泛型

  • ParameterizedType:表示一种参数化类型
  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数据类型
  • TypeVariable:时各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式
//通过反射获取泛型
public void test01(Map<String,User> map, List<User> list){
    System.out.println("test01");
}
public Map<String,User> test02(){
    System.out.println("test02");
    return null;
}

public static void main(String[] args) throws NoSuchMethodException {
    //获取方法
    Method method = test11.class.getMethod("test01", Map.class, List.class);
    //通过Method过的泛型
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println(genericParameterType);
        //判断泛型是不是参数化类型
        if(genericParameterType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
    /*
    *   java.util.Map
        class java.lang.String
        class com.kuang.reflection.User
        java.util.List
        class com.kuang.reflection.User
    * */
    Method method2 = test11.class.getMethod("test02",null);
    Type returnType = method2.getGenericReturnType();
    if(returnType instanceof ParameterizedType){
        Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument);
        }
    }
    /*
    *   class java.lang.String
        class com.kuang.reflection.User
    * */
}

反射读取注解

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.kuang.reflection.Student2");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解的value值
        Tablekuang tablekuang = (Tablekuang)c1.getAnnotation(Tablekuang.class);
        String value = tablekuang.value();
        System.out.println(value);

        //获得类指定的注解
        Field f = c1.getDeclaredField("name");
        Filekuang annotation = f.getAnnotation(Filekuang.class);
        System.out.println(annotation.cloumName());
        System.out.println(annotation.length());
        System.out.println(annotation.Type());
    }
}
@Tablekuang("db_student")
class Student2{
    @Filekuang(cloumName = "db_id" ,Type = "int",length = 10)
    private int id;
    @Filekuang(cloumName = "db_name" ,Type = "varchar",length = 3)
    private String name;
    @Filekuang(cloumName = "db_age" ,Type = "int",length =10)
    private int age;

    public Student2() {
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablekuang{
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Filekuang{
    String cloumName();
    String Type();
    int length();
}

你可能感兴趣的:(Java注解和反射学习笔记)