浅谈Java反射的基本运用 - 极悦
首页 课程 师资 教程 报名

浅谈Java反射的基本运用

  • 2020-11-26 17:49:31
  • 958次 极悦

Java反射(Reflection)就是在运行 Java 程序时,可以加载、探知、使用编译期间完全未知的类。也就是说,Java 程序可以加载一个运行时才得知类名的类,获得类的完整构造方法,并实例化出对象,给对象属性设定值或者调用对象的方法。Java反射可以用于判断任意对象所属的类,获得Class对象,构造任意一个对象以及调用一个对象。以此为基础,我们来讲一讲Java反射的基本运用

 

1. 获得Class对象

Class类的实例表示Java应用运行时的类(class and enum)或接口(interface and annotation)(每个Java类运行时都在JVM里表现为一个Class对象,可通过类名.class,类型.getClass(),Class.forName("类名")等方法获取Class对象)。基本类型boolean,byte,char,short,int,long,float,double和关键字void同样表现为Class对象。

声明普通的Class对象,在编译器并不会检查Class对象的确切类型是否符合要求,如果存在错误只有在运行时才得以暴露出来。但是通过泛型声明指明类型的Class对象,编译器在编译期将对带泛型的类进行额外的类型检查,确保在编译期就能保证类型的正确性。

 

2.判断是否为某个类的实例

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);

 

3.创建实例

使用Class对象的newInstance()方法来创建Class对象对应类的实例

classObj.newInstance() 只能够调用public类型的无参构造函数,此方法是过时的。

Class<?> c = String.class;

Object str = c.newInstance();

先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。

可以根据传入的参数,调用任意构造函数,在特定情况下,可以调用私有的构造函数,此方法是推荐使用的。

 

//获取String所对应的Class对象

Class<?> c = String.class;

//获取String类带一个String参数的构造器

Constructor constructor = c.getConstructor(String.class);

//根据构造器创建实例

Object obj = constructor.newInstance("23333");

System.out.println(obj);

 

4.获取方法

getMethods()

返回某个类的所有public方法,包括自己声明和从父类继承的。

getDeclaredMethods()

获取所有本类自己的方法,不问访问权限,不包括从父类继承的方法

getMethod(String name, Class<?>... parameterTypes)

方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

Method getDeclaredMethod(String name, Class<?>... params)

方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象

 

操作私有方法

/**

 * 访问对象的私有方法

 * 为简洁代码,在方法上抛出总的异常,实际开发别这样

 */

private static void getPrivateMethod() throws Exception{

    //1. 获取 Class 类实例

    TestClass testClass = new TestClass();

    Class mClass = testClass.getClass();

 

    //2. 获取私有方法

    //第一个参数为要获取的私有方法的名称

    //第二个为要获取方法的参数的类型,参数为 Class...,没有参数就是null

    //方法参数也可这么写 :new Class[]{String.class , int.class}

    Method privateMethod =

            mClass.getDeclaredMethod("privateMethod", String.class, int.class);

 

    //3. 开始操作方法

    if (privateMethod != null) {

        //获取私有方法的访问权

        //只是获取访问权,并不是修改实际权限

        privateMethod.setAccessible(true);

 

        //使用 invoke 反射调用私有方法

        //privateMethod 是获取到的私有方法

        //testClass 要操作的对象

        //后面两个参数传实参

        privateMethod.invoke(testClass, "Java Reflect ", 666);

    }

}

 

5.获取构造函数

Constructor[] getConstructors()

 

获得类的所有公共构造函数

 

Constructor getConstructor(Class[] params)

 

获得使用特殊的参数类型的公共构造函数,

 

Constructor[] getDeclaredConstructors()

 

获得类的所有构造函数

 

Constructor getDeclaredConstructor(Class[] params)

 

获得使用特定参数类型的构造函数

 

6. 获取成员变量字段

Field[] getFields()

 

获得类的所有公共字段

 

Field getField(String name)

 

获得命名的公共字段

 

Field[] getDeclaredFields()

 

获得类声明的所有字段

 

Field getDeclaredField(String name)

 

获得类声明的命名的字段

 

修改私有变量

**

 * 修改对象私有变量的值

 * 为简洁代码,在方法上抛出总的异常

 */

private static void modifyPrivateFiled() throws Exception {

    //1. 获取 Class 类实例

    TestClass testClass = new TestClass();

    Class mClass = testClass.getClass();

 

    //2. 获取私有变量

    Field privateField = mClass.getDeclaredField("MSG");

 

    //3. 操作私有变量

    if (privateField != null) {

        //获取私有变量的访问权

        privateField.setAccessible(true);

 

        //修改私有变量,并输出以测试

        System.out.println("Before Modify:MSG = " + testClass.getMsg());

 

        //调用 set(object , value) 修改变量的值

        //privateField 是获取到的私有变量

        //testClass 要操作的对象

        //"Modified" 为要修改成的值

        privateField.set(testClass, "Modified");

        System.out.println("After Modify:MSG = " + testClass.getMsg());

    }

}


7.调用方法

当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。invoke 方法的原型为:

public Object invoke(Object obj, Object... args)

        throws IllegalAccessException, IllegalArgumentException,

           InvocationTargetException

下面是一个实例

public class test1 {

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

        Class<?> klass = methodClass.class;

        //创建methodClass的实例

        Object obj = klass.newInstance();

        //获取methodClass类的add方法

        Method method = klass.getMethod("add",int.class,int.class);

        //调用method对应的方法 => add(1,4)

        Object result = method.invoke(obj,1,4);

        System.out.println(result);

    }

}

class methodClass {

    public final int fuck = 3;

    public int add(int a,int b) {

        return a+b;

    }

    public int sub(int a,int b) {

        return a+b;

    }

}


8.利用反射创建数组

数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:

public static void testArray() throws ClassNotFoundException {

        Class<?> cls = Class.forName("java.lang.String");

        Object array = Array.newInstance(cls,25);

        //往数组里添加内容

        Array.set(array,0,"hello");

        Array.set(array,1,"Java");

        Array.set(array,2,"fuck");

        Array.set(array,3,"Scala");

        Array.set(array,4,"Clojure");

        //获取某一项的内容

        System.out.println(Array.get(array,3));

    }


以上就是Java反射的基本运用,这些运用离不开Java反射的核心: JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。对于Java反射的核心分析,可以观看本站的Java基础教程


选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交