Java 反射基础

最近在调研 Android 应用加固方案,涉及大量反射技术,因此趁这个机会总结下 Java 反射的一些知识。

什么是反射?

反射是 Java 语言提供的一种基本功能。通过反射我们可以在运行时动态地操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造函数,甚至可以在运行时修改类定义。

基本使用方法

反射的主要步骤包括:

  • 获取目标类型的 Class 对象
  • 通过 Class 对象分别获取 Constructor 类对象、Method 类对象 和 Field 类对象。
  • 通过 Constructor 、Method 和 Field 分别获取目标类的构造函数、方法和属性的具体信息,并进行后续操作。

获取目标类型的 Class 对象

1、Object.getClass()

StringBuilder stringBuilder = new StringBuilder("123");
Class<?> classType = stringBuilder.getClass();
System.out.println(classType);   // class java.lang.StringBuilder

2、T.class

Class<?> classType = int.class;
System.out.println(classType);   // int

T 代表任意 Java 类型。

3、Class.forName()

Class<?> classType = null;
try {
    classType = Class.forName("java.lang.Integer");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
System.out.println(classType);   // class java.lang.Integer

通过 Class 对象分别获取 Constructor 类对象、Method 类对象 和 Field 类对象

1、获取 Constructor 类对象

// a. 获取指定的构造函数 (公共 / 继承)
Constructor<T> getConstructor(Class<?>... parameterTypes)
// b. 获取所有的构造函数(公共 / 继承) 
Constructor<?>[] getConstructors(); 
// c. 获取指定的构造函数 (不包括继承)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
// d. 获取所有的构造函数(不包括继承)
Constructor<?>[] getDeclaredConstructors(); 

2、获取 Method 类对象

// a. 获取指定的方法(公共 / 继承)
Method getMethod(String name, Class<?>... parameterTypes) ;
// b. 获取所有的方法(公共 / 继承)
Method[] getMethods() ;
// c. 获取指定的方法 ( 不包括继承)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) ;
// d. 获取所有的方法( 不包括继承)
Method[] getDeclaredMethods() ;

3、获取 Field 类对象

// a. 获取指定的属性(公共 / 继承)
Field getField(String name) ;
// b. 获取所有的属性(公共 / 继承)
Field[] getFields() ;
// c. 获取指定的所有属性 (不包括继承)
Field getDeclaredField(String name) ;
// d. 获取所有的所有属性 (不包括继承)
Field[] getDeclaredFields() ;

以上方法中,不带 "Declared" 的方法返回某个类的公共方法或属性,继承的方法或属性;带 "Declared" 的方法返回公共、保护、默认(包)访问和私有方法或属性,但不包括继承的方法或属性。

通过 Constructor 、Method 和 Field 分别获取目标类的构造函数、方法和属性的具体信息,并进行后续操作

1、利用反射调用类的构造函数

// 获取 ConstructorClass 类的 Class 对象
Class clazz = ConstructorClass.class;
Object obj1 = clazz.getConstructor().newInstance(); // 输出:无参数构造函数
Object obj2 = clazz.getConstructor(String.class).newInstance("wuzy"); // 输出:有参数构造函数

// 目标类
class ConstructorClass {

    public ConstructorClass() {
        System.out.println("无参数构造函数");
    }

    public ConstructorClass(String str) {
        System.out.println("有参数构造函数");
    }
}

newInstance() 调用默认构造函数,若目标类无构造函数,则抛出异常 NoSuchMethodException。

2、利用反射调用类对象的方法

// 1、获取 MethodClass 类的 Class 对象
Class<?> clazz = MethodClass.class;
// 2、通过 Class 创建 MethodClass 对象
Object object = clazz.newInstance();
// 3、通过 Class 对象获取 add 方法
Method method = clazz.getMethod("add", int.class, int.class);
// 4、通过 Method 调用 add 方法
Object result = method.invoke(object,1,4);
System.out.println(result);   // 输出 5

// 目标类
class MethodClass {

    public MethodClass() {
    }

    public int add(int a, int b) {
        return a + b;
    }
}

3、利用反射获取类的属性

Class clazz = FieldClass.class;
Object object = clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(object, "wuzy");
System.out.println(field.get(object));   // 输出: wuzy

// 目标类
class FieldClass {

    public FieldClass() {}

    private String name;
}

其中, setAccessible 用于屏蔽 Java 语言的访问检查,设为 true 可以访问类的私有属性、方法。

反射的使用场景

1、工厂模式:Factory 类中用反射的话,添加了一个新的类之后,就不需要再修改工厂类 Factory 了

2、数据库 JDBC 中通过 Class.forName(Driver) 来获得数据库连接驱动

3、访问一些不能访问的变量或属性:破解别人代码。

4、实现动态代理。

以上就是反射的基本知识点,需要注意的是由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。通过反射实现动态代理和工厂模式会在后续文章中专门撰写。

原文发布于微信公众号 - 空帆船w(gh_a27e6529b76c)

原文发表时间:2018-09-13

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hbbliyong

Javascript构造函数

     构造函数注意事项: 1.默认函数首字母大写 2.构造函数并没有显示返回任何东西。new 操作符会自动创建给定的类型并返回他们,当调用构造函数时,new...

35911
来自专栏java技术学习之道

java反射详解

1785
来自专栏Ryan Miao

Java复习3-类的继承

本次学习面向对象设计的另外一个基本概念:继承(inheritance)。这是Java程序设计中的一项核心技术。另外,还要学习反射(reflection)的概念。

1022
来自专栏互扯程序

大牛:你真的懂反射吗?

现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

1363
来自专栏开发之途

重拾Java(8)-反射

3407
来自专栏猿学

猿学-深入理解Java中的反射机制

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

410
来自专栏陈纪庚

javascript冷知识

  如果放在数值前的话,对数值不会产生任何影响,不过放在其他的数据类型前面的话,就等于调用number()将他转为数字,布尔值false被转为0,ture被转为...

1123
来自专栏java一日一条

ava enum(枚举)使用详解 + 总结

enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中。

1593
来自专栏柠檬先生

你不知道的javaScript笔记(3)

对象 对象可以通过两种形式定义: 声明形式和构造形式 声明形式语法: var myObj = {key:value} 构造形式语法: var myObj = n...

1865
来自专栏微信公众号:Java团长

Java基础之反射(非常重要)

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

963

扫码关注云+社区

领取腾讯云代金券