Java基础之反射

大家肯定都使用过流行的开源框架,那么这些框架的实现原理呢,一般来说它们都是基于反射来实现的,因此,反射对于我们来说至关重要。这边文章主要讲解反射的基本原理以及使用。

本文学习自(https://blog.csdn.net/sinat_38259539/article/details/71799078),非常感谢作者

1.概述

JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象

Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.例如:一个实体类中有String name;int age两个属性,那他所对应的字节码文件对象含String.class,int.class

小结
反射就是将类中的成分一个个映射为Java对象
例如:一个对象中含有成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
如图是类的正常加载过程:反射的原理在与class对象。
熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
在这里插入图片描述

2.Class类在api中的解释

https://docs.oracle.com/javase/7/docs/api/

3.反射获取成员方法、属性、构造

  1. 获取Class对象,三种方式:
    Class clazz = Student.class
    Class clazz = new Student().getClass()
    Class clazz = Class.forName(“完整路径的包名”)
  2. 通过以下方法获取
方法作用
clazz.getConstructors()获取所有**公有**构造函数
clazz.getDeclaredConstructors()获取所有构造函数
clazz.getConstructor(parameterTypes)获取单个公有对应参数类型的构造函数
clazz.getDeclaredConstructor(parameterTypes)获取单个对应参数类型构造函数
clazz.getMethods()获取所有公有成员方法
clazz.getDeclaredMethods()获取所有成员方法
clazz.getMethod(name,parameterTypes)获取单个对应名字对应参数类型公有成员方法
clazz.getDeclaredMethod(name,parameterTypes)获取单个对应名字对应参数类型成员方法
clazz.getFields()获取所有公有成员属性
clazz.getDeclaredFields()获取所有成员属性
clazz.getField(name)获取单个对应名字公有成员属性
clazz.getDeclaredField(name)获取单个对应名字成员属性

案例:
1.获取构造函数

实体类

package main.pojo;

/**
 * @program: reflect
 * @description: 用来测试反射获取构造函数的实体类
 * @author: wdl
 * @create: 2018-11-12 17:34
 */
public class Student {
    private String name;
    private int age;
    private boolean isMan;

    public int hair;

    public static void main(String...args){
        System.out.println("main方法执行了。。。。。。");
    }
    public Student(String name, int age, boolean isMan) {
        this.name = name;
        this.age = age;
        this.isMan = isMan;
    }

    //默认的构造方法
    Student(String name) {
        System.out.println("默认的构造方法 name = " + name);
        this.name = name;
    }

    //无参公有构造方法
    public Student() {
        System.out.println("无参公有构造方法执行");
    }

    //受保护的构造方法
    protected Student(int age) {
        System.out.println("受保护的构造方法 age = " + age);
        this.age = age;
    }

    //私有的构造方法
    private Student(boolean isMan) {
        System.out.println("私有的构造方法 isMan = " + isMan);
        this.isMan = isMan;
    }

    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 boolean isMan() {
        return isMan;
    }

    public void setMan(boolean man) {
        isMan = man;
    }`在这里插入代码片`

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

实现:

package main;

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

/**
 * @program: reflect
 * @description: 通过反射获取构造方法
 * @author: wdl
 * @create: 2018-11-12 17:53
 * <p>
 * 1.批量获取构造函数
 * Class.getConstructors 所有公有构造方法
 * Class.getDeclaredConstructors 所有构造函数(私有、受保护、默认、公有)
 * 2.获取单个构造函数
 * Class.getConstructor(parameterTypes)入的是参数的类型,返回一个描述这个无参构造函数的类对象,公有
 * Class.getDeclaredConstructor(parameterTypes)入的是参数的类型,返回一个描述这个无参构造函数的类对象,所有
 */
public class ReflectConstructors {
    public static void main(String... args) {
        try {
            //加载Class对象
            Class clx = Class.forName("main.pojo.Student");
            //获取所有公有构造方法
            Constructor[] publicConstructors = clx.getConstructors();
            System.out.println("**********************所有公有构造方法*********************************");
            for (Constructor constructor : publicConstructors) {
                System.out.println(constructor);
            }

            //Declared 包括所有
            //获取所有构造方法---包括public private protected
            Constructor[] allConstructors = clx.getDeclaredConstructors();
            System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
            for (Constructor constructor : allConstructors) {
                System.out.println(constructor);
            }


            //注意 : 传入的是参数的类型,返回一个描述这个无参构造函数的类对象
            //Constructor constructor = clx.getConstructor(String.class,int.class,boolean.class);
            //parameterTypes
            Constructor constructor = clx.getConstructor(null);
            System.out.println("************公有、无参构造方法***************");
            //通过反射获取的无参构造方法实例化对象
            Object object = constructor.newInstance();
            //Object object = constructor.newInstance("wdl",5,false);

            Constructor privateConstructor = clx.getDeclaredConstructor(boolean.class);
            System.out.println("************私有构造方法***************");
            //暴力访问 忽略掉访问修饰符
            privateConstructor.setAccessible(true);
            Object object1 = privateConstructor.newInstance(true);
            System.out.println(object1.toString());


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


Object object = constructor.newInstance();通过反射获取的构造方法实例化对象

2.获取成员变量

实体类

package main.pojo;

/**
 * @program: reflect
 * @description: 用来测试反射获取成员属性的实体类
 * @author: wdl
 * @create: 2018-11-12 18:28
 */
public class Book extends Student{
    //私有
    private String name;
    //公有
    public double price;
    //受保护
    protected int count;

    String press;

    public Book() {
    }

    public void show(int count){
        System.out.println("调用有参公有方法 count = "+count);
    }
    protected void show1(){
        System.out.println("调用无参受保护方法");
    }
    private int show2(int price){
        System.out.println("调用有参数私有方法 price = "+price);
        return price;
    }
    void show3(String name){
        System.out.println("调用有参默认方法 name = "+name);
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                ", count=" + count +
                ", press='" + press + '\'' +
                '}';
    }
}

实现:

package main;

import main.pojo.Book;

import java.lang.reflect.Field;

/**
 * @program: reflect
 * @description: 反射获取成员属性或者赋值
 * @author: wdl
 * @create: 2018-11-12 18:31
 * <p>
 * 获取成员变量并调用
 * 1.Field[] -->Class.getFields()  获取所有公有成员变量,包括父类的公有成员变量
 * 2.Field[] -->Class.getDeclaredFields()  获取所有成员变量(包括私有 公有 受保护 默认)
 * 3.Field   -->Class.getField(String propertyName)   获取单个公有成员变量,传入参数名,包括父类的公有成员变量
 * 4.Field   -->Class.getDeclaredFields(String propertyName)   获取单个成员变量,传入参数名(包括私有 公有 受保护 默认)
 */
public class ReflectFiled {
    public static void main(String... args) {
        try {
            Class clx = Class.forName("main.pojo.Book");
            //获取所有公有成员变量
            System.out.println("*******************获取所有公有成员变量******************");
            Field[] fields = clx.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
            System.out.println("*******************获取所有成员变量(包括公有,默认,私有,受保护)******************");
            fields = clx.getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field);
            }

            System.out.println("*******************获取单个公有成员变量,并设置值******************");
            //获取成员属性
            Field field = clx.getField("price");
            System.out.println(field);
            //通过构造实例化
            Object object = clx.getConstructor().newInstance();
            //设置值
            field.set(object, 50.2);
            //获取成员变量值
            System.out.println(field.get(object));
            Book book = (Book) object;
            System.out.println(book.price);

            System.out.println("*******************获取单个成员变量(私有,公有,保护,默认),并设置值******************");
            //获取成员属性
            field = clx.getDeclaredField("name");
            //暴力反射,解除私有权限
            field.setAccessible(true);
            System.out.println(field);
            //设置值
            field.set(object, "wdl");
            System.out.println(book);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//暴力反射,解除私有权限 Object object = clx.getConstructor().newInstance(); field.setAccessible(true); //设置值 field.set(object, "wdl");

3.获取成员方法
实现

package main;

import java.lang.reflect.Method;

/**
 * @program: reflect
 * @description: 反射获取成员方法
 * @author: wdl
 * @create: 2018-11-12 19:10
 * 与反射获取构造 属性类似
 */
public class ReflectMethod {
    public static void main(String...args){
        try {
            Class clx = Class.forName("main.pojo.Book");
            Method[] methods = clx.getMethods();
            System.out.println("****************获取所有公有成员方法****************");
            for (Method method : methods) {
                System.out.println(method);
            }

            methods = clx.getDeclaredMethods();
            System.out.println("****************获取所有成员方法****************");
            for (Method method : methods) {
                System.out.println(method);
            }

            //第一个为方法名,第二个为参数类型
            Method method = clx.getMethod("show",int.class);
            System.out.println("****************获取单个公有成员方法****************");
            System.out.println(method);
            //构建实例
            Object object = clx.getConstructor().newInstance();
            //通过invoke给此实例的这个方法设置参数
            method.invoke(object,50);



            //第一个为方法名,第二个为参数类型
            method = clx.getDeclaredMethod("show2",int.class);
            System.out.println("****************获取单个成员方法,包括私有等****************");
            System.out.println(method);
            method.setAccessible(true); //解除私有限定
            Object o  = method.invoke(object,20);
            System.out.println(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

总结:

  1. 获取构造函数时,constructor = clazz.getDeclaredConstructor(parameterTypes);通过constructor.newInstance(对应参数)可实例化对象。
  2. 获取成员变量后,通过field.set(object,“value”),可设置成员变量值;通过field.get(object)获取成员变量值.
  3. 获取成员方法后,通过method.invoke(“methodName”,参数值)可调用成员方法
  4. 在通过Declared获取私有信息时,必须调用xx.setAccessible(true),暴力反射解除私有限制,否则无法生效。
  5. parameterTypes代表的是参数类型,比如获取的成员方法为void show(int age,String name),则获取时应该为clazz.getDeclaredMethod(“show”,int.class,String.class);
关键字意义
getFields()获取所有公有属性,包括父类
get**Declared**Fields()获取所有属性,不包括父类

Demo链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值