Java中的反射该如何使用?

Posted benming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的反射该如何使用?相关的知识,希望对你有一定的参考价值。

1. 什么是反射

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

2. 反射可以用来做什么

反射能够分析类的能力,反射的机制十分强大,主要可以用来:

在运行时分析类的能力

在运行时查看对象

实现通用的数组操作代码

利用Method对象,实现C++中函数指针的功能

3. Class

所谓的反射其实是获取类的字节码文件,也就是.class文件,而获取Class这个对象主要有三种方式:

getClass()函数、.classforName()方法,代码如下:

package core.java;

import java.util.ArrayList;

public class Test

    public static void main(String[] args) throws ClassNotFoundException

        ArrayList<Integer> test = new ArrayList<>();

        //第一种方法

        Class a = test.getClass();

        System.out.println(a);

        //第二种方法

        Class b = Test.class;

        System.out.println(b);

        //第三种方法

        Class c = Class.forName("java.lang.Math");

        System.out.println(c);

    

4. 利用反射分析类

reflect包中有三个类:FieldMethodConstructor分别用于描述类的域、方法和构造器。这三个类都有一个叫做getName()的方法,用来返回项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象。这三个类共同有一个getModifiers的方法,他将返回一个整型数值,来描述修饰符的情况。可以使用Modifier类的静态方法分析其返回的整型数值,也可以使用其toString()方法将对应的修饰符打印出来。

Class类中的getFieldsgetMethodsgetConstructors方法将分别返回类提供的public域、方法和构造器数组,其中包括超类的共有成员。

Class类中的getDeclareFieldsgetDeclareMethodsgetDeclaredConstructors方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。

实例代码:

package core.java.reflect;

import java.util.*;

import java.lang.reflect.*;

public class ReflectionTest

    public static void main(String[] args)

    

        // 读取类名

        String name;

        if (args.length > 0) name = args[0];

        else

        

            Scanner in = new Scanner(System.in);

            System.out.println("Enter class name (e.g. java.util.Date): ");

            name = in.next();

        

        try

        

            Class cl = Class.forName(name);

            Class supercl = cl.getSuperclass();

            String modifiers = Modifier.toString(cl.getModifiers()); //打印修饰符

            if (modifiers.length() > 0) System.out.print(modifiers + " ");

            System.out.print("class " + name);

            if (supercl != null && supercl != Object.class) System.out.print(" extends "

                    + supercl.getName());//输出超类

            System.out.print("\n\n");

            printConstructors(cl); //输出构造器数组

            System.out.println();

            printMethods(cl); //输出方法

            System.out.println();

            printFields(cl);  //输出域

            System.out.println("");

        

        catch (ClassNotFoundException e)

        

            e.printStackTrace();

        

        System.exit(0);

    

    public static void printConstructors(Class cl)

    

        Constructor[] constructors = cl.getDeclaredConstructors(); //获取构造器数组

        for (Constructor c : constructors)

        

            String name = c.getName();

            System.out.print("   ");

            String modifiers = Modifier.toString(c.getModifiers()); //输出修饰符

            if (modifiers.length() > 0) System.out.print(modifiers + " ");

            System.out.print(name + "("); //构造器签名

            // print parameter types

            Class[] paramTypes = c.getParameterTypes(); //获取构造器参数数组

            for (int j = 0; j < paramTypes.length; j++)

            

                if (j > 0) System.out.print(", ");

                System.out.print(paramTypes[j].getName());

            

            System.out.println(");");

        

    

    public static void printMethods(Class cl)

    

        Method[] methods = cl.getDeclaredMethods();

        for (Method m : methods)

        

            Class retType = m.getReturnType(); //获取返回类型

            String name = m.getName(); //方法名

            System.out.print("   ");

            String modifiers = Modifier.toString(m.getModifiers()); //输出修饰符

            if (modifiers.length() > 0) System.out.print(modifiers + " ");

            System.out.print(retType.getName() + " " + name + "(");

            // print parameter types

            Class[] paramTypes = m.getParameterTypes(); //获取参数数组

            for (int j = 0; j < paramTypes.length; j++)

            

                if (j > 0) System.out.print(", ");

                System.out.print(paramTypes[j].getName());

            

            System.out.println(");");

        

    

    public static void printFields(Class cl)

    

        Field[] fields = cl.getDeclaredFields(); //获取域数组

        for (Field f : fields)

        

            Class type = f.getType(); //获取参数类型

            String name = f.getName(); //获取域名称

            System.out.print("   ");

            String modifiers = Modifier.toString(f.getModifiers()); //输出修饰符

            if (modifiers.length() > 0) System.out.print(modifiers + " ");

            System.out.println(type.getName() + " " + name + ";");

        

    

5利用反射技术得到所有的构造函数

public class Test02

public static void main(String[] args)

try

Class clazz = Student.class;// 获取class对象

String name = clazz.getName();// 获得类的名称(全限定名)

Constructor<?>[] constructors = clazz.getDeclaredConstructors();// 返回指定参数类型的所有构造器

for (Constructor constructor : constructors)

System.out.println(constructor);

catch (SecurityException e)

e.printStackTrace();

输出结果:

public com.etime2.Student()

public com.etime2.Student(java.lang.String,java.lang.Integer,java.lang.String)

备注:

getDeclaredConstructor()getConstructor的区别

getDeclaredConstructor(Class<?>parameterTypes)

这个方法会返回指定参数类型的所有构造器,包括public的和非public的,其中当然也包括private私有的。

getDeclaredConstructors()的返回结果就没有参数类型的过滤了。

getConstructor(Class<?>parameterTypes)

这个方法返回的是上面方法返回结果的子集,外汇返佣只返回指定参数类型访问权限是public的构造器。

getConstructors()的返回结果同样也没有参数类型的过滤。

6利用反射技术得到类的所有方法

public class Test03

public static void main(String[] args)

try

Class clazz = Class.forName("com.etime2.Student");// 获取类的class对象(加载和解析类的字节码,返回相应的class对象)

Method[] Methods = clazz.getDeclaredMethods();// 获取所有的方法,包括私有方法

for (Method method : Methods)

String name = method.getName();// 获得类的名称(全限定名)

System.out.println(name);

catch (ClassNotFoundException e)

e.printStackTrace();

输出结果:

getName

setName

sleep

getGender

getAge

setAge

setGender

7利用反射技术得到类的所有字段

public class Test04

public static void main(String[] args)

try

Class clazz = Class.forName("com.etime2.Student");

Field[] fields = clazz.getDeclaredFields();// 获取所有的字段

for (Field field : fields)

System.out.println("字段:" + field);

String name = field.getName();// 获得类的名称(全限定名)

System.out.println("名称:" + name);

Class<?> type = field.getType();// 获取变量的类型

System.out.println("类型:" + type);

int modifiers = field.getModifiers();// 获得类的修饰符

boolean public1 = Modifier.isPublic(modifiers);

boolean static1 = Modifier.isStatic(modifiers);

boolean final1 = Modifier.isFinal(modifiers);

System.out.println("public1=" + public1 + "  static1=" + static1 + "  final1=" + final1);

catch (ClassNotFoundException e)

e.printStackTrace();

输出结果:

字段:private java.lang.String com.etime2.Student.name

名称:name

类型:class java.lang.String

public1=false  static1=false  final1=false

字段:private java.lang.Integer com.etime2.Student.age

名称:age

类型:class java.lang.Integer

public1=false  static1=false  final1=false

字段:private java.lang.String com.etime2.Student.gender

名称:gender

类型:class java.lang.String

public1=false  static1=false  final1=false

利用反射调用对象的私有方法(不完整)

public class Test05

public static void main(String[] args)

try

Class<?> clazz = Class.forName("com.etime2.Student");

Method method = clazz.getDeclaredMethod("sleep");

method.setAccessible(true);// 允许访问私有

Object newInstance = clazz.newInstance();// 调用无参构造函数创建对象

Student student = (Student) newInstance;

Object invoke = method.invoke(student);

System.out.println(invoke);

catch (Exception e)

e.printStackTrace();

运行结果:

上课时间打盹!

null

以上是关于Java中的反射该如何使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何限制开发人员使用反射访问Java中的私有方法和构造函数?

如何从反射访问中过滤特定字段?

07 JVM 是如何实现反射的

如何使用反射访问对象中的字段值

如何理解java中的反射机制,为什么利用反射可以写开源框架?

大厂难进,Java面试该如何一面即中?