熬夜刚完的注解与反射

Posted 野生java研究僧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了熬夜刚完的注解与反射相关的知识,希望对你有一定的参考价值。

1.反射的概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

反射是比较重要的一个知识,现在的大多数框架都使用得到了反射+注解的形式,对我们的程序进行封装,让我们开箱即用,大大的减少了我们的开发时间,提升了我们的开发效率,使用反射+注解使得我们的程序变得更加的灵活多变

反射就是把java类中的属性和方法映射成与之对应的Java对象,一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把这些组成一个完整类的成员,拆分为一个一个的java对象。

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是说jvm中每个实例都应该属于某个Class对象与之对应。(包括基本数据类型)
Class 没有公共构造方法Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

**我们来看下Class类的一些方法:**当然太多,等下挑常用的讲

Modifier and TypeMethod and Description
<U> 类<? extends U>asSubclass(类<U> clazz) 这个 对象来表示由指定的类对象表示的类的子类。
Tcast(Object obj) 施放一个目的是通过本表示的类或接口 对象。
booleandesiredAssertionStatus() 如果要在调用此方法时初始化该类,则返回将分配给此类的断言状态。
static 类<?>forName(String className) 返回与给定字符串名称的类或接口相关联的 对象。
static 类<?>forName(String name, boolean initialize, ClassLoader loader) 使用给定的类加载器返回与给定字符串名称的类或接口相关联的 对象。
AnnotatedType[]getAnnotatedInterfaces() 返回一个 AnnotatedType对象的数组, AnnotatedType使用类型指定由此 AnnotatedType对象表示的实体的超级
AnnotatedTypegetAnnotatedSuperclass() 返回一个 AnnotatedType对象,该对象表示使用类型来指定由此 对象表示的实体的 类。
<A extends Annotation>AgetAnnotation(类<A> annotationClass) 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。
Annotation[]getAnnotations() 返回此元素上 存在的注释。
<A extends Annotation>A[]getAnnotationsByType(类<A> annotationClass) 返回与此元素相关 联的注释
StringgetCanonicalName() 返回由Java语言规范定义的基础类的规范名称。
类<?>[]getClasses() 返回包含一个数组 表示所有的公共类和由此表示的类的成员接口的对象 对象。
ClassLoadergetClassLoader() 返回类的类加载器。
类<?>getComponentType() 返回 数组的组件类型的Class。
Constructor<T>getConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 函数。
Constructor<?>[]getConstructors() 返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 对象。
<A extends Annotation>AgetDeclaredAnnotation(类<A> annotationClass) 如果这样的注释 直接存在 ,则返回指定类型的元素注释,否则返回null。
Annotation[]getDeclaredAnnotations() 返回 直接存在于此元素上的注释。
<A extends Annotation>A[]getDeclaredAnnotationsByType(类<A> annotationClass) 如果此类注释 直接存在或 *间接存在,*则返回该元素的注释(指定类型)。
类<?>[]getDeclaredClasses() 返回一个反映所有被这个 对象表示的类的成员声明的类和 对象的数组。
Constructor<T>getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 函数。
Constructor<?>[]getDeclaredConstructors() 返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组
FieldgetDeclaredField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 对象。
Field[]getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的所有字段 对象。
方法getDeclaredMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 对象。
方法[]getDeclaredMethods() 返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
类<?>getDeclaringClass() 如果由此 对象表示的类或接口是另一个类的成员,则返回表示其声明的类的 对象。
类<?>getEnclosingClass() 返回底层类的即时封闭类。
Constructor<?>getEnclosingConstructor() 如果此对象表示构造函数中的本地或匿名类,则返回表示底层类的立即封闭构造函数的Constructor对象。
方法getEnclosingMethod() 如果此对象表示方法中的本地或匿名类,则返回表示基础类的即时封闭方法的方法对象。
T[]getEnumConstants() 返回此枚举类的元素,如果此Class对象不表示枚举类型,则返回null。
FieldgetField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 对象。
Field[]getFields() 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 对象。
Type[]getGenericInterfaces() 返回 Type表示通过由该对象所表示的类或接口直接实现的接口秒。
TypegetGenericSuperclass() 返回 Type表示此所表示的实体(类,接口,基本类型或void)的直接超类
类<?>[]getInterfaces() 确定由该对象表示的类或接口实现的接口。
方法getMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 对象。
方法[]getMethods() 返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 对象,包括那些由类或接口和那些从超类和超接口继承的声明。
intgetModifiers() 返回此类或接口的Java语言修饰符,以整数编码。
StringgetName() 返回由 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String
软件包getPackage() 获取此类的包。
ProtectionDomaingetProtectionDomain() 返回 ProtectionDomain
URLgetResource(String name) 查找具有给定名称的资源。
InputStreamgetResourceAsStream(String name) 查找具有给定名称的资源。
Object[]getSigners() 获得这个类的签名者。
StringgetSimpleName() 返回源代码中给出的基础类的简单名称。
类<? super T>getSuperclass() 返回 表示此所表示的实体(类,接口,基本类型或void)的超类
StringgetTypeName() 为此类型的名称返回一个内容丰富的字符串。
TypeVariable<类<T>>[]getTypeParameters() 返回一个 TypeVariable对象的数组,它们以声明顺序表示由此 GenericDeclaration对象表示的通用声明声明的类型变量。
booleanisAnnotation() 如果此 对象表示注释类型,则返回true。
booleanisAnnotationPresent(类<? extends Annotation> annotationClass) 如果此元素上 存在指定类型的注释,则返回true,否则返回false。
booleanisAnonymousClass() 返回 true当且仅当基础类是匿名类时。
booleanisArray() 确定此 对象是否表示数组类。
booleanisAssignableFrom(类<?> cls) 确定由此 对象表示的类或接口是否与由指定的Class 表示的类或接口相同或是超类或 接口。
booleanisEnum() 当且仅当该类在源代码中被声明为枚举时才返回true。
booleanisInstance(Object obj) 确定指定的Object是否与此 Object表示的对象分配
booleanisInterface() 确定指定 对象表示接口类型。
booleanisLocalClass() 返回 true当且仅当基础类是本地类时。
booleanisMemberClass() 返回 true当且仅当基础类是成员类时。
booleanisPrimitive() 确定指定 对象表示一个基本类型。
booleanisSynthetic() 如果这个类是一个合成类,返回true ; 返回false其他。
TnewInstance() 创建由此 对象表示的类的新实例。
StringtoGenericString() 返回描述此 的字符串,包括有关修饰符和类型参数的信息。
StringtoString() 将对象转换为字符串。

2.反射基本使用

User:案例类

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-23-0:00
 * @Version:1.0
 * @Description:
 */
public class User {

    private int id;
    private int age;
    private String name;
    private String sex;

    public static List<User> getUserList(){
        List<User> userList = new ArrayList<>();
        userList.add(new User(1,29,"小明","男"));
        userList.add(new User(2,21,"小王","男"));
        userList.add(new User(3,18,"小李","女"));
        userList.add(new User(4,23,"小华","女"));
        userList.add(new User(7,50,"小花","女"));
        userList.add(new User(5,50,"小k","男"));
        userList.add(new User(6,60,"小浪","女"));

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

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

    }
    public String getSex() {
        return sex;
    }

    public void setSex(int id) {
        this.sex = sex;
    }
    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 "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\\'' +
                '}';
    }

    /**
     *  获取一个User对象
     * @return
     */
    public User getUser(){
        return new User(1,29,"小明","男");
    }

}

1.获取Class的三种方法

// 1.使用Object的方法getClass(),Object是所有类的父类,那么任何一个对象,都应该有getClass()方法
        User u = new User();
        Class<? extends User> uClass = u.getClass();

//2.任何数据类型都包含了一个class属性,类型.class的方式
        Class<User> aClass = User.class;
        
//3.常用的 Class.classFrom(String arg),传递一个String类型的从类路径到该类的具体路径
// Class.forName("test.User") : 这个代码会导致我们的静态代码块加载,如果只是想执行某个类的静态代码块,那么可以使用该方法
        Class<?> bClass = Class.forName("test.User");

获取到某个类的Class对象有什么用?

我们可以通过该类的class对象,通过newInstance() 方法对该类进行实例化,不用我们手动去new,注意该方法,默认调用的是无参构造方法,如果一个类没有任何构造方法,默认有一个无参构造,如果你重写了有参构造,记得无参构造一定要带上,否则newInstance() 方法将创建对象失败。

User user = (User)bClass.newInstance();

2.通过反射获取构造方法

   @Test
    void test1() throws Exception{
// 获取共有的构造方法(public进行修饰的方法),并且返回一个 Constructor数组
        Constructor<?>[] constructors = User.class.getConstructors();
        for (Constructor constructor: constructors){
            System.out.println(constructor);
        }
        System.out.println("----------------------------------------------");

// 获取指定某个构造方法,不传递任何参数,默认获取无参构造,如果要获取有参的需要跟上参数类型,必须和构造方法中参数顺序一致
        Constructor<User> constructor1 = User.class.getConstructor(); // 获取无参构造
        System.out.println("无参构造="+constructor1);

        System.out.println("----------------------------------------------");

        Constructor<User> constructor2 = User.class.getConstructor(String.class); // 获取有参构造 User(String name)
        System.out.println("有参构造="+constructor2);

        System.out.println("----------------------------------------------");

// 获取私有、受保护、默认、公有的构造方法,并且返回一个 Constructor数组
        Constructor<?>[] dc1 = User.class.getDeclaredConstructors();
        for (int i = 0; i < dc1.length; i++) {
            System.out.println("private="+dc1[i]);
        }

        System.out.println("----------------------------------------------");

// 获取私有、受保护、默认、公有的构造方法,获取单个的(自定义)
        Constructor dc2 = User.class.getDeclaredConstructor(int.class,String.class);
        System.out.println(dc2);

// 如果该构造方法是私有的,不能直接进行访问,需要先设置为可访问的
        if (!dc2.isAccessible()){ // 先判断该方法是否可以进行访问,如果不可以,进行修改,设置为可访问的
            dc2.setAccessible(true); // 将private修饰的方法修饰为可访问的
        }
// 调用 获取到的构造方法,可以跟参数(不过要和获取到的构造方法中的参数对应,否则抛出:IllegalArgumentException)
        User user1 = (User)dc2.newInstance(1, "张三");
        System.out.println("name="+user1.getName());

    }

3.通过反射获取到属性字段

 @Test // 通过class对象获取到属性
    void test2() throws Exception{
        // 获取到User类中的所有(公共)属性 ,返回一个 Field[]数组
        Field[] fields = User.class.getFields();
        for (Field field : fields) {
            System.out.println("filed = "+field);
        }

        System.out.println("----------------------------------------");

        // 获取到User类中单个属性,返回一个Field对象
        Field emailFiled = User.class.getField("email");
        System.out.println("emailFiled = "+emailFiled);

        System.out.println("----------------------------------------");

        // 获取到User类中的所有属性(私有、受保护、默认)
        Field[] df1 = User.class.getDeclaredFields();
        for (Field field : df1) {
            System.out.println("field = "+field);
        }

        System.out.println("----------------------------------------");

        // 获取到User类中的单个的属性(私有、受保护、默认)
        Field emailAttributes = User.class.getDeclaredField("email");
        System.out.println("emailAttributes ="+emailAttributes);

        System.out.println("----------------------------------------");

        // 通过反射实例化一个对象,并且获取到该类中的字段(email),并且给其赋值
        Class<User> userClass = User.class; // 获得一个User.class对象
        User user = userClass.newInstance();
        Field[] declaredFields = userClass.getDeclaredFields(); // 获取到user类中所有的属性
        for (int i = 0; i < declaredFields.length; i++) { // 遍历User类中所有的属性,找到email属性,为其赋值
          if (declaredFields[i].toString().contains("email")){
              declaredFields[i].setAccessible(true);//设置为可访问的,以免程序出错
              declaredFields[i].set(user,"admin@qq.com");
          }
        }
        System.out.println(user.email);
    }

4.通过反射获取方法



    @Test // 同过class对象获取到类中的所有方法,以及调用方法
    void test3() throws Exception{

        // 获取到User类中所有的public方法,包括父类的
        Method[] methods = User.class.getMethods();
        for (Method method : methods) {
            System.out.println(" method = "+method);
        }

        System.out.println("----------------------------------------");

        // 获取到User类中单个的public方法,包括父类的
        Method equals = User.class.getMethod("equals", Object.class);
        System.out.println("equals ="+equals);

        System.out.println("----------------------------------------");

        // 获取到User类中所有的(私有、受保护、默认)方法
        Method[] methods2 = User.class.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(" method = "+method);
        }

        Day17-注解与反射

注解与反射

注解与反射

理解Android中的注解与反射

Java 注解与反射 基础

反射与注解的使用