简述Java反射

本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。

简述:反射是框架设计的灵魂(框架相当于半成本软件,可以在框架的基础上进行软件开发,从而简化编码,框架的出现大大的减轻了我们的工作)。
反射的好处:
1、可以在程序运行过程中,操作反射对象。
2、大大减低代码的耦合,提高程序的可扩展性。
我们知道,Java代码在计算机大体经历三个阶段(如下图1
),反射的使用前提必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)。在这里插入图片描述
反射就是将类的各个组成部分封装成为各个对象。例如:一个类有:成员变量、方法、构造器、包等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。我们可以看看下图的类的加载过程:Class对象的由来是将.class文件读入内存,并为之创建一个Class对象(反射的原理在Class类对象阶段)。
在这里插入图片描述
我们可以自己私下查看api类简单了解下Class类(所在包:java.lang)。

获取Class对象的三种方式:

Class.forName("全类名"):将字节码文件加载进内存返回Class对象。多用于配置文件,将类名定义在配置文件中,通过读取文件来加载类。
类名.class:通过类名的属性class获取,多用于参数传递,这种方式需要导入包,依赖性比较强。
对象.getClass():此方法从Object类中继承而来多用于对象获取字节码的方式,此方法不常用(对象都有了还要反射!)

public static void main(String[] args) throws ClassNotFoundException {
        // 获取Class对象的三种方式,第一种方法会抛出ClassNotFoundException异常
        Class clazz1 = Class.forName("Person");
        Class clazz2 = new Person().getClass();
        Class clazz3 = Person.class;

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz3 == clazz2);
    }

true
true

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会加载一次,不论通过哪一种方式获取Class对象都是同一个。

/**
 * 该类包括四个成员变量:默认id,私有name,公有age,保护address
 * 该类包括三个构造器:私有无参,公有双参,公有三参
 * 该类包括三个方法:私有无参method(),公有单参method(),重写toString()方法
 */
public class Person {
    String id;
    private String name;
    public int age;
    protected String address;

    private Person() {
    }

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

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

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

    public void method(String name) {
        System.out.println("有参数公有方法" + name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}

获取Class对象中的成员变量

Field[] getFields():获取所有公有的成员变量。
Field getField(String name):获取指定名称的公有成员变量。
Field[] getDeclaredFields():获取所有的成员变量(包括私有)。
Field getDeclaredField(String name):获取指定名称的成员变量(包括私有)。
void set(Object obj, Object value):设置成员变量的值。
Object get(Object obj):获取该成员变量的值。
String getName():获取该成员变量的名称。

@Test
    public void test() throws Exception {
        Class clazz = Class.forName("Person");
        // 获取所有成员变量(包括私有)
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            System.out.println(field);
        }
        System.out.println("----------------------------");
        // 获取指定名称的成员变量,并重新赋值name
        Field nameField = clazz.getDeclaredField("name");
        Person person = new Person("灰灰渣", 20);
        // 暴力反射
        nameField.setAccessible(true);
        
        Object name = nameField.get(person);
        System.out.println(name);
        nameField.set(person, "社会梁");
        System.out.println(person);
    }

java.lang.String Person.id
private java.lang.String Person.name
public int Person.age
protected java.lang.String Person.address
----------------------------
灰灰渣
Person{id=‘null’, name=‘社会梁’, age=20, address=‘null’}

获取Class对象中的构造器

Constructor<?>[] getConstructors():获取所有public修饰的构造器。
Constructor<T> getConstructor(类<?>... parameterTypes):获取指定参数且public修饰的构造器。
Constructor<?>[] getDeclaredConstructors():获取所有方法,包括私有的构造器(private修饰的)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):获取指定参数的构造器包括私有的构造器。
constructor.newInstance(参数列表):通过该构造器,创建对象。
构造器对象.setAccessible(boolean):暴力反射,忽略访问权限修饰符的安全检查。
String getName():获取该构造器的名称。

@Test
    public void test() throws Exception {
        Class clazz = Class.forName("Person");
        // 获取所有构造器(包含私有的)
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for(Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        
        // 获取无参构造器
        Constructor constructor0 = clazz.getDeclaredConstructor();
        // 如果不设置,会发生IllegalAccessException异常
        constructor0.setAccessible(true);
        System.out.println("无参私有构造器----------------------");
        System.out.println(constructor0.newInstance());
        
        // 获取三个参数的构造函数
        Constructor constructor3 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        System.out.println("三参公有构造器----------------------");
        System.out.println(constructor3.newInstance("灰灰渣", 20, "青青草原"));
    }

public Person(java.lang.String,int,java.lang.String)
public Person(java.lang.String,int)
private Person()
无参私有构造器----------------------
Person{name=‘null’, age=0, address=‘null’}
三参公有构造器----------------------
Person{name=‘灰灰渣’, age=20, address=‘青青草原’}

获取Class对象中的方法

Method[] getMethods():获取非私有的方法。
Method getMethod(String name, 类<?>... parameterTypes):获取指定名称公有的方法。
Method[] getDeclaredMethods():获取所有方法(包括私有)。
Method getDeclaredMethod(String name, 类<?>... parameterTypes):获取指定名称方法。
方法对象.setAccessible(boolean b):暴力反射,忽略访问权限修饰符的安全检查。
Object invoke(Object obj, Object... args):执行方法。
String getName():获得方法名。

    @Test
    public void test() throws Exception {
        Class clazz = Class.forName("Person");
        // 获取所有方法(包括私有)
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method : methods) {
            System.out.println(method);
        }
        Person person = new Person("灰灰渣", 20);
        // 获取无参method方法
        Method method0 = clazz.getDeclaredMethod("method");
        // 暴力反射,忽略修饰符
        method0.setAccessible(true);
        method0.invoke(person);
        // 获取单参method方法
        Method method1 = clazz.getDeclaredMethod("method", String.class);
        method1.invoke(person, "渣渣灰");
    }

public java.lang.String Person.toString()
public void Person.method(java.lang.String)
private void Person.method()
私有方法
有参数公有方法渣渣灰

参考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值