编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

Java 反射详解,重要方法解析 java反射的步骤原理

gowuye 2024-04-04 11:57 8 浏览 0 评论

概念

1.反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。

2.反射可以在一个类运行的时候获取类的信息的机制,可以获取在编译期不可能获得的类的信息。

3.对于任意一个对象,都能调用它的任意一个方法和属性。

4.因为类的信息是保存在Class对象中的,而这个Class对象是在程序运行时被类加载器(ClassLoader)动态加载的。

5.当类加载器装载运行了类后,动态获取Class对象的信息以及动态操作Class对象的属性和方法的功能称为Java语音的反射机制。

作用:

1.反编译:.class —> .java。

2.通过反射机制访问Java对象中的属性、方法、构造方法等。

反射原理

Java反射的原理:java类的执行需要经历以下过程,



编译:.java文件编译后生成.class字节码文件

加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例

连接:细分三步

验证:格式(class文件规范) 语义(final类是否有子类) 操作

准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。

解析:符号引用转化为直接引用,分配地址

初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。


Java的反射就是利用上面第二步加载到jvm中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。


Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。

总结说:反射就是把java类中的各种成分映射成一个个的Java对象,并且可以进行操作。

获取class的三种方式


Class类主要方法

getName():获得类的完整名字。

getFields():获得类的public类型的属性。

getDeclaredFields():获得类的所有属性。包括private 声明的和继承类

getMethods():获得类的public类型的方法。

getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类

getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。

getConstructors():获得类的public类型的构造方法。

getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。

newInstance():通过类的构造方法创建这个类的一个对象。

代码测试方法:

Person.java 类:


package reflect;

import java.util.Date;

/**
 *
 *
 * @author pine
 */
public class Person {

    private String username;

    private int age;

    private Date birthDay;

    public String nick;

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

    public String getNick() {
        return nick;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

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

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }


    private void sayHello(){
        System.out.println("person sayHello ---");
    }

    public void workIng(){
        System.out.println("person work ing ---");
    }

    @Override
    public String toString() {
        return "Person{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", birthDay=" + birthDay +
                ", nick='" + nick + '\'' +
                '}';
    }
}

ReflectTest.java类:

package reflect;

import com.alibaba.fastjson.JSON;

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

/**
 *
 * 反射
 * @author anzy
 */
public class ReflectTest {



    public static void main(String[] args) {

//       testClassEqual();

        testMethodClass();

    }

    public static void testClassEqual(){
        //1、对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
        //??类型的对象,而我不知道你具体是什么类,用这种方法
        Person person = new Person();

        Class c1 = person.getClass();

        //2、通过类名.class 方式获取,此方法最为安全可靠,性能高
        //  这说明任何一个类都有一个隐含的静态成员变量 class
        Class c2 = Person.class;

        //3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
        //   但可能抛出 ClassNotFoundException 异常
        Class c3 = null;
        try {
            c3 = Class.forName("reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println(c1.equals(c2));
        System.out.println(c1.equals(c3));
        System.out.println(c3.equals(c2));

    }

    public static void testMethodClass(){
        Class c3 = null;
        try {
            c3 = Class.forName("reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("c3.getName():" + c3.getName());
        // 获得类的public类型的属性。
        Field[] fields = c3.getFields();
        System.out.println("c3.getFields():" + JSON.toJSON(fields));
        //输出结果:c3.getFields():[{"accessible":false,"declaredAnnotations":[],"synthetic":false,"annotatedType":
        // {"declaredAnnotations":[],"annotations":[],"type":"java.lang.String"},
        // "enumConstant":false,"name":"nick","annotations":[],"genericType":"java.lang.String",
        // "modifiers":1,"type":"java.lang.String","declaringClass":"reflect.Person"}]
        // 从输出结果可以看到,只拿到了Person类中的nick public属性。
        Field[] fieldsAll = c3.getDeclaredFields();
        System.out.println("c3.getDeclaredFields():" + JSON.toJSON(fieldsAll));

        try {
            // 只能获取public方法,获取private会报错:java.lang.NoSuchMethodException: reflect.Person.sayHello()
            Method method = c3.getMethod("workIng",null);
            System.out.println("method: " + method);
            Method[] methods = c3.getMethods();
            System.out.println("methods: " + methods);
            // public,private 方法都能获取
            Method declaredMethod = c3.getDeclaredMethod("sayHello",null);
            System.out.println("declaredMethod: " + declaredMethod);
            Method[] declaredMethods = c3.getDeclaredMethods();
            System.out.println("declaredMethods: " + declaredMethods);
            // 获取构造函数
            Constructor<Person> constructors[] = c3.getConstructors();
            System.out.println("constructors: " + constructors);
            // JSON.toJSON(constructors) 会报错,栈溢出 Exception in thread "main" java.lang.StackOverflowError
//            System.out.println("constructors: " + JSON.toJSON(constructors));
            // 通过类的构造方法创建这个类的一个对象。
            Person person = constructors[0].newInstance("pine",1);
            System.out.println("person: " + person);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

}


c3.getMethod()拿到的结果:


c3.getDeclaredMethods() 拿到的结果


两个对比可以发现:

getMethods() 能够获取Object类中的public方法。

getDeclaredMethods()获取不到。

让我们引发思考想到了,普通类与Object的关系:

Object类是一切java类的父类,对于普通的java类,即便不声明,也是默认继承了Object类。典型的,可以使用Object类中的toString()方法。

Class能实现的功能

1判断对象属于哪个类

Person person = new Person();

Class class2= person.getClass();

System.out.println("class2:"+class2);

输出:class2:class reflect.Person

2获取类信息

Class class1 = Person.class;

Method[] methods = class1.getMethods();

Method[] declaredMethods = class1.getDeclaredMethods();

Field[] declaredFields = class1.getDeclaredFields();


3构建对象

Person person = new Person();

Class class2= person.getClass();

Object o = class2.newInstance();

//强转前先用instanceof判断

if(o instanceof Person){

((Person) o).workIng();

}


4动态执行方法

Class class1 = Class.forName("reflect.Person");

Method work = class1.getDeclaredMethod("work");

Person person = new Person();

work.invoke(person);


5动态操作属性

Class class1 = Class.forName("reflect.Person");

Person person = new Person();

Field field = class1.getDeclaredField("username");

field.set(person,"pine");

6动态代理


其他:

分享一下与内容有关的思维导图与流程图

反射思维导图:https://www.processon.com/view/link/5e1eb718e4b0169fb52123db
类加载流程图:https://www.processon.com/view/link/5e1eb5f6e4b04e6f9a263797


希望能对大家有帮助,有问题的地方希望大家指正。

能够点个赞转发,关注一下就更好了。

相关推荐

爱上开源之golang入门至实战第四章-切片(Slice)

前言Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可...

Go语言入门必知教程-切片

切片是一种灵活的和可扩展的数据结构,用于实现和管理数据集。切片由多个元素组成,所有元素都是相同类型的。切片是动态数组的一部分,可以根据需要进行增长和收缩。与数组一样,切片也可以索引。切片具有容量和长度...

Go语言基础-切片

切片是什么?切片是Go语言的一种数据结构。和数组相似,不过切片可以在它的结尾增加更多的元素。这样可变长度在实际编程中更为有用。声明切片切片的声明和数组也很相似,只是声明切片时不需要指定大小。例:va...

5分钟掌握GO中切片的基本使用方法

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

揭秘 Go 切片(Slice)的秘密

当向切片添加新参数时,底层数组会发生什么变化?它会扩展以容纳更多元素吗?在这篇文章中,我们将深入探讨切片的内部工作原理,以及如何利用这些知识来进行更好的内存管理和性能优化。具体而言,我们将探索Go...

【Go语言slice详解】深入掌握Go语言中的slice类型及常用操作!

Go语言中的slice(切片)是一种非常方便的数据结构,可以动态地增加或减少其元素数量,且可以访问底层数组的任意一个子序列。本文将对Go语言中的slice进行详细的讲解。Slice的定义在Go语言中,...

掌握GO中的Slice,这就够了

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

golang2021面向对象(26)Go语言类型内嵌和结构体内嵌

结构体可以包含一个或多个匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型也就是字段的名字。匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌结构体。?可以粗略地将这个...

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内的指针方法列表?以下代码应该返回{"S1":["M1","M2"],"S...

Go语言文件和目录操作

文件和目录操作概述一、文件和目录操作概述在计算机中,文件和目录是存储数据的重要方式。在Go语言中,我们可以使用os和io/ioutil包提供的函数和结构体来进行文件和目录操作。本文将详细介绍Go语言中...

跟我一起学习go语言(五)golang中结构体的初始化方法

1、自定义一个结构体typeVertexstruct{X,Yfloat64}2、初始化方法-指针:rect1:=new(Vertex)rect2:=&Vertex...

Go复合数据类型:结构体

一种通用的、对实体对象进行聚合抽象的能力,在Go中,提供这种聚合抽象能力的类型是结构体类型,也就是struct。自定义一个新类型在Go中,我们自定义一个新类型一般有两种方法。第一种是类型定义...

Go语言基础:方法

导读在阅读本文章前,假定你具备如下能力:?已掌握结构体1.方法1.1方法的概念在理解程序中方法的概念时,我们先看看现实中的一些情况,这样相对比较好理解一些。在农村的朋友可能会知道,在医疗落后的情况...

为什么 Go 语言 struct 要使用 tags

在Go语言中,struct是一种常见的数据类型,它可以用来表示复杂的数据结构。在struct中,我们可以定义多个字段,每个字段可以有不同的类型和名称。除了这些基本信息之外,Go还提供了s...

一文带你掌握掌握 Golang结构体与方法

1.Golang结构体的概念及定义结构体是Golang中一种复合类型,它是由一组具有相同或不同类型的数据字段组成的数据结构。结构体是一种用户自定义类型,它可以被用来封装多个字段,从而实现数据的...

取消回复欢迎 发表评论: