专栏首页bingfeng-技术Java重点基础:反射机制

Java重点基础:反射机制

一、什么是反射?

Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。

二、反射的三种方式

这里需要跟大家说一下,所谓反射其实是获取类的字节码文件,也就是.class文件,那么我们就可以通过Class这个对象进行获取。

1、第一种方式

这个方法其实是Object的一个方法,Class继承了Object,所以我们可以直接使用。

public class Test02 {

    public static void main(String[] args) {

        // 创建一个对象
        Test02 t = new Test02();

        // 获取该对象的Class对象
        Class c = t.getClass();
        
        // 获取类名称
        System.out.println(c.getName()); // com.ms.Test02
    }
}

2、第二种方式

public class Test02 {

    public static void main(String[] args) {

        Class c = Test02.class;

        // 获取类名称
        System.out.println(c.getName()); // com.ms.Test02
    }
}

3、第三种

这里需要注意,通过类的全路径名获取Class对象会抛出一个异常,如果根据类路径找不到这个类那么就会抛出这个异常。

public class Test02 {

    public static void main(String[] args) {

        try {
            // 根据类的全路径名获取
            Class c = Class.forName("com.ms.Test02");

            // 获取类名称
            System.out.println(c.getName()); // com.ms.Test02
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

那么这3中方式我们一般选用哪种方式呢?第一种已经创建了对象,那么这个时候就不需要去进行反射了,显得有点多此一举。第二种需要导入类的包,依赖性太强。所以我们一般选中第三种方式。

三、通过反射获取类的构造方法、方法以及属性

1、获取构造方法

public class Test01 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException {

        // 加载Class对象
        Class c = Class.forName("com.reflect.User");

        System.out.println("===========================获取所有公用的构造方法==============================");
        // 获取所有公用的构造方法
        Constructor[] constructors = c.getConstructors();

        for (Constructor constructor : constructors) {

            System.out.println(constructor);
        }

        System.out.println("=============================获取所有的构造方法============================");
        // 获取所有的构造方法
        Constructor[] declaredConstructors = c.getDeclaredConstructors();

        for (Constructor declaredConstructor : declaredConstructors) {

            System.out.println(declaredConstructor);
        }

        System.out.println("=============================获取公有 & 无参的构造方法============================");

        Constructor constructor = c.getConstructor(null);

        System.out.println(constructor);

        System.out.println("=============================获取公有 & 有参的构造方法============================");

        Constructor constructor1 = c.getConstructor(new Class[]{String.class, Integer.class, String.class});

        System.out.println(constructor1);

        System.out.println("=============================获取私有 & 有参 构造方法============================");

        Constructor declaredConstructor1 = c.getDeclaredConstructor(new Class[]{String.class});

        System.out.println(declaredConstructor1);
    }
}

结果:

2、获取类属性

public class Test02 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        // 获取Class对象
        Class<?> clazz = Class.forName("com.reflect.User");

        System.out.println("=====获取所有的公共字段=====");
        Field[] fields = clazz.getFields();

        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("=====获取所有的字段(公开的、私有的)=====");
        Field[] declaredFields = clazz.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println("=====获取公有字段并使用=====");
        // 获取指定公有字段
        Field field = clazz.getField("name");
        // 获取一个公有构造方法,然后实例化
        Object obj = clazz.getConstructor().newInstance();
        // 为属性设置值
        field.set(obj, "张三");
        // 测试,看设置的值是否成功
        User user = (User) obj;

        System.out.println(user.getName());

        System.out.println("=====获取私有字段并使用=====");
        Field field1 = clazz.getDeclaredField("sex");

        // 获取构造函数,实例化对象
        Object obj1 = clazz.getConstructor().newInstance();
        // 暴力反射
        field1.setAccessible(true);
        // 给属性设置值
        field1.set(obj1, "男");
        // 测试
        User u = (User) obj1;
        System.out.println(u.getSex());
    }
}

结果

这里需要注意,在获取私有属性的时候如果没有进行暴力反射,那么会抛出下面这个异常。

3、获取类中的方法

先定义几个方法

public void method1(String str) {

    System.out.println("public 修饰的方法");
}

private void method2() {

    System.out.println("private 修饰的方法");
}

String method3(String name, Integer age, String sex) {

    System.out.println("默认修饰 " + name + " " + sex + " " + age + "岁");

    return name + sex + age;
}

protected void method4() {

    System.out.println("protected 修饰的方法");
}

正题

public class Test03 {

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

        // 获取Class对象
        Class<?> clazz = Class.forName("com.reflect.User");

        System.err.println("======获取所有的public修饰的方法=====");
        Method[] methods = clazz.getMethods();

        for (Method method : methods) {

            System.out.println(method);
        }

        Thread.sleep(1000);

        System.err.println("======获取所有的方法=====");
        Method[] declaredMethods = clazz.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        Thread.sleep(1000);

        System.err.println("======获取特定方法(带参)并使用=====");
        Method method1 = clazz.getMethod("method1", String.class);

        System.out.println(method1);

        Thread.sleep(1000);

        System.err.println("======获取特定方法(不带参)并使用=====");
        Method method2 = clazz.getDeclaredMethod("method2");
        System.out.println(method2);

        System.err.println("======获取特定方法(多个参数)并使用=====");
        Method method3 = clazz.getDeclaredMethod("method3", String.class, Integer.class, String.class);
        // 获取构造方法,实例化一个对象
        Object obj = clazz.getConstructor().newInstance();
        // 给方法传值
        Object invoke = method3.invoke(obj, "小涛", 24, "男");

        // 测试
        System.out.println(invoke);
    }
}

结果

这里需要注意的就是当一个方法需要传入多个参数值的时候,一定要注意。踩了一点坑。

四、反射执行main方法

public class Main {

    public static void main(String[] args) {
        System.out.println("main方法执行了");
    }
}

反射调用

public class Test04Main {

    public static void main(String[] args) {

        try {
            // 获取Class对象
            Class<?> clazz = Class.forName("com.reflect.Main");

            // 获取Main方法
            Method method = clazz.getMethod("main", java.lang.String[].class);

            // 调用
            method.invoke(null, (Object) new String[]{"a"});

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这里需要告诉大家,在导String包的时候千万要看清楚,我在这填了20多分钟的坑。

五、总结

看到这里你已经对反射有了一个简单的了解,可以使用反射获取一些属性方法,其实我们平时写代码很少用到反射技术,但是在我们使用的一些主流框架中反射技术应用是非常广泛的,所以学好反射也是非常有必要的。

今天就写到这里,下篇给大家分享一下利用反射做一些有应用型的例子。

本文分享自微信公众号 - 一个程序员的成长(xiaozaibuluo),作者:小涛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringBoot系列之使用自定义注解校验用户是否登录

    记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。

    一个程序员的成长
  • Java8 Stream常用API整理(值得收藏)

    来 源:https://blog.csdn.net/wangchengming1/article/details/89245402

    一个程序员的成长
  • 「Java并发」 HashMap实现原理及源码分析(Java 1.8.0_101)

    HashMap 作为一种容器类型,无论你是否了解过其内部的实现原理,它的大名已经频频出现在各种互联网面试中了。从基本的使用角度来说,它很简单,但从其内部的实现来...

    一个程序员的成长
  • Class类

    用户2965768
  • JavaSE(十)之反射

    开始接触的时候可能大家都会很模糊到底什么是反射,大家都以为这个东西不重要,其实很重要的,几乎所有的框架都要用到反射,增加灵活度。到了后面几乎动不动就要用到反射。...

    用户1195962
  • IO流介绍与File类

    io就是Input/Output的缩写形式,Input是输入流,Output是输出流。

    端碗吹水
  • java反射技术

    想必开发过接口的童鞋们,应该或多或少写过一些接口说明文档。那么,有没有可能把现有的接口做成一个界面在页面展现出来而不用去写什么接口文档,在页面展示的信息包括接口...

    wblearn
  • java反射简明示例

    Java反射在我们Java学习的过程中是非常重要的知识点。可能有些同学认为这个学习起来不容易理解,其实就我个人而言还是比较简单,学习起来也比较容...

    java达人
  • 20.Swift学习之扩展

    扩展可以使已有的类型遵循一个或多个协议。在这种情况下,协议名的书写方式与类或结构体完全一样:

    YungFan
  • 文件操作与文件夹操作

扫码关注云+社区

领取腾讯云代金券