Java——反射详解(边边奋斗史)

类的形成

1.(加载)先将Class文件字节码 加载到内存,并将这些静态数据转换成方法区运行时的数据结构,然后生成一个代表这个类的 java.lang.Class 类对象

方法区:(包含在内的元素)

  • 静态方法
  • 静态变量
  • 常量池 -->类名、变量名、方法名,常量(final)
  • 代码

2.(连接)将JAVA类二进制代码合并到JVM的运行状态之中的过程

  • 1、 (验证) 验证信息完整性、规范性(JVM规范) 和 安全性
  • 2、 (准备) 正式为类变量(static)分配内存并设置类变量的默认值的阶段,这些空间都将在方法区中进行分配
  • 3、 (解析) 虚拟机常量池中的符号引用(常量名) 都将替换为真正的引用(地址)(指针)的过程。

3.(初始化) 执行类构造器()——(这里要区别对象构造器),,

  • 1、 < clinit >()方法 会将所有类变量赋值。
  • 2、 < clinit >()方法 会将所有的 静态(static)代码合并 。
  • 3、 当初始化一个类的时候发现他的父类没有被初始化,会先调用它父类的 类初始化。
  • 4、 虚拟机会保证一个类的()方法 在多线程下 被 正确的加锁 和 同步。

代码详情:

package reflection;

/**
 * @ClassName ReflectionTest_1
 * @Description
 * @Author SkySong
 * @Date 2020-09-27 20:42
 */
public class ReflectionTest_1 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.a);
    }
    /**
     * 1.(加载)先将Class文件字节码 加载到内存,并将这些静态数据转换成方法区运行时的数据结构,然后生成一个代表这个类的 java.lang.Class 类对象
     *      方法区-->
     *              静态方法
     *              静态变量
     *              常量池 -->类名、变量名、方法名,常量(final)
     *              代码
     * 2.(连接)将JAVA类二进制代码合并到JVM的运行状态之中的过程
     *      1>(验证) 验证信息完整性、规范性(JVM规范) 和 安全性
     *      2>(准备) 正式为类变量(static)分配内存并设置类变量的默认值的阶段,这些空间都将在方法区中进行分配
     *      3>(解析) 虚拟机常量池中的符号引用(常量名) 都将替换为真正的引用(地址)(指针)的过程。
     * 3.(初始化) 执行类构造器<clinit>()——(这里要区别对象构造器),,
     *      1> <clinit>()方法 会将所有类变量赋值。
     *      2> <clinit>()方法 会将所有的 静态(static)代码合并 。
     *      3> 当初始化一个类的时候发现他的父类没有被初始化,会先调用它父类的 类初始化。
     *      4> 虚拟机会保证一个类的<clinit>()方法 在多线程下 被 正确的加锁 和 同步。
     */
}

class A{
    static {
        System.out.println("A类静态代码块初始化");
        a = 300;
    }
    static int a = 100;

    /**
     * 静态代码合并
     *          System.out.println("A类静态代码块初始化");
     *          a = 300;
     *          int a = 100;
     */

    public A(){
        System.out.println("A类的无参构造初始化");
    }
}

执行结果:

A类静态代码块初始化
A类的无参构造初始化
100

Process finished with exit code 0

类的加载

package reflection;

/**
 * @ClassName ReflectionTest_2
 * @Description
 * @Author SkySong
 * @Date 2020-09-27 21:37
 */
public class ReflectionTest_2 {
    static {
        System.out.println("main方法类静态代码块的初始化");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //主动引用
        /**
         * 当检测到父类没有被加载时,会先加载父类
         */
        Sun sun = new Sun();
        //利用反射
        Class.forName("reflection.Sun");

        //不会触发子类加载
        // 利用子类去调用父类的变量
        System.out.println(Sun.name);
        //创建数组
        /**
         * array 会在常量池中找到(无需加载类)
         * Sun[5] 只是分配了 5块空间,并没有初始化。
         */
        Sun[] array = new Sun[5];
        //调用类中的常量也不会初始化类
        System.out.println(Sun.sum);
    }
}

class Father{
    static {
        System.out.println("Father类静态代码块的初始化");
    }
    static String name = "father";
}

class Sun extends Father{
    static {
        System.out.println("Sun类静态代码块的初始化");
    }

    static final int sum = 10;
}

执行结果:

main方法类静态代码块的初始化
Father类静态代码块的初始化
Sun类静态代码块的初始化
father
10

Process finished with exit code 0

具体可以参照:JVM——类加载器

获取类信息

package reflection;

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

/**
 * @ClassName ReflectionTest_4
 * @Description 获得类的信息
 * @Author SkySong
 * @Date 2020-09-28 21:23
 */
public class ReflectionTest_4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("reflection.User");
        //获得类的名字
        System.out.println(c1.getName());//包名 + 类名
        System.out.println(c1.getSimpleName());//类名
        //获得类的属性
        Field[] fields = c1.getFields();
        for (Field field:fields){
            //无法打印出来,,因为getFields() 方法只能找到 public 的属性
            System.out.println(field.getName());
        }
        //getDeclaredFields() 方法可以找到 所有权限的 属性
        Field[] fields1 = c1.getDeclaredFields();
        for (Field field:fields1){
            System.out.println(field);
        }

        //获得指定属性
        System.out.println(c1.getDeclaredField("name").getName());

        /**
         * =========================================================
         */
        System.out.println("========================================");
        //获得类的方法
        /**
         * 获得类 及其 父类的 全部 public 方法
         */
        Method[] methods = c1.getMethods();
        for (Method method:methods){
            System.out.println("正常的:"+ method);
        }
        /**
         * 获得 本类的 所有方法
         */
        Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method method:declaredMethods){
            System.out.println("declare的:"+method);
        }
        System.out.println("==========================================");
        //获得指定方法
        /**
         * 需要将参数类型也传入,是因为方法有重载的特性。(需要参数列表来做区分)
         */
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得所有的构造器
        System.out.println("===========================================");
        /**
         * 获得 本类的 public 构造器方法
         */
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor:constructors){
            System.out.println(constructor);
        }
        /**
         * 获得 本类的 所有 构造器方法
         */
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("#"+ declaredConstructor);
        }

        System.out.println();
        //获得指定的构造器
        Constructor constructor = c1.getConstructor(null);
        System.out.println(constructor);
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, String.class);
        System.out.println("#"+ declaredConstructor);

    }
}

执行结果:

reflection.User
User
private java.lang.String reflection.User.name
private int reflection.User.age
private java.lang.String reflection.User.career
name
========================================
正常的:public java.lang.String reflection.User.toString()
正常的:public java.lang.String reflection.User.getName()
正常的:public void reflection.User.setName(java.lang.String)
正常的:public java.lang.String reflection.User.getCareer()
正常的:public int reflection.User.getAge()
正常的:public void reflection.User.setAge(int)
正常的:public void reflection.User.setCareer(java.lang.String)
正常的: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()
declare的:public java.lang.String reflection.User.toString()
declare的:public java.lang.String reflection.User.getName()
declare的:public void reflection.User.setName(java.lang.String)
declare的:public java.lang.String reflection.User.getCareer()
declare的:private void reflection.User.privateMethod()
declare的:public int reflection.User.getAge()
declare的:public void reflection.User.setAge(int)
declare的:public void reflection.User.setCareer(java.lang.String)
==========================================
public java.lang.String reflection.User.getName()
public void reflection.User.setName(java.lang.String)
===========================================
public reflection.User()
public reflection.User(java.lang.String,int,java.lang.String)
#public reflection.User()
#public reflection.User(java.lang.String,int,java.lang.String)

public reflection.User()
#public reflection.User(java.lang.String,int,java.lang.String)

Process finished with exit code 0

构建对象

package reflection;

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


/**
 * @ClassName ReflectionTest_5
 * @Description
 * @Author SkySong
 * @Date 2020-09-28 23:05
 */
public class ReflectionTest_5 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class<?> userClass = Class.forName("reflection.User");
        //创建一个对象
        User user = (User) userClass.newInstance();//本质上是掉用无参构造器
        System.out.println(user);

        //利用构造器 创建对象
        Constructor<?> userClassDeclaredConstructor = userClass.getDeclaredConstructor(String.class, int.class, String.class);

        User user1 = (User) userClassDeclaredConstructor.newInstance("Sky", 23, "god");
        System.out.println(user1);

        //通过反射调用方法
        User user2 = (User) userClass.newInstance();
        Method setName = userClass.getMethod("setName", String.class);
        //invoke():激活
        //invoke(对象,"方法对应的参数")
        setName.invoke(user2,"btg");

        System.out.println(user2.getName());

        //通过反射操作属性
        User user3 = (User) userClass.newInstance();
        Field name = userClass.getDeclaredField("name");
        /**
         * 不能直接操作私有属性,需要关闭他的安全检测
         * 可以提高反射的性能
         */
        name.setAccessible(true);//取消他的安全检测
        name.set(user3,"边边");

        System.out.println(user3);
    }
}

执行结果:

User{name=‘null’, age=0, career=‘null’}
User{name=‘Sky’, age=23, career=‘god’}
btg
User{name=‘边边’, age=0, career=‘null’}

Process finished with exit code 0

附上User类:
全程都是用的这个 User类

package reflection;

/**
 * @ClassName User
 * @Description
 * @Author SkySong
 * @Date 2020-09-28 21:25
 */
public class User {
    private String name;
    private int age;
    private String career;//职业
    //无参构造
    public User(){}

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

    private void privateMethod(){
        System.out.println("这是一个私有方法!!");
    }

    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;
    }

    public String getCareer() {
        return career;
    }

    public void setCareer(String career) {
        this.career = career;
    }

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

性能分析( setAccessible(true) )

setAccessible(true) 是关闭安全检测。可以提高反射的构建效率。

package reflection;

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

/**
 * @ClassName ReflectionTest_6
 * @Description 性能分析
 * @Author SkySong
 * @Date 2020-09-29 21:56
 */
public class ReflectionTest_6 {
    //直接获取对象
    public static void test_1(){
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("直接获取对象,getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
    }
    //反射获取对象
    public static void test_2() throws Exception {
        Class<?> userClass = Class.forName("reflection.User");
        User user = (User) userClass.newInstance();
        Method getName = userClass.getDeclaredMethod("getName");
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射获取对象,getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
    }
    //反射获取对象 (关闭安全检测)—— setAccessible(true)
    public static void test_3() throws Exception {
        Class<?> userClass = Class.forName("reflection.User");
        User user = (User) userClass.newInstance();
        Method getName = userClass.getDeclaredMethod("getName");
        getName.setAccessible(true);//关闭安全检测
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射获取对象(关闭安全检测),getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws Exception {
        test_1();
        test_2();
        test_3();
    }
}

执行结果:

直接获取对象,getName()方法跑10亿次所需:5ms
反射获取对象,getName()方法跑10亿次所需:3015ms
反射获取对象(关闭安全检测),getName()方法跑10亿次所需:1370ms

Process finished with exit code 0

反射获取注解

package reflection;

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

/**
 * @ClassName ReflectionTest_7
 * @Description
 * @Author SkySong
 * @Date 2020-09-29 23:23
 */
public class ReflectionTest_7 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        //这里的泛型化 可以避免 后续的强转
        Class<?> studentClass = Class.forName("reflection.Student");
        //通过反射获得注解
        Annotation[] annotations = studentClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解 value 的值
        table annotationValue = studentClass.getAnnotation(table.class);
        String table = annotationValue.table();
        System.out.println(table);

        //获得指定属性的 注解值
        Field name = studentClass.getDeclaredField("name");
        field f = name.getAnnotation(field.class);
        System.out.println(f.column());
        System.out.println(f.length());
        System.out.println(f.type());

    }
}

/**
 * 类(Class)的注解
 */
//运行时
@Retention(RetentionPolicy.RUNTIME)
//TYPE(class) METHOD(方法) FIELD(属性)
@Target({ElementType.TYPE})
@interface table{
    String table();
}

/**
 * 属性的注解
 */
@Retention(RetentionPolicy.RUNTIME)
//TYPE(class) METHOD(方法) FIELD(属性)
@Target({ElementType.FIELD})
@interface field{
    String column();
    String type();
    int length();
}

@table(table = "db_student")
class Student{
    @field(column = "student_id",type = "int",length = 10)
    private int id;
    @field(column = "student_name",type = "varchar2",length = 32)
    private String name;
    @field(column = "student_age",type = "int",length = 10)
    private int age;

    public Student(){}

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

执行结果:

@reflection.table(table=db_student)
db_student
student_name
32
varchar2

Process finished with exit code 0

总结

反射是通过 " 非直接手段 " 去获取类的信息,我们把 类 比作 印刷 对象模子,有了这个模子,我们便可以 印刷 对象

Java有了反射机制,就有了动态性。但这也降低了安全性。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值