动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
Java 反射机制主要提供了以下功能
• 在运行时判断任意一个对象所属的类。
• 在运行时构造任意一个类的对象。
• 在运行时判断任意一个类所具有的成员变量和方法。
• 在运行时调用任意一个对象的方法
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection
APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(
例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改
变fields内容或调用methods
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
– Class类:代表一个类。
– Field 类:代表类的成员变量(成员变量也称为类的属性)。
– Method类:代表类的方法。
– Constructor 类:代表类的构造方法。
– Array类:提供了动态创建数组,以及访问数组的元素的静态方法
获取某个类或者对象所对应的Class对象的常用3种方式:
1) 使用Class类的静态方法forName: Class.forName("java.lang.String");
2) 使用类的.class语法:String.class
3) 使用对象的getClass()方法:String s = "aaa"; Class<?> clazz = s.getClass();
在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法
– getName():获得类的完整名字。
– getFields():获得类的public类型的属性。
– getDeclaredFields():获得类的所有属性。
– getMethods():获得类的public类型的方法。
– getDeclaredMethods():获得类的所有方法。
• getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指 定方法的参数类型。
• getConstructors():获得类的public类型的构造方法。
• getConstructor(Class[] parameterTypes): 获得类的特定构造方法,parameterTypes 参数 指定构造方法的参数类型。
• newInstance():通过类的不带参数的构造方法创建这个类的一个对象
若想通过类的不带参数的构造方法来生成对象,有两种方式:
1) 先获得Class对象,然后通过Class对象的newInstance方法
Class<?> clazz = String.class;
Object obj = class.newInstatnce();
2) 先获得Class对象,然后获取对应的Constructor对象,使用Constructor的newInstance()方法
Class<?> clazz = Customer.class;
Constructor cons = class.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
若想通过类的带参数的构造方法生成对象,只有一种方式
Class<?> clazz = Customer.class;
Constructor cons = class.getConstructor(new Class[]{String.class, int.class});
Object obj = cons.newInstance(new Object[]{"hello", 3});
Note: Integer.TYPE返回的是int, 而Integer.class返回的是Integer类所对应的Class对象
获得对象的所有属性:
• Field fields[]=classType.getDeclaredFields();
• Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性
首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set()
Class<?> clazz = Class.forName("Test");
Field f = clazz.getField("d");
Test obj = new Test();
f.get(obj);
f.set(obj, 123);
方法调用:
InvokerTester invokeTester = new InvokerTester();
Class<?> clazz = invokeTester.getClass();
Method addMethod=clazz.getMethod("add",new Class[]{int.class,int.class});
Object result=addMethod.invoke(invokeTester, new Object[]{new Integer(100),new Integer(200)});
• Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回
由于数组的特殊性, Array类提供了一系列的静态方法用来创建数组和对数组中的元素进行访问和操作。
例如有以下方法:
public void arrayInput(String[] inputs) {}
使用反射可以这样调用:
Class<?> clazz = ...
Object object = clazz.newInstance();
Method method = clazz.getMethod("arrayInput", String[].class);
//Method 1
Object array = Array.newInstance(String.class, 2);//等价于 new String[2]
Array.set(array, 0, "Hello"); //等价于array[0] = "Hello"
Array.set(array, 1, "World"); //等价于array[1] = "World"
method.invoke(object, array);
//Method 2
String[] stringArray = new String[]{"Cafe","Baby"};
arrayInputMethod.invoke(object, new Object[] { stringArray });
还有一个方法是生成多维数组的:
使用Java反射API的时候可以绕过Java默认的访问控制检查,比如可以直接获取到对象的私有域的值或是调用私有方法。只需要在获取到Constructor、Field和Method类的对象之后,调用setAccessible方法并设为true即可。有了这种机制,就可以很方便的在运行时刻获取到程序的内部状态
在编程过程中发现连private static final的都能改变~~
field.setAccessible(true);//平时想要改变private的就用这个
Field modifiersField = Field.class.getDeclaredField("modifiers");//获取modifiers
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); //与取过反的Final类型,这个很经典,也很危险
field.set(null, newValue);
处理泛型
Java 5中引入了泛型的概念之后,Java反射API也做了相应的修改,以提供对泛型的支持。由于类型擦除机制的存在,泛型类中的类型参数等信息,在运行时刻是不存在的。JVM看到的都是原始类型。对此,Java 5对Java类文件的格式做了修订,添加了Signature属性,用来包含不在JVM类型系统中的类型信息。比如以java.util.List接口为例,在其类文件中的Signature属性的声明是<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;> ,这就说明List接口有一个类型参数E。在运行时刻,JVM会读取Signature属性的内容并提供给反射API来使用。
class Customer { public List<String> list; } public static void main(String[] args) throws Exception{ Class<?> clazz = Customer.class; Field field = clazz.getField("list"); Type type = field.getGenericType(); if(type instanceof ParameterizedType) { ParameterizedType type1 = (ParameterizedType)type; Type[] types = type1.getActualTypeArguments(); for(Type t : types) { if(t instanceof Class) { Class<?> clz = (Class)t; System.out.println(clz.getName()); } } } }
打印出来的结果即java.lang.String。
相关推荐
JAVA基础--JAVA中的反射机制详解:本文档详细的介绍了Java的反射API的应用,希望能对各有所帮助
java基础,反射枚举基础,自己总结的笔记。
java基础之一反射笔记
java基础之反射讲解
【Java基础笔记】反射.docx
本Java视频教程适合有一定编程语言基础的学员观看,在本Java视频教程中讲解了Java面向对象、异常、数组、常用类、集合、IO流、线程、反射机制。该视频教程基于Java13进行讲解,Java13是目前Java最新版本。视频中讲师...
结合java最基本的多线程,反射,泛型 对java基础的学习非常有帮助
本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...
Java基础 反射篇 - Java基础 反射篇 - 反射的思想及作用 - 反射的基本使用 - 获取类的 Class 对象 - 构造类的实例化对象 - 获取一个类的所有信息 - 获取类中的变量(Field) - 获取类中的方法(Method) - ...
Java基础之—反射(非常重要)。 一篇文章带你快速了解!
java基础之注解和反射
654.652.JAVA基础教程_反射-获取运行时类的父类及父类的泛型(654).rar
Java基础 反射篇 反射的思想及作用 反射的基本使用 获取类的 Class 对象 构造类的实例化对象 获取一个类的所有信息 获取类中的变量(Field) 获取类中的方法(Method) 获取类的构造器(Constructor) 获取注解 通过...
Java基础入门(四)-泛型、反射、注解
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。...
Java反射机制Java反射机制Java反射机制Java反射机制
JAVA基础JAVA中的反射机制详解.pdf
二、 Java语法基础 5 数据类型 5 运算符号 14 语句 15 函数 15 方法重载(Overloadjing)与重写(Overriding) 16 数组 17 总结 18 三、 常见关键字 20 四、 面向对象★★★★★ 21 五、 封装(面向对象特征之一)★...
完整版 Java基础入门教程 Java程序语言设计 07 网络编程 反射机制(共23页).ppt 完整版 Java基础入门教程 Java程序语言设计 07 网络编程 网络编程(共32页).ppt 完整版 Java基础入门教程 Java程序语言设计 07 网络...
代码为JAVA反射的一个DEMO,适合初学者临摹学习,还附有properties的创建方法,比较基础。