Java学习之反射

反射

什么是反射

获取运行时类信息的手段

反射技术的起点就是获取字节码文件对象

获取字节码文件对象的几种方式

  • 对象.getClass()
  • 类名.class
  • Class.forName(全类名)
  • ClassLoader.loadClass(全类名)

无论通过何种方式获取到的字节码文件对象 , 都是同有一个

配置文件(.properties)

配置文件里面放的是什么? 一般放的就是配置信息, 数据库的配置信息, 第三方服务的配置信息

格式

键值对(key-value) key = value

  • 注释使用的是#
  • key不能重复

Properties

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

构造方法

Properties() 创建一个无默认值的空属性列表。

成员方法

voidload(InputStream inStream) 从输入流中读取属性列表(键和元素对)。
voidload(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
StringgetProperty(String key) 用指定的键在此属性列表中搜索属性。

通过反射获取构造方法(Constructor)

通过反射获取所有构造方法

Constructor[] getConstructors()
Constructor[] getDeclaredConstructors()

获取指定构造方法

Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

使用Constructor创建对象

Person p = new Person("zs",20,true)
newInstance(参数列表)

暴力破解权限限制

setAccessible(true) 
/*
获取构造方法
 */
public class ConstructorTest {
    public static void main(String[] args) throws Exception{
        // 反射技术的起点获取字节码文件对象
        Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
        // 获取所有的public的构造方法
        System.out.println("获取所有的public的构造方法");
        // Constructor[] getConstructors()
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("获取所有的构造方法");
        //Constructor[] getDeclaredConstructors()
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println(constructor);
        }
        System.out.println("获取指定的public的构造方法---------");

        // Constructor<T> getConstructor(Class<?>... parameterTypes)
        Constructor<?> constructor = personCls.getConstructor(String.class, int.class);
        System.out.println(constructor);

        System.out.println("获取指定的构造方法---------");

        //Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        Constructor<?> declaredConstructor =
                personCls.getDeclaredConstructor(String.class, int.class, boolean.class);
        System.out.println(declaredConstructor);


        // 通过构造方法实例化对象
        // newInstance(参数)
        Object o = constructor.newInstance("zs", 20);
        System.out.println(o);

        // 暴力破解
        // setAccessible(true) 忽略java语法检查
        declaredConstructor.setAccessible(true);
        Object o1 = declaredConstructor.newInstance("ls", 22, true);
        System.out.println(o1);
        
    }
}

通过反射获取成员变量(Field)

通过反射获取所有成员变量

Field[] getFields()
Field[] getDeclaredFields()

获取指定成员变量

Field getField(String name)
Field getDeclaredField(String name)

通过Field读写对象的成员变量(可暴力破解)

Object get(Object obj):获取值,传入对象
void set(Object obj, Object value):赋值,传入对象
public class FieldTest {
    public static void main(String[] args) throws Exception{
        // 获取字节码文件对象
        Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");

        System.out.println("获取所有的public的成员变量-------");
        // Field[] getFields()
        Field[] fields = personCls.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("获取所有的成员变量-------");

        //Field[] getDeclaredFields()
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
        }
        System.out.println("获取指定的public成员变量-------");
        // Field getField(String name)
        Field nameField = personCls.getField("name");
        System.out.println(nameField);

        System.out.println("获取指定成员变量-------");
        //Field getDeclaredField(String name)
        Field ageField = personCls.getDeclaredField("age");
        System.out.println(ageField);

        // 需要一个对象
        Constructor<?> declaredConstructor = personCls.getDeclaredConstructor();
        Object o = declaredConstructor.newInstance();
        // set()给成员变量设置值
        nameField.set(o, "zs");
        System.out.println(o);
        // get() 获取成员变量的值
        System.out.println(nameField.get(o));

        ageField.setAccessible(true);
        ageField.set(o, 20);
        System.out.println(o);
    }
}

通过反射获取成员方法(Method)

获取所有成员方法

Method[] getMethods()
Method[] getDeclaredMethods()

获取指定的成员方法

Method getMethod(String name, Class<?>... parameterTypes)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)

利用Method调用对象的方法

Object invoke(Object obj, Object... args)
public class MethodTest {
    public static void main(String[] args) throws Exception{
        // 获取字节码文件对象
        Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
        System.out.println("获取所有的public的成员方法");
        //Method[] getMethods()
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("获取所有的成员方法-----------------");
        Method[] declaredMethods = personCls.getDeclaredMethods();
        //Method[] getDeclaredMethods()
        for (Method method : declaredMethods) {
            System.out.println(method);
        }
        System.out.println("获取指定的public的成员方法");
        // Method getMethod(String name, Class<?>... parameterTypes)
        Method eatMethod = personCls.getMethod("eat");
        System.out.println(eatMethod);

        System.out.println("获取指定的成员方法");

        //Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        Method eatMethod2 = personCls.getDeclaredMethod("eat", String.class);
        System.out.println(eatMethod2);

        // 创建Person对象
        Constructor<?> declaredConstructor = personCls.getDeclaredConstructor();
        Object o = declaredConstructor.newInstance();
        // invoke()
        eatMethod.invoke(o);

        eatMethod2.setAccessible(true);
        eatMethod2.invoke(o, "apple");
    }
}

补充

其他API

/*
补充其他API
 */
public class Demo2 {
    public static void main(String[] args) throws Exception{
        Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
        //Class<?> personCls = Class.forName("java.io.OutputStream");
        // 获取类名
        String name = personCls.getName();
        System.out.println(name);
        // 获取简单名
        System.out.println(personCls.getSimpleName());
        // 获取父类
        Class<?> superclass = personCls.getSuperclass();
        System.out.println(superclass.getSimpleName());
        // 获取接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> i : interfaces) {
            System.out.println(i);
        }
        // 获取成员变量
        Field nameFiled = personCls.getDeclaredField("name");
        // 获取权限修饰符
        int modifiers = nameFiled.getModifiers();
        System.out.println(modifiers);
        // static String toString(int mod)
        // 返回描述指定修饰符中的访问修饰符标志的字符串
        String s = Modifier.toString(modifiers);
        System.out.println(s);
        // 获取成员变量类型
        System.out.println(nameFiled.getType());

        // 获取方法对象
        Method eatMethod = personCls.getDeclaredMethod("eat");
        System.out.println(eatMethod.getReturnType().getSimpleName());
    }
}

小练习

1.设计一个方法如下,要求该方法能修改任意对象中,指定成员变量的值

import java.lang.reflect.Field;
/*
@param targetObj 要修改成员变量值的目标对象

@param fieldName 对象中要修改的成员变量的名字

@param newValue 要修改成员变量值的新值*/
public class Demo {
    public static void setAll(Object targetObj, String fieldName, Object newValue) throws Exception {
        //创建要修改成员变量值的目标对象的字节码文件对象
        Class<?> targetObjClass = targetObj.getClass();
        //通过反射获取对象中要修改的成员变量
        Field nameField = targetObjClass.getDeclaredField(fieldName);
        //解决权限问题,让jvm绕过权限检查机制
        nameField.setAccessible(true);
        //在指定对象上修改成员变量值的新值
        nameField.set(targetObj, newValue);
    }
}

2.使用反射机制完成学生对象的创建并输出学生信息。

要求:

(1)定义一个学生类Student,其中包含姓名(String)、年龄(int)、成绩(int)的属性。

(2)编写带参与无参构造方法。

(3)重写父类的toString()方法用于输出学生的信息。

(4)编写测试类TestStudent,从键盘录入学生的信息格式为(姓名:年龄:成绩)一次性录入使用“:”分隔,举例(张三:20:90)。

(5)使用String类的split方法按照“:”进行分隔。

(6)调用Constructor的newInstance()方法并用分隔后的信息初始化学生对象。

(7)调用重写父类的toString()方法将学生信息进入输出显示。

public class Student {
    String name;
    int age;
    int score;

    public Student() {
    }

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

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

import java.lang.reflect.Constructor;
import java.util.Scanner;

public class TestStudent {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        String student = sc.nextLine();
        String[] strings = student.split(":");
        //反射技术的起点获取字节码对象
        Class<?> studentCls = Class.forName("second_day._01exercise.Student");
        //获取指定的public构造方法
        Constructor<?> constructor = studentCls.getConstructor(String.class, int.class, int.class);
        //通过构造方法实例化对象
        //解决权限问题,让jvm绕过权限检查机制
        constructor.setAccessible(true);
        Student o = (Student) constructor.newInstance(strings[0], Integer.parseInt(strings[1]), Integer.parseInt(strings[2]));
        System.out.println(o.toString());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值