Java中的反射

What

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

Why

在不更改源代码的情况下,提供程序的扩展性,使开发更简单(接口加配置文件)

EG:Tomcat 工作原理
这里写图片描述

How

Class类可以获取字节码文件中的所有内容,反射就是依靠该类完成。想要获取类中的信息,只要获取到字节码文件对应的对象即可。

获取字节码对应的对象

  1. Object类中的getClass方法,使用这种方法,必须要明确具体的类,并创建对象 —-(复杂)

    public static void getClass1() {
            Car car = new Car();
            Class clazz = car.getClass();
    
            Car car1 = new Car();
            Class clazz1 = car1.getClass();
    
            System.out.println(clazz == clazz1);
        }
  2. 任何数据类型都具备一个静态的数据类型.class来获取对应的Class对象相对简单,但是还是要明确用到类中的静态成员,达不到扩展的效果

    public static void getClass2() {
            Class clazz = Car.class;
            Class clazz1 = Car.class;
    
            System.out.println(clazz == clazz1);
        }
  3. 只要通过给定的类的名称就可以获取该类,更为扩展.可以使用Class中的方法完成,该方法就是forName,只要有名称即可,更为方便,扩展性更强

    public static void getClass3() {
            String className = "ung8023.base.reflect.Car";
            Class clazz = null;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            System.out.println(clazz == null ? "null" : clazz);
        }

获取构造方法

  1. 无参构造方法

        public static void createObject1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
            /*
              通过new关键字创建对象,现根据new的类的名称找寻该类的字节码文件,并加载进内存
              并创建该字节码文件对象,接着创建该字节码文件的对应的Car对象
             */
            ung8023.base.reflect.Car car = new ung8023.base.reflect.Car();
    
            //使用反射:
            String name = "ung8023.base.reflect.Car";
            //找寻该名称类文件,并加载进内存,并产生Class对象
            Class clazz = Class.forName(name);
            //生成该类的对象,如果无空参构造函数会报InstantiationException,如果无参构造方法为私有,则IllegalAccessException
            Object obj = clazz.newInstance();
        }
  2. 有参构造方法

        public static void createObject2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
         //ung8023.base.reflect.Car car = new ung8023.base.reflect.Car("oooo", 300);
            /*
             当获取指定名称对应类中所体现的对象时,而该对象初始化不使用空参构造方法
             既然是通过指定的函数进行对象的初始化,所以应该先获取到该构造函数。
             通过字节码文件对象即可完成,通过getConstructor(Class<?> ...param);
             通过getDeclaredConstructor();可获取到所有(包括私有)构造方法。
             */
            //使用反射:
            String name = "ung8023.base.reflect.Car";
            //找寻该名称类文件,并加载进内存,并产生Class对象
            Class clazz = Class.forName(name);
            //获取构造器对象
            Constructor constructor = clazz.getConstructor(String.class, int.class);
            Object car = constructor.newInstance("Aodi", 300);
        }

获取属性

public static void getField() throws Exception {
        Class clazz = Class.forName("ung8023.base.reflect.Car");

        Field field = null;//clazz.getField("speed");只能获取共有的

        field = clazz.getDeclaredField("maxSpeed");// 只获取本类,但包含私有
        //对私有字段访问取消权限检查,暴力访问(不建议)
        field.setAccessible(true);

        Object obj = clazz.newInstance();
        field.set(obj, 100);
        Object o = field.get(obj);
        System.out.println(o);

    }

获取方法

  1. 查看所有方法

    public static void getMethod() throws Exception{
            Class clazz = Class.forName("ung8023.base.reflect.Car");
    
            Method[] methods = clazz.getMethods();
            Object obj = clazz.newInstance();
            for(int i=0; i<methods.length; i++) {
                System.out.println(methods[i]);
            }
        }
  2. 运行无参方法

    public static void getMethod_1() throws Exception{
            Class clazz = Class.forName("ung8023.base.reflect.Car");
    
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("run", null);
            method.invoke(obj, null);
        }
  3. 运行带参方法

    public static void getMethod_2() throws Exception{
            Class clazz = Class.forName("ung8023.base.reflect.Car");
    
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("paramMethod", String.class, int.class);
            method.invoke(obj, "audi",300);
        }   

Car类源码

public class Car {
    private String name;
    private int maxSpeed;

    public Car(String name, int maxSpeed) {
        super();
        this.name = name;
        this.maxSpeed = maxSpeed;
        System.out.println("paramContructorRun");
    }

    public Car() {
        super();
        System.out.println("noparamConstructor");
    }

    private void privateMethod() {
        System.out.println("privateMehtod run");
    }

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

    public void paramMethod(String str, int speed) {
        System.out.println("paramMethod run " + str + ":" + speed);
    }

    public static void staticMethod() {
        System.out.println("staticMethod run");
    }
}

Sample(以电脑运行为例)

主板增加扩展性,通过声明PCI接口来达到扩展性.读取配置文件,来达到扩展性。

  1. Computer类

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.util.Properties;
    
    public class Computer {
    
        public static void main(String[] args) throws Exception {
            run();
        }
    
        public static void run() throws Exception {
            MainBoard mainBoard = new MainBoard();
    
            //读取配置文件(一般使用xml,此处使用properties代替)
            File configFile = new File("pciproperties.properties");
            //定义Properties对象
            Properties prop = new Properties();
            //使用流关联文件
            FileInputStream fis = new FileInputStream(configFile);
            //将文件加载入Properties
            prop.load(fis);
    
            for(int i=0; i < prop.size(); i++) {
                String pciName = prop.getProperty("pci"+(i+1));
                Class pciClass = Class.forName(pciName);
                PCI pci = (PCI)pciClass.newInstance();
                mainBoard.pciRun(pci);
                mainBoard.pciClose(pci);
            }
    
            fis.close();
        }
    }
  2. PCI接口

    public interface PCI {
        void start();
        void close();
    }
  3. MainBoard类

    public class MainBoard {
    
        public void mainBoardRun() {
            System.out.println("mainboard run");
        }
    
        public void pciRun(PCI pci) {
            pci.start();
        }
    
        public void pciClose(PCI pci) {
            pci.close();
        }
    }
  4. NetCard类

    public class NetCard implements PCI {
    
        @Override
        public void start() {
            System.out.println("net run");
        }
    
        @Override
        public void close() {
            System.out.println("net close");
        }
    }
    
  5. SoundCard类

    public class SoundCard implements PCI {
    
        @Override
        public void start() {
            System.out.println("sound run");
        }
    
        @Override
        public void close() {
            System.out.println("soundclose");
        }
    }
  6. pciproperties.properties文件

    pci1 = ung8023.base.reflect.sample.NetCard
    pci2 = ung8023.base.reflect.sample.SoundCard
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值