Java核心-反射

1.什么是Java反射

指在JAVA程序运行状态中

  • 给定一个类(Class)对象,通过反射获取这个类(Class)对象的所有成员结构
  • 给定一个具体的对象,能够动态的调用它的方法及任意属性值进行获取和赋值
    这种动态获取类的内容,创建对象,以及动态调用对象的方法及操作属性的机制就是Java反射机制 。

示例

public class Dog {
    public String color;

    public void bark() {
        System.out.println("Dog barking");
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Dog.class;
        // 创建对象
        Dog dog = (Dog) clazz.newInstance();

        // 获取包的结构
        System.out.println(clazz.getSuperclass()); // 父类
        System.out.println(clazz.getClassLoader());// 类的classlader
        System.out.println(clazz.getPackage());// 包名
        System.out.println(clazz.getName());//类名

        Method method = clazz.getDeclaredMethod("bark");
        method.invoke(clazz.newInstance());
    }
}

运行结果:

    class java.lang.Object
    sun.misc.Launcher$AppClassLoader@18b4aac2
    package com.liulin.reflect.demo1
    com.liulin.reflect.demo1.Dog
    Dog barking

2.反射的优劣势

优势

增加程序的灵活性,避免将固有的逻辑程序写死到代码里
代码简洁,可读性强,可提高代码的复用率

缺点

相较直接调用在量大的情况下反射性能下降
存在一些内部暴露和安全隐患

反射慢在哪里

  • 寻找类Class 字节码的过程
  • 安全管理机制的权限验证等等
  • 若需要调用native 方法调用时JNI 接口的使用

3.反射初体验

Office接口

public interface Office {
    public void toPDF();
}

Excel类

public class Excel implements Office {
    @Override
    public void toPDF() {
        System.out.println("Excel to PDF");
    }
}

PPT类

public class PPT implements Office {
    @Override
    public void toPDF() {
        System.out.println("PPT to PDF");
    }
}

Word类

public class Word implements Office {
    @Override
    public void toPDF() {
        System.out.println("Word to PDF");
    }
}

测试类

public class Main {

    public static void main(String[] args) {
        String key = "PPT";
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++) {
            Office office = getInstanceReflectByKey(key);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("总计花费时间:" + (endTime - startTime));
    }

    /**
     * 通过传入key 创建不同的对象
     *
     * @param key
     * @return
     */
    public static Office getInstanceByKey(String key) {
        if ("Word".equals(key)) {
            return new Word();
        }

        if ("Excel".equals(key)) {
            return new Excel();
        }

        if ("PPT".equals(key)) {
            return new PPT();
        }

        return null;
    }

    /**
     * 通过反射机制动态的创建
     *
     * @param key
     * @return
     */
    public static Office getInstanceReflectByKey(String key) {
        String packageName = "com.gpseven.corejava.demo2";

        Office office = null;
        try {
            Class clazz = Class.forName(packageName + "." + key);
            office = (Office) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return office;
    }
}

4.反射技术的重要组成

万物皆对象,我们定义的类其实从面向对象的角度来分析,它其实也是一个具体的对象,它是
一个描述类的实例.描述这个类中有哪些属性,行为等等内容.
我们可以通过定义类,来描述一组具有相同属性,行为的实例对象.比如我们创建Person 类

Class Person {
	String ID;
	int age;
	void talk(){
		//TODO
	}
}

我们可以基于这个类创建具体不同身份证号和姓名的Person 实例(new Person).
每一个实例都具有身份证号,年龄,说话的行为.
通过上面的简单案例,我们可以这么理解在Java 语言中Class 的定义,是创建对象的统一模板.
那么我们可以思考这样一个问题,既然不管是Java 语言默认的类还是我们自定义创建的类都
是为了创建具有相同行为属性的对象的模板…
那么每一个类我们在定义的时候,是不是也可以抽取共性的东西,比如,每一个类都有包名,属
性定义,行为(方法),构造器等等.
那么既然每一个类都会具备这样的内容,那么这些类对象实例,应该也可以抽取成一个公有的
模板,用于创建类对象实例的模板.
所以在java 中,这个类定义的创建模板就是我们java 语言中的java.lang.Class 类.在Class 的模
板中,我们也可以找到大家耳熟能详的模板类如Method,Constructor,Field …

在这里插入图片描述
通过上面的内容,我们已经了解到我们创建的每一个自定义的Class 实例都是基于他的模板类
java.lang.Class 类.
在大家每一个编写的类实例中,都会定义这个类的包名,类名,访问域,特征符,构造器,字段,函
数,父类,接口等等内容.

5.反射-API

基本信息操作

  • int modifier = clazz.getModifiers(); //获取类的修饰符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SXI9YZIT-1586783714370)(http://www.zgliulin.com:6060/upload/20200413_21111947.png)]

若类的定义为,public abstract Class ClassXXX{ }
int modify = clazz.getModifers();
返回值为public 值+ abstract 的值= 1025

  • Package package= clazz.getPackage(); //获取类的包名
  • String fullClassName = clazz.getName(); //获取类的全路径名称
  • String simpleClassName = clazz.getSimpleName(); //获取类的简单名称
  • ClassLoader classLoader = clazz.getClassLoader(); //获取类的类加载器
  • Class[] interfacesClasses = clazz.getInterfaces(); //获取类实现的接口列表
  • Class fc= clazz.getSuperclass(); //获取类的父类
  • Annotation[] annotations= clazz.getAnnotations(); //获取类的注解列表

字段操作

  • Field[] fields = clazz.getFields(); //获取类中所有的公有字段 包含继承
  • Field[] declaredFields=clazz.getDeclaredFields(); //获取类中定义的字段 内部
  • Field nameField=clazz.getField(“name”); //获取指定名称的公有字段
  • Field likeDescField=clazz.getDeclaredField(“likeDesc”); //获取指定名称类中定义的字段
  • int modifersFiled = likeDescField.getModifiers(); //获取字段的修饰
  • nameField.setAccessible(true); //指定字段强制访问
  • nameField.set(person,“小皮皮”); //成员字段赋值(需指定对象)
  • descriptionField.set(null,“没有结婚的都是男孩!”); //静态字段赋值

方法操作

  • Method[] methods = clazz.getMethods(); //获取类中所有的公有方法 继承
  • Method[] declaredMethods = clazz.getDeclaredMethods(); //获取类中定义的方法
  • Method talkMethod = clazz.getMethod(“talk”, String.class); //获取类中指定名称和参数的公有方法
  • Method pugMethod = clazz.getDeclaredMethod(“pickUpGirls”) //获取类中定义指定名称和参数的方法
  • int modifers = pugMethod .getModifiers(); //获取方法的修饰符
  • talkMethod.invoke(boy,“I LOVE SEVEN”); //指定对象进行成员方法的调用
  • pugMethod .setAccessible(true); //指定方法的强制访问
  • pickUpGirlsMethod.invoke(null); //静态方法的调用

构造器操作

  • Constructor[] cons = clazz.getConstructors(); //获取类中所有的公有构造器
  • Constructor[] cons = clazz.getDeclaredConstructors(); //获取类中所有的构造器
  • Constructor conNoParam= clazz.getDeclaredConstructor(); //获取类中无参的构造器
  • Constructor con= clazz.getDeclaredConstructor(String.class,String.class); //获取类中有参构造
  • int modifers = con.getModifiers(); //获取构造器的修饰符
  • conNoParam.newInstance(); //构造器实例对象
  • con.setAccessible(true); //指定方法的强制访问
  • con.newInstance(‘abc’,‘def’); //有参构造调用
  • class.newInstacne(); //class直接调用默认无参构造

代码示例

Boy类

public class Boy extends Person {
    //身高
    public int height;

    private int weight;

    public static String desc;

    public Boy() {}

    private Boy(int height) {
        this.height = height;
    }

    public Boy(int height,int weight) {
        this.height = height;
        this.weight = weight;
    }

    public static void playBasketball(){
        System.out.println("play basketball !");
    }

    public void playball(String ballType){
        System.out.println("play "+ballType+" !");
    }
    
    //追女孩
    private void pickUpGirl(){
        System.out.println("pick up girl !");
    }

    public int getWeight() {
        return weight;
    }
}

Person类

public class Person {

    //名字
    public String name;

    //年龄
    private int  age;

    //说话
    public void talk(){
        System.out.println(name +",正在说话");
    }

}

测试类

public class Main {
    public static void main(String[] args) throws Exception {
        basicOper();// 基本信息操作
        filedOper();// 字段操作
        methodOper(); // 方法操作
        constructorOper();// 构造器操作
    }


    /**
     * 类的基本操作
     */
    public static void basicOper() {

        // 获取一个Class的对象实例方法1
        Class clazz = Boy.class;
       /* // 获取一个Class的对象实例方法2
        Class clazz2 = new Boy().getClass();
        // 获取一个Class的对象实例方法3
        try {
            Class clazz3 = Class.forName("com.gpseven.corejava.demo3.Boy");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        // 获取一个Class的对象实例方法4
        try {
            Class clazz4 = Main.class.getClassLoader().loadClass("com.gpseven.corejava.demo3.Boy");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }*/
        // 获取类修饰符
        int modifers = clazz.getModifiers();
        System.out.println("modifers:" + modifers);
        // 获取类的包名
        Package boyPkg = clazz.getPackage();
        System.out.println("boyPkg:" + boyPkg);
        // 获取类的全路径名称
        System.out.println("clazz.getName():" + clazz.getName());
        //获取类的简单名称
        System.out.println("clazz.getSimpleName():" + clazz.getSimpleName());
        //获取类的类加载器
        System.out.println("clazz.getClassLoader():" + clazz.getClassLoader());
        //获取类实现的接口列表
        System.out.println("clazz.getInterfaces().length:" + clazz.getInterfaces());
        //获取类的父类
        System.out.println("clazz.getSuperclass():" + clazz.getSuperclass());
        //获取类的注解列表
        System.out.println("clazz.getAnnotations().length:" + clazz.getAnnotations().length);
    }

    public static void filedOper() throws Exception {
        Class clazz = Boy.class;
        Boy boy = (Boy) clazz.newInstance();
        Field[] fields = clazz.getFields(); //获取当前类当中所有的公有字段,包含继承
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
        }
        Field nameField = clazz.getField("name");
        System.out.println(nameField.getName());
        Field[] fields2 = clazz.getDeclaredFields();
        System.out.println(fields2.length);
        for (int i = 0; i < fields2.length; i++) {
            System.out.println(fields2[i]);
        }
        Field weightField = clazz.getDeclaredField("weight");
        System.out.println(weightField.getModifiers());
        //让私有字段进行强制访问
        weightField.setAccessible(true);
        weightField.set(boy, 180);
        System.out.println(boy.getWeight());
        Field descField = clazz.getField("desc");
        descField.set(null, "这是一个静态的属性内容!!");
        System.out.println(Boy.desc);
    }

    public static void methodOper() throws Exception {
        Class clazz = Boy.class;
        Boy boy = (Boy) clazz.newInstance();
        Method[] methods = clazz.getMethods();
		//包含父类的方法 Object
        System.out.println("public method 一共有" + methods.length + "个");

        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
        }

        Method talkMethod = clazz.getMethod("talk");
        System.out.println(talkMethod.getName());
        Method playBallMethod = clazz.getMethod("playball", String.class);
        System.out.println(playBallMethod.getName());
        System.out.println(playBallMethod.getModifiers());
        playBallMethod.invoke(boy, "乒乓球");

        Method[] methods2 = clazz.getDeclaredMethods();
        System.out.println(methods2.length);
        Method pickUpGirlMethod = clazz.getDeclaredMethod("pickUpGirl");
        System.out.println(pickUpGirlMethod.getModifiers());
		// private方法强制访问
        pickUpGirlMethod.setAccessible(true);
        pickUpGirlMethod.invoke(boy);
		// 静态方法调用
        Method playBasketballMethod = clazz.getDeclaredMethod("playBasketball");

        playBasketballMethod.invoke(null);
    }


    public static void constructorOper() throws Exception {
        Class clazz = Boy.class;
        clazz.newInstance(); // ---> constructor 进行对象的构建.


        System.out.println(clazz.getConstructors().length);
        System.out.println(clazz.getDeclaredConstructors().length);

        //获取clazz中无参的构造器
        Constructor constructor = clazz.getDeclaredConstructor();

        Constructor constructor1 = clazz.getDeclaredConstructor(int.class);

        Constructor constructor2 = clazz.getDeclaredConstructor(int.class, int.class);


        System.out.println(constructor.getModifiers());
        System.out.println(constructor1.getModifiers());
        System.out.println(constructor2.getModifiers());

        Boy boy = (Boy) constructor.newInstance();
        System.out.println(boy);

        boy = (Boy) constructor2.newInstance(176, 130);
        System.out.println(boy.getWeight());

        constructor1.setAccessible(true);
        boy = (Boy) constructor1.newInstance(176);
        System.out.println(boy.height);

    }
}

6. Class 中newInstance 函数的本质

通过查看源码,我们发现,他底层还是调用的类的Constructor 对象进行newInstance 函数的调
用他会默认调用无参的构造函数
Class 类中newInstance 部分源码:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值