Java SE进阶注解和反射

文章目录

  • 一、注解
    • 1.1认识注解
    • 1.2内置注解
    • 1.3元注解
  • 二、反射
    • 2.1反射的概念
    • 2.2Class类
      • 2.2.1获取Class对象
    • 2.3类加载器
    • 2.4Class对象功能
  • 2.5反射和普通方法创建对象性能测试:
    • 2.6通过反射操作注解

一、注解

1.1认识注解

Annotation是从JDK5.0开始引进的新技术
1.Annotation的作用:
(1)不是程序本身,可以对程序作出解释(这一点和注释(comment)没什么区别)
(2)可以被其他程序(比如编译器)读取
2.Annotation的格式:
注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:
@SuppressWarnibgs(value=“unchecked”)
3.Annotation在哪里使用
可以附加在package、class、method。field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些数据的访问

Java SE进阶注解和反射_第1张图片
@Override重写父类方法,如果重写的方法名和父类不一致,则会出现错误提示
Java SE进阶注解和反射_第2张图片

1.2内置注解

1.Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
2.Deprecated:定义在java.lang.Deprecated中,此注释可以修辞方法,属性,类,表示不鼓励程序员使用的元素,通常是因为它很危险或者我存在更好的选择
3.SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,与前面两个注释不一样的是,需要添加一个参数才能正确使用,这些参数都是已经定义好了:
@SuppressWarnings(“all”)
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,“deprecated”})

/*
 * author zhxd
 * ClassName Car
 * date 2022/12/3 13:49
 */

public class Car extends Object{
    @Override
    public String toString() {
        return super.toString();
    }

    @Deprecated
    public static void test01() {
        System.out.println("deprecated");
    }

    public static void test02() {
        test01();
        System.out.println("Suppresswarnings");
    }
}

Java SE进阶注解和反射_第3张图片
可加上@SupperWarnings注解抑制编译时的警告
Java SE进阶注解和反射_第4张图片

1.3元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们是被用来提供对其他annotation类型作说明,这些类型和它们所注解的类在java.lang.annotation可以找到(@Target、@Retention、@Document、@Inheritd)
1.@Target:用于描述注解的使用范围(注解在哪里可以使用,在类中还是方法或者其他地方)
2.@Retention:表示需要在什么级别保存该注解信息,用于描述注解的声明周期(SOURCE < CLASS < RUNTIME
3.@Documented:说明该注解被包含在Javadoc中
4.@Inheritd:说明子类可以继承父类的注解

package com.zhxd.test;
/*
 * author zhxd
 * ClassName Test
 * date 2022/12/3 22:55
 */

import java.lang.annotation.*;

@MyAnnotation
public class Test {

}

//定义一个注解
//Target表示我们的注解在什么地方可以使用
@Target(value = {ElementType.METHOD, ElementType.TYPE})

//Retention 表示我们在什么地方还有效
// SOURCE表示在源码中有效 CLASS表示源码编译后有效 RUNTIME在运行时还是有效 RUNTIME > CALSS > SOURCE
@Retention(value = RetentionPolicy.RUNTIME)

//Documented 表示是否将我们的注解生成在Javadoc中
@Documented

//Inherited 表示子类可以继承父类的注解
@Inherited
@interface MyAnnotation {

}

使用了@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
自定义注解分析:

  1. @interface用来声明一个注解,格式:[public] @interface 注解名{定义内容}
  2. 其中每一个方法实际上是声明了一个配置参数
  3. 方法名称就是参数名称
  4. 返回值就是参数的类型(返回值只能是基本数据类型,Class,String,enum)
  5. 可以通过default来声明参数的默认值
  6. 如果只有一个参数成员,一般参数名为value
  7. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值
package com.zhxd.test;
        /*
         * author zhxd
         * ClassName Test
         * date 2022/12/3 22:55
         */

        import java.lang.annotation.*;

@MyAnnotation(age = 18)
public class Test {

}

@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    //注解参数 : 注解类型 + 参数名()
    String name() default "";
    int age();
    int id() default -1;
    String[] school() default {"华南师范大学", "华南理工大学"};
}

二、反射

2.1反射的概念

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflect API取得任何类内部的信息,并能直接操作内部属性及方法。加载类之后,在堆内存中就会产生一个Class类型的对象(一个类只有一个Class对象),这个对象就像一面镜子,透过这个镜子看到类结构,所以我们形象的称之为:反射
Java SE进阶注解和反射_第5张图片

2.2Class类

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口,对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。

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

2.2.1获取Class对象

  1. Class.forName(包名)
  2. 类名.class
  3. 对象.getClass()
  4. 获取父类类型:对象.getSuperClass()
package com.zhxd.test;
/*
 * author zhxd
 * ClassName Test02
 * date 2022/12/27 15:35
 */

//测试Class类的创建方式有哪些
public class Test02 {
    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()); // 1956725890

        //方式二:forName获得
        Class c2 = Class.forName("com.zhxd.test.Student");
        System.out.println(c2.hashCode()); // 1956725890

        //方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode()); // 1956725890

        //方式四:基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);// int

        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c3);// class com.zhxd.test.Student
    }
}


class Person {
    String name;

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

    public Person() {
    }

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

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

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

2.3类加载器

类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。(把类(class)装载进内存的

类缓存:标准的Java SE 类加载器可以按要求查找类,但一旦被加载带类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。
Java SE进阶注解和反射_第6张图片
JVM规范定义了如下的类加载器:
Java SE进阶注解和反射_第7张图片
引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库,该加载器无法直接获取
扩展类加载器:负责jre/lib/ext目录下的jar包或者-D java.ext.dirs指定目录下的jar包装入工作库
系统类加载器:负责java --classpath或者java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器

package com.zhxd.test;
/*
 * author zhxd
 * ClassName Test03
 * date 2022/12/31 13:23
 */

public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类加载器
        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@74a14482

        //获取扩展类加载器的父类加载器 --> 根加载器(c/c++ 无法直接获取,返回null)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);//null

        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("com.zhxd.test.Test03").getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //测试jdk内置的类是哪个记载器加载的
        classLoader = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);//null

		//如何获取系统加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

双亲委派机制:检测安全性,自定义的类加载器去往父类加载器找,如果在父类中能找到,则自定义的这个类是无效的,比如我们自己定义了一个java.lang.String,类加载器就会往父类加载器找,最终在根加载器找到了String类,自定义的String类则是无效的,不会执行,在一定程度上保证了安全性。

2.4Class对象功能

  1. 获取成员变量:
  • Field[] getFields():获取所有public修饰的成员变量
  • Field getField(String name):获取指定名称public修饰的成员变量
  • Field[] getDeclaredFields():获取所有成员变量,不考虑修饰符号
  • Field[] getDeclaredField(String name)::获取指定名称的成员变量,不考虑修饰符号
    Fileld:成员变量
  • 设置值:void set(Object obj,Object value)
  • 操作值:void get (Object obj)
  • 忽略访问权限:setAccessible(true)
package com.zhxd.test;

/*
 * author zhxd
 * ClassName Test01
 */

import java.lang.reflect.Field;

public class Test01 {
    public static void main(String[]args) throws NoSuchFieldException, IllegalAccessException {
        Class personClass = Person.class;
        //01获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();//->public修饰的成员变量会被获取到。
        Field field = personClass.getField("name");
        //获取成员变量a的值
        Person p = new Person("zhxd", "female", 20);
        System.out.println( field.get(p));
        //设置p的a变量值
        field.set(p,"张三");
        //获取所有的成员变量
        Field[] declaredFields = personClass.getDeclaredFields();
        Field d  = personClass.getDeclaredField("age"); //访问私有属性会报错,但是可以忽略权限限制。
        d.setAccessible(true);//暴力反射
        Object value2 = d.get(p); //-->null
    }
}

class Person {
    public String name;
    private String sex;
    private int age;

    Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
  1. 获取构造方法
  • Constructor[] getConstructors():获取所有用public进行修饰的构造方法
  • Constructor getConstructor(类... parameterTypes):获取指定参数的public修饰的构造方法
  • Constructor[] getDeclaredConstructors():获取所有构造方法
  • Constructor getDeclaredConstructor(类... parameterTypes):获取指定的构造方法
    Constructor:构造方法
  • T newInstance(Object ...initargs)
  • Object person1 = personClass.newInstance():实例化对象
package com.zhxd.test;

/*
 * author zhxd
 * ClassName Test01
 */

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

public class Test01 {
    public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Person> personClass = Person.class;
        //1. 获取构造方法
        Constructor<Person> constructor = personClass.getConstructor(String.class, String.class, int.class);
        //2. 创建对象
        Person person = (Person)constructor.newInstance("zhxd", "female",  20);
        //空参构造简写
        Person person1 = (Person)personClass.newInstance();
    }
}

class Person {
    public String name;
    private String sex;
    private int age;

    public Person () {}

    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
  1. 获取成员方法
  • Method[] getMethods():获取所有public修饰的成员方法
  • Method getMethod(String name,类... parameterTypes):获取指定名称的public修饰的成员方法
  • Method[] getDeclaredMethods():获取所有*成员方法
  • Method getDeclaredMethod(String name,类... parameterTypes):获取指定名称的成员方法
    Method:方法对象
  • Object invoke(Object obj,Object ...args):执行方法
  • String getName():获取方法名称
    Java SE进阶注解和反射_第8张图片
package com.zhxd.test;

/*
 * author zhxd
 * ClassName Test01
 */

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

public class Test01 {
    public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Person> personClass = Person.class;
        //1. 获取构造方法
        Constructor<Person> constructor = personClass.getConstructor(String.class, String.class, int.class);
        //2. 创建对象
        Person person = (Person)constructor.newInstance("zhxd", "female",  20);
        //3. 获取eat方法
        Method eatMethod = personClass.getMethod("eat",String.class);
        //4. 执行eat方法
        eatMethod.invoke(person, "水果");
    }
}

class Person {
    public String name;
    private String sex;
    private int age;

    public Person () {}

    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

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

    public void eat(String food) {
        System.out.println("The" + " "+ name + " " + "eat" + " " + food);
    }
}
  1. 获取类名:
    String getName()
public static void main(String[]args) {
 Class<Person> personClass = Person.class;
    String className = personClass.getName();
    System.out.println(className);
}

2.5反射和普通方法创建对象性能测试:

package com.zhxd.test;
/*
 * author zhxd
 * ClassName Test06
 * date 2022/12/31 16:10
 */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test06 {
    //普通方法
    public static void test01() {
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法执行10亿次:" + (endTime - startTime) + "ms");
    }

    //反射
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c = user.getClass();
        Method getName = c.getMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射执行10亿次:" + (endTime - startTime) + "ms");
    }

    //反射,关闭安全检测
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c = user.getClass();
        Method getName = c.getMethod("getName", null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭检测后执行10亿次:" + (endTime - startTime) + "ms");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }
}

结果:
普通方法执行10亿次:5ms
反射执行10亿次:2761ms
关闭检测后执行10亿次:1491ms

2.6通过反射操作注解

getAnnotations:获取注解
getAnnotation:获取指定注解
注解对象.value:获取注解的值

package com.zhxd.test;
/*
 * author zhxd
 * ClassName Test07
 * date 2022/12/31 16:39
 */

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

public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c = Class.forName("com.zhxd.test.Student2");
        //通过反射获得注解
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation); //@com.zhxd.test.TableZhxd(value=db_student)
        }

        //获得注解的value值
        TableZhxd tableZhxd = (TableZhxd) c.getAnnotation(TableZhxd.class);
        String value = tableZhxd.value();
        System.out.println(value);// db_student

        //获取字段的注解
        Field f = c.getDeclaredField("id");
        FieldZhxd annotation = f.getAnnotation(FieldZhxd.class);
        System.out.println(annotation.columnName());//db_id
        System.out.println(annotation.type());//int
        System.out.println(annotation.length());//10
    }
}

@TableZhxd(value = "db_student")
class Student2 {
    @FieldZhxd(columnName = "db_id", type="int", length=10)
    private int id;
    @FieldZhxd(columnName = "db_type", type="int", length=10)
    private int age;
    @FieldZhxd(columnName = "db_length", type="varchar", 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 TableZhxd {
    String value();
}

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

你可能感兴趣的:(java,java)