反射:框架设计的灵魂

反射:框架设计的灵魂

反射:将类的各个组成部分封装为其他对象,这就是反射机制
优点:
1.可以在程序运行过程中,操作这些对象
2.可以解耦,提高程序的可扩展性.后期学习的ssh框架都会用来

一、字节码对象Class的功能:

1.获取成员变量:

1. Field[] getFields() :获取所有public修饰的成员变量
2. Field getField(String name) 获取指定名称(单个)的 public修饰的成员变量
3. Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符(private4. Field getDeclaredField(String name) 获取指定名称的成员变量,不考虑修饰符(private

2.获取构造方法:

1. Constructor<?>[] getConstructors() 
2. Constructor<T> getConstructor(<?>... parameterTypes) 
3. Constructor<T> getDeclaredConstructor(<?>... parameterTypes) 
4. Constructor<?>[] getDeclaredConstructors()

3.获取成员方法:

1. Method[] getMethods() 
2. Method getMethod(String name,<?>... parameterTypes) 
3. Method[] getDeclaredMethods() 
4. Method getDeclaredMethod(String name,<?>... parameterTypes) 

二、获取字节码对象Class的三种方式:

1.Class.forName(“全类名”):

public class Dog {

    public String name;

    int age;

    protected String color;

    private String eat;

    public Dog() {
    }


    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                ", eat='" + eat + '\'' +
                '}';
    }
}
=============================执行方法===================================
    public class DogExample {
    public static void main(String[] args) throws Exception {
		//得到字节码对象
        Class<?> aClass = Class.forName("com.qst.opp.Dog");
        //初始化对象
        Object obj = aClass.newInstance();

        //获取公开的所有属性信息
        Field[] fields01 = aClass.getFields();
        for (Field f:fields01) {
            System.out.println("获取公开的所有属性信息:"+f);
        }

        //获取单个公开的属性
        Field name = aClass.getField("name");
        System.out.println(name);

        //获取所有的属性信息(包括私有的)
        Field[] fields02 = aClass.getDeclaredFields();
        for (Field f:fields02) {
            System.out.println("获取所有的属性信息:"+f);
        }

        System.out.println("===============================");
        
        //获取单个非公开的属性
        Field age = aClass.getDeclaredField("age");
        Field eat = aClass.getDeclaredField("eat");
        System.out.println(age);
        System.out.println(eat);

        System.out.println("===============================");

        //取值与赋值
        name.set(obj,"大黄");
        System.out.println("查看赋值操作:"+obj);
        Object o = name.get(obj);
        System.out.println("通过反射取值:"+o);

    }
}

2.类名.class:

public class Cat {

    public Cat() {
    }

    //测是方法

    public void eat(){
        System.out.println("猫吃鱼");
    }

    void run(){
        System.out.println("跑");
    }

    protected String sleep(){
        return "猫爱睡觉";
    }

    private String ww(){
        return "ww";
    }
}
===============================执行方法===============================
    public class CatExample {
    public static void main(String[] args) throws Exception {

        // 得到字节码对象
        Class<Cat> aClass = Cat.class;
        //对象:获取方法的用不上,但是执行方法的时候一定用
        //初始化对象
        Cat cat = (Cat)aClass.newInstance();

        //读取公开的方法 - 可以读取父类的公开方法
        Method[] methods01 = aClass.getMethods();
        for (Method m:methods01) {
            System.out.println("读取公开的方法:"+m);
        }

        //读取单个方法 - 读取公开的
        Method eat = aClass.getMethod("eat");
//        System.out.println(eat);
        
        //读取所有的方法 - 只能读取本类所有方法
        Method[] methods02 = aClass.getDeclaredMethods();
        for (Method m:methods02) {
            System.out.println("读取所有的方法:"+m);
        }

        System.out.println("=============================");


        //读取不公开的方法
        Method run = aClass.getDeclaredMethod("run");
        Method sleep = aClass.getDeclaredMethod("sleep");
        Method ww = aClass.getDeclaredMethod("ww");

        System.out.println("读取不公开的方法:"+run);
        System.out.println("读取不公开的方法:"+sleep);
        System.out.println("读取不公开的方法:"+ww);

        System.out.println("==============测试方法执行===============");

        //测试无返回值,公开的
        Object invoke = eat.invoke(cat);
        System.out.println("测试无返回值,公开的:"+invoke);

        //测试有返回值,且不公开
        Object invoke1 = sleep.invoke(cat);
        System.out.println("测试有返回值,且不公开:"+invoke1);
        //私有的方法,一定需要设置反射权限,暴力反射
        ww.setAccessible(true);
        Object invoke2 = ww.invoke(cat);
        System.out.println("测试有返回值,且不公开:"+invoke2);
    }
}

3.对象.getClass():

public class Apple {

    private String color;

    public int price;

    public Apple() {
    }

    private Apple(String color) {
        this.color = color;
    }

    private Apple(int price) {
        this.price = price;
    }

    public Apple(String color, int price) {
        this.color = color;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
}
============================执行方法=================================
    public class AppleExample {

    public static void main(String[] args) throws Exception {

        //得到字节码对象
        Apple apple = new Apple();
        Class<? extends Apple> aClass = apple.getClass();

        //读取构造方法 - 只获取公开的构造
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor cr:constructors) {
            System.out.println("获取公开的构造:"+cr);
        }
        //获取所有的构造
        Constructor<?>[] constructors1 = aClass.getDeclaredConstructors();
        for (Constructor cr:constructors1) {
            System.out.println("获取所有的构造:"+cr);
        }

        System.out.println("==========================");

        //获取空的
        Constructor<?> constructor0 = aClass.getConstructor();
        //获取有参的                                     //参数类型
        Constructor<?> constructor1 = aClass.getConstructor(String.class,int.class);
        //测试使用getConstructor获取私有的构造  -- 不行
        //Constructor<?> constructor2 = c.getConstructor(int.class);

        //测试getDeclaredConstructor
        Constructor<?> constructor3 = aClass.getDeclaredConstructor(int.class);
        System.out.println(constructor3);

        System.out.println("=============111=============");

        //实例化对象 == 公开的空构造
        Constructor<?> ctr = aClass.getConstructor();
        Apple app = (Apple) ctr.newInstance();
        System.out.println(app);

        //实例化对象 == 公开的有参构造
        Constructor<?> ctr1 = aClass.getConstructor(String.class,int.class);
        Apple app1 = (Apple) ctr1.newInstance("红富士",20);
        System.out.println(app1);

        System.out.println("==========================");

        //实例化对象 == 私有的有参构造
        Constructor<?> cturs = aClass.getDeclaredConstructor(int.class);
        //暴力反射
        cturs.setAccessible(true);

        Apple ap01 = (Apple) cturs.newInstance(222);
        System.out.println(ap01);
    }

}

三、总结:

1.方法中只要带有后缀"s"的,就是获取所有的
2.方法中只要带有"Declared"的,就是可以获取私有(方法/成员变量/构造方法)

3.Class.forName("全类名"):将字节码文件加载进内存,返回Class对象;多用于配置文件,将类名定义在配置文件中。读取文件,加载类
4.类名.class:通过类名的属性class获取;多用于参数的传递
5.对象.getClass():getClass()方法在Object类中定义着。多用于对象的获取字节码的方式

总结:同⼀个字节码⽂件(*.class)在⼀次程序运⾏过程中,只会被加载⼀次,不论通过哪⼀种⽅式获取的Class对象
都是同⼀个

四、框架的配置文件–反射简单的实现

package com.soft;

/**
 * @author 想要的东西太贵
 * @version 喜欢的女人太美
 * @date 2021/8/4 19:49
 */

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 我要写一个"框架",不要改变原先代码的情况下,可以帮我创建任意的类,并调用任意方法
 * 实现:
 *  配置文件:xml,json,peroperties,是一个文件
 *  反射
 *  1.读取配置文件内的信息
 *  2.在程序开启的时候加载,使用反射
 *  3.操作(初始化对象,方法调用)
 */
public class ReflectExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //1.读取配置信息
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("initClass.properties"));
        byte[] buffer = new byte[1024];

        int len = bis.read(buffer);
        String content = new String(buffer, 0, len);
        System.out.println(content);

        //2.得到类跟方法的字符串
        String[] strs = content.split(":");
        String className = strs[0];
        String methodName = strs[1];

//        System.out.println(ClassName);
//        System.out.println(constructor);

        //3.通过反射初始化对象
        Class<?> aClass = Class.forName(className);
        Object obj = Class.forName(className).newInstance();
        //4.调用对应的方法
        Method method = aClass.getMethod(methodName);
        Object invoke = method.invoke(obj);
        System.out.println(invoke);
    }
}
========================学生类=======================
    package com.soft;

public class Student {
    private String name;
    private int age;
    int age2;

    public String address;
    public String newAddress;
    public int num;

    public void study(){
        System.out.println("学习");
    }

    public void superStudy(){
        System.out.println("超级学习法");
    }

    public void miss() {
        System.out.println("我好想你,xxx");
    }
    public Student() {
        System.out.println("构造1");
    }

    //构造的参数不一样
    public Student(String name, int age) {
        System.out.println("构造2");
        this.name = name;
        this.age = age;
    }
    //构造的参数不一样
    public Student( int age,String name) {
        System.out.println("构造3");
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, int age2, String address) {
        System.out.println("构造3");
        this.name = name;
        this.age = age;
        this.age2 = age2;
        this.address = address;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("setName方法执行:"+name);
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public int getAge2() {
        return age2;
    }

    public void setAge2(int age2) {
        this.age2 = age2;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getNewAddress() {
        return newAddress;
    }

    public void setNewAddress(String newAddress) {
        this.newAddress = newAddress;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
=========================配置文件信息initClass.properties=============================
    com.soft.Student:miss
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值