7.注解和反射机制

本文详细介绍了Java的反射机制,包括如何通过反射获取类的内部信息,如何使用类加载器,以及如何获取和操作类的成员变量、方法和构造器。此外,还讨论了普通调用与反射调用的性能差异以及如何通过反射获取注解。
摘要由CSDN通过智能技术生成

注解和反射机制

1反射

反射是java被视为动态语言的关键,反射机制允许程序在执行期通过反射有关操作获得任何类的内部信息,直接操作任意对象的内部变量及方法。
加载完类之后,在堆内存方法区产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,可以通过该对象看到类的结构,所以形象的称之为:反射
正常方式:引入需要的类->通过new实例化->获得实例化对象进行操作
反射方式:实例化对象->getclass方法->得到完整的类消息

在这里插入图片描述

1.1获得类的class对象方法

public static void main(String[] args) throws Exception {
 //1.通过全包名获得Person类的class对象
        Class<?> c1 = Class.forName("cn.itcast.domain.Person");
        //2.通过Person类的属性class获得class对象
        Class<Person> c2 = Person.class;
        //3.通过Person类的对象.getClass():
        Person person = new Person();
        Class<? extends Person> c3 = person.getClass();
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        //4.通过Person类的class对象获得他的父类对象
        Class<?> superclass = c1.getSuperclass();
        System.out.println(superclass);
        //5.基本类型的包装类通过TYPE属性获得class对象
        Class<Integer> type = Integer.TYPE;
        System.out.println(type);
    }
}

输出结果:class cn.itcast.domain.Person
class cn.itcast.domain.Person
class cn.itcast.domain.Person
class java.lang.Object
int

2.类加载器

类加载的作用:将class文件字节码加载到内存中,并将这些静态的数据转化成方法区运行时的数据结构,然后在堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。
JVM定义了如下类型的类加载器:
引导类(根)加载器:用C++编写,是JVM自带的类加载器,负责Java平台核心库(rt下的库),用来装载核心类库,该加载器无法直接获取。
拓展类加载器:负责jre/lib/ext目录下的jar包或D java.ext.dirs指定目录下的jar包装入工作库。
系统类加载器:负责Java-classpath或D java.class.path所指的目录下的类与jar包装入工作库,是最常用的加载器。

在这里插入图片描述

public class Demo01OutputStream {
	public static void main(String[] args) throws ClassNotFoundException {
	    //获得系统类加载器(用户加载器)
	    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
	    //获取系统类加载器的父类,即扩展类加载器
	    ClassLoader parentClassLoader = systemClassLoader.getParent();
	    //获得根加载器,但因为根加载器的特殊性,所以返回null
	    ClassLoader rootClassloader = parentClassLoader.getParent();
	
	    System.out.println(systemClassLoader);
	    System.out.println(parentClassLoader);
	    System.out.println(rootClassloader);
	
	    //当前类的加载器是哪个
	    ClassLoader classLoader1 = Class.forName("com.itheima.demo01.OutputStream.Demo01OutputStream").getClassLoader();
	    System.out.println(classLoader1);
	
	    //JDK内置的Object类是哪个加载器加载的
	    ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader();
	    System.out.println(classLoader2);
	
	    //获得系统类加载器可以加载的路径
	    String property = System.getProperty("java.class.path");
	    System.out.println(property);
    }
}

输出结果:jdk.internal.loader.ClassLoaders$AppClassLoader@2f0e140b
jdk.internal.loader.ClassLoaders$PlatformClassLoader@16b98e56
null
jdk.internal.loader.ClassLoaders$AppClassLoader@2f0e140b
null
C:\Users\秋天的思念\Desktop\Java\JavaSE\02-Java语言进阶\day09_字节流、字符流\code\09_IOAndProperties\out\production\09_IOAndProperties

3.获取类运行时结构

Class对象功能:
* 获取功能:
1. 获取成员变量们
* Field[] getFields()
* Field getField(String name)
* * Field[] getDeclaredFields()
* Field getDeclaredField(String name)
* 2. 获取构造方法们
* * Constructor<?>[] getConstructors() * Constructor getConstructor(类<?>… parameterTypes)
* * Constructor getDeclaredConstructor(类<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors()
* 3. 获取成员方法们:
* Method[] getMethods()
* Method getMethod(String name, 类<?>... * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 类<?>…

通过类的class对象用以上方法获取到的成员变量、方法、构造方法等都属于反射的一部分。通过这些Field、Method、Constructor(这三个都是反射包下的类)调用对应方法,然后指定实例化对象(有参的传参),就可以执行该实例化对象对应的操作。
比如一个Method变量 m,这个m属于反射的一部分,m是由class对象获取到的对应类中的方法(比如eat(int x)方法)。通过m.invoke(obj,1)就可以调用实例化对象obj的eat(int x)方法(即obj.eat(1))。从另一个角度来看,相对于不用常规的实例化对象去调用方法,而采用反射(一面镜子)获得该方法m,然后m就是eat(int x)方法的反射,就可以执行任意实例化对象的eat(int x)方法。
注意: Field,Constructor,Method都有setAccessible()方法,设置为true表示可以操作被private修饰的成员变量、方法、构造器。
用一个例子来看:
package cn.itcast.reflect;

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

public class Test {
    public static void main(String[] args) throws Exception{
        //通过类.class获得T的class对象进行操作
        Class<T> t_class = T.class;
        //获取T类的全类名
        System.out.println(t_class.getName());//cn.itcast.reflect.T
        //获取T类的类名
        System.out.println(t_class.getSimpleName());//T

        //获取public修饰的属性(即成员变量)
        Field field1 = t_class.getField("x");
        //获取该属性的名称
        System.out.println(field1.getName());//x
        //获取任何修饰符的属性
        Field[] declaredFields = t_class.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());//x  y
        }

        //获取T类public修饰的成员方法,第一个参数要要获取的方法名,第二参数是该方法参数类型的class对象
        Method setx = t_class.getMethod("setX", int.class);
        System.out.println(setx.getName());//setX
        //执行new T().setX(4)
        setx.invoke(new T(), 4);   //调用了setX方法
        //获取本类任何修饰符的成员方法,而getMethods()是获得本类和父类的所有public方法
        Method[] declaredMethods = t_class.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());//method  setX  getX  getY  setY
        }

        //获取T类和父类pbulic修饰的所有构造器
        Constructor<?>[] constructors = t_class.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);//public cn.itcast.reflect.T()   public cn.itcast.reflect.T(int,int)
        }
        //获取T类的任何修饰符的构造器
        Constructor<?>[] declaredConstructors = t_class.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);//public cn.itcast.reflect.T()   public cn.itcast.reflect.T(int,int)
        }
        System.out.println(t_class.getConstructor(int.class, int.class).newInstance(1, 2)); //T{x=1, y=2}
    }
}

class T{
    public int x;
    private int y;

    public T() {
    }

    public T(int x, int y) {
        this.x = x;
        this.y = y;
    }

    private void method(){
        System.out.println("私有方法");
    }

    public int getX() {
        System.out.println("调用了getX方法");
        return x;
    }

    public void setX(int x) {
        this.x = x;
        System.out.println("调用了setX方法");
    }

    public int getY() {
        System.out.println("调用了getY方法");
        return y;
    }

    public void setY(int y) {
        this.y = y;
        System.out.println("调用了setY方法");
    }

    @Override
    public String toString() {
        return "T{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

4.普通方式调用,反射方式调用以及setAccessible性能分析

package cn.itcast.reflect;

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception{
        method1();
        method2();
        method3();
    }

    //普通方式调用方法
    public static void method1(){
        T t = new T();

        long starttime = System.currentTimeMillis();
        for (int i = 0; i < 100_000_000; i++)
            t.getName();
        long lasttime = System.currentTimeMillis();

        System.out.println("普通方式调用方法共执行了:" + (lasttime-starttime) + "ms");
    }
    //反射方式调用方法
    public static void method2() throws Exception {
        T t = new T();
        Class<? extends T> aClass = t.getClass();
        Method getname = aClass.getMethod("getName");

        long starttime = System.currentTimeMillis();
        for (int i = 0; i < 100_000_000; i++)
            getname.invoke(t);
        long lasttime = System.currentTimeMillis();

        System.out.println("反射方式调用方法共执行了:" + (lasttime-starttime) + "ms");
    }
    //反射方式调用,设置setAccessible(true)
    public static void method3() throws Exception {
        T t = new T();
        Class<? extends T> aClass = t.getClass();
        Method getname = aClass.getMethod("getName");
        getname.setAccessible(true);

        long starttime = System.currentTimeMillis();
        for (int i = 0; i < 100_000_000; i++)
            getname.invoke(t);
        long lasttime = System.currentTimeMillis();

        System.out.println("反射方式调用(设置setAccessible(true))调用方法共执行了:" + (lasttime-starttime) + "ms");
    }
}

class T{
    public String name;

    public T(){
    }

    public String getName() {
        return name;
    }
}

输出结果:
普通方式调用方法共执行了:5ms
反射方式调用方法共执行了:496ms
反射方式调用(设置setAccessible(true))调用方法共执行了:199ms

5.通过反射获得注解

package cn.itcast.reflect;

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

public class Test {
    public static void main(String[] args) throws NoSuchFieldException {
        //通过sduent的class对象获取类上的注解(即通过反射获得注解),并获得注解属性的值
        Class<sduent> sduentClass = sduent.class;
        Table annotation = sduentClass.getAnnotation(Table.class);
        System.out.println(annotation.value()); //db_st

        //通过class获得sduent的id成员变量的反射对象field
        Field field = sduentClass.getDeclaredField("id");
        //通过反射对象field获取id成员变量上注解,并获注解各个属性的值
        field annotation1 = field.getAnnotation(field.class);
        System.out.println(annotation1.columnmame()); //id
        System.out.println(annotation1.type()); //int
        System.out.println(annotation1.length()); //10
    }
}

@Table("db_st")
class sduent {
    @field(columnmame = "id", type = "int", length = 10)
    private int id;
    @field(columnmame = "age", type = "int", length = 6)
    private int age;
    @field(columnmame = "name", type = "varchar", length = 3)
    private String name;

    public sduent() {
    }

    public sduent(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 "sduent{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

//类的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}
//成员变量的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface field{
    String columnmame();
    String type();
    int length();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值