反射是Java程序开发语言的特征之一。它允许动态地发现和绑定类、方法、字段,以及所有其他的由语言所产生的元素。
Java反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法。通过反射甚至可以调用到private的方法;
Java反射所需要的类并不多,主要有java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
Class类:Class类的对象表示正在运行的 Java 应用程序中的类和接口。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。它封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。它是用来封装反射类方法的一个类。
Array类:提供了动态创建数组和访问数组的静态方法。该类中的所有方法都是静态方法
class类
JVM为每种类型管理着一个独一无二的Class对象----每个类(型)都有一个Class对象。
Java程序运行过程中,当需要创建某个类的实例时,JVM首先检查所要加载的类对应的Class对象是否已经存在。如果还不存在,JVM就会根据类名查找对应的字节码文件并加载,接着创建对应的Class对象,最后才创建出这个类的实例。
运行中的类或接口在JVM中都会有一个对应的Class对象存在,它保存了对应类或接口的类型信息。要想获取类或接口的相应信息,需要先获取这个Class对象。
获得Class对象
调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。
例如, MyObject x=new MyObject(); Class c1 = x.getClass();
使用Class类的forName()静态方法获得与字符串对应的Class对象。
Class c2=Class.forName("java.lang.String");
注意:参数字符串必须是类或接口的完全限定名。
使用类型名.class获取该类型对应的Class对象。
例如,Class cl1 = Manager.class; Class cl2 = int.class; Class cl3 = double[].class;
使用反射机制来获取类的详细信息、创建类的对象、访问属性值、调用类的方法等。
获取类型信息
要在运行时获取某个类型的信息,需先获取这个类型所对应的Class对象,然后调用Class类提供的相应方法来获取。
获取指定类对应的Class对象 Class
clazz = Class.forName("java.util.ArrayList");
获取指定类的包名clazz.getPackage()获取此Class对象所对应的实体所在的包的信息描述类java.lang.Package的一个对象。
String packageName = clazz.getPackage().getName();
获取指定类的修饰符 通过Class对象的getModifiers()方法可以获取此Class对象所对应的实体的用整数表示的类修饰符值。
int mod = clazz.getModifiers(); String modifier = Modifier.toString(mod);
获取指定类的完全限定名 className = clazz.getName();
获取指定类的父类 superClazz = clazz.getSuperclass();
获取指定类实现的接口
通过Class对象的getInterfaces()方法可以获取此Class对象所对应的实体实现的所有接口的Class对象数组。
Class[] interfaces = clazz.getInterfaces();
获取指定类的成员变量
通过Class对象的getFields()方法可获取此Class对象所对应的实体的所有public字段(成员变量)。如果要获取所有字段,可以使用getDeclaredFields()方法。
注意:方法返回的是java.lange.reflect.Field类的对象数组。Field类用来代表字段的详细信息。通过调用Field类的相应方法可以获取字段的修饰符、数据类型、字段名等信息。
获取类的构造方法 通过Class对象的getConstructors()方法可获取该Class对象所对应的实体的所有public构造方法。如果要获取所有的构造方法,可以使用getDeclaredConstructors()方法。
Constructor[] constrcutors = clazz.getDeclaredConstructors();
获取类的成员方法 通过Class对象的getMethods()方法获取到的是该Class对象所对应的实体的所有public成员方法。如果要获取所有成员方法,可以使用getDeclaredMethods()方法。
Method[] methods = clazz.getDeclaredMethods();
创建对象
以前,创建对象的方法通常都是通过new操作符调用该类的构造方法来创建的。
例如,Date currentDate = new Date();
大多数情况下,这种方式已足够满足需求。因为在编译期间,已经知道要创建的对象所对应的类名称。
但是,如果现在编写一个开发工具软件,将可能直到运行时才知道要创建的对象所对应的类名称。
例如,一个GUI开发工具可以让用户拖拽各种图形组件到设计界面上。
public Object create(String className){
根据类名来创建出它的对象
返回这个新创建的对象
}
使用无参构造方法
如果要使用无参的构造方法创建对象,只需调用这个类对应的Class对象的newInstance()方法。 Class c = Class.forName("java.util.ArrayList"); List list = (List) c.newInstance();
需要注意的是:如果指定名称的类没有无参构造方法,在调用newInstance()方法时会抛出一个NoSuchMethodException异常。
使用带参数的构造方法
要使用带参数的构造方法来创建对象,可以分为如下3个步骤来完成。
第1步 获取指定类对应的Class对象。
第2步 通过Class对象获取满足指定参数类型要求的Constructor对象。
第3步 调用指定Constructor对象的newInstance方法,传入对应的参数值,创建对象。
调用方法 使用反射可以取得指定类的指定方法的对象代表,方法的对象代表就是java.lang.reflect.Method类的实例,通过Method类的invoke方法可以动态调用这个方法。
public Object invoke(Object obj, Object... args) throws IllegalAccessException,IllegalArgumentException, InvocationTargetException
该方法的第一个参数是一个对象类型,表示要在指定的这个对象上调用这个方法
第二个参数是一个可变参数,用来给这个方法传递参数值;
invoke方法的返回值用来表示动态调用指定方法后的实际返回值。
访问成员变量的值
使用反射可获取类的成员变量的对象代表,成员变量的对象代表是java.lang.reflect.Field类的实例,可以使用它的getXXX方法来获取指定对象上的值,也可以调用它的setXXX方法来动态修改指定对象上的值,
其中的XXX表示成员变量的数据类型。
在实际开发中,为了达到各个类之间的依赖关系剥离(也就是经常说的解耦),在对类的调用和实例化的时候,通过在配置文件中配置相应的类名,在程序中读取类名,然后通过反射技术在程序中加载和实例化,如常见的数据库驱动程序类,为了达到不依赖特定数据库驱动类,将用到的数据库驱动类名放到配置文件中(常用的有XML文件、Properties文件和文本文件),然后在程序中加载驱动,来实现对数据库的解耦,也就是说只要修改配置文件,就可以方便地更改数据库类型。
Properties文件的处理
Java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是“键=值”的格式,也就是说文件的每一行都是先定义一个键名,然后等于号后面是值,在properties文件中,可以用“#”来作注释,
properties文件在Java编程中用到的地方很多,操作很方便。最常见的操作该类文件的方法是通过Properties类来完成。
JDK 中的 Properties 类存在于包java.util 中,该类继承自 Hashtable ,主要方法包括:
getProperty(String key):用指定的键在此属性列表中搜索属性。也就是通过参数 key ,得到key所对应的 value。
load(InputStream inStream) :从输入流中读取属性列表(键和元素对)。通过对指定的文件进行装载来获取该文件中的所有键-值对,以供getProperty(String key) 来搜索。
setProperty(String key, String value):调用Hashtable的方法put 。来设置“键-值”对。
store(OutputStream out, String comments):以适合使用load方法加载到Properties表中的格式,将此Properties表中的属性列表(键和元素对)写入输出流。
clear ():清除所有装载的“键-值”对。
源码:
Student.java
package com.ifly.classpractice.day7_29.reflect;
public class Student {
private String name;
public int age;
protected String password;
private boolean isGoodStudent;
public void run() {
System.out.println("public run()被调用");
}
private String eat(String str) {
System.out.println("private eat() 被调用 ");
return str;
}
void sing() {
}
public void read(int a, String b) {
System.out.println("public read()被调用");
}
/**
*
*/
public Student() {
}
/**
* @param name
* @param age
* @param password
*/
public Student(String name) {
this.name = name;
}
/**
* @param name
* @param age
*/
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
/**
* @param name
* @param age
* @param password
* @param isGoodStudent
*/
public Student(String name, int age, String password, boolean isGoodStudent) {
super();
this.name = name;
this.age = age;
this.password = password;
this.isGoodStudent = isGoodStudent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isGoodStudent() {
return isGoodStudent;
}
public void setGoodStudent(boolean isGoodStudent) {
this.isGoodStudent = isGoodStudent;
}
}
GetClassTest.java
package com.ifly.classpractice.day7_29.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.TypeVariable;
/**
* JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
* 对于任意一个对象,都能够调用它的任意一个方法和属性;
* 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
*
*/
public class GetClassTest {
public static void main(String[] args) throws ClassNotFoundException {
//获得class类 3中方法
Class<Student> clazz = (Class<Student>) Class.forName("com.ifly.classpractice.day7_29.reflect.Student");
// System.out.println(clazz);
//
// Class clazz1 = new Student().getClass();
// System.out.println(clazz1);
//
// Class clazz2 = Student.class;
// System.out.println(clazz2.getName());
//
// System.out.println("==========================\n");
// GetClassFields(clazz); //获得字段
// Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
// GetClassMethods(clazz); //获得方法
// GetConstructor(clazz); //获得构造器
// GetNewInstance(clazz); //获得实例
GetInvoke(clazz); //动态调用方法
// changeFieldValue(clazz);//动态设置field
}
/**
* 动态设置field
*/
private static void changeFieldValue(Class<Student> clazz) {
try {
// Constructor constructor = clazz.getConstructor(String.class);
// Object object = constructor.newInstance("康平");
Object object = clazz.getConstructor(String.class, int.class).newInstance("康平", 2);
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
//得到field的值
String nameFieldValue = (String) field.get(object);
System.out.println(nameFieldValue);
field.set(object, "毛泽东");
System.out.println(((Student) object).getName());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
/**
* 动态调用方法
*/
private static void GetInvoke(Class clazz) {
try {
Object object = clazz.getConstructor().newInstance();
Method method = clazz.getDeclaredMethod("run");
method.invoke(object);
Method method2 = clazz.getDeclaredMethod("eat", String.class);
method2.setAccessible(true); //调用私有方法
Object o = method2.invoke(object, "吃饭"); //处理返回值
System.out.println(o);
Method method3 = clazz.getDeclaredMethod("read", int.class, String.class);
//method3.invoke(object, 2, "bb"); //无返回值
Object[] b = new Object[] { 2, "bb" };
method3.invoke(object, b); //无返回值
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
/**
* 获得实例
*/
private static void GetNewInstance(Class clazz) {
try {
//通过无参构造器生成实例
Object object = clazz.getConstructor().newInstance();
System.out.println(((Student) object).getName());
//通过有参构造器生成实例
Object obj = clazz.getConstructor(String.class).newInstance("kangping");
System.out.println(((Student) obj).getName());
System.out.println(((Student) obj).getAge());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
/**
* 获得构造器
*/
private static void GetConstructor(Class clazz) {
// 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
}
System.out.println("=====");
try {
Constructor constructor = clazz.getConstructor(); //无参构造器
System.out.println(constructor.getModifiers());
System.out.println(Modifier.toString(constructor.getModifiers()) + " " + constructor.getName());
Constructor constructor2 = clazz.getConstructor(String.class, int.class, String.class); //有参构造器
System.out.println(Modifier.toString(constructor2.getModifiers()) + " " + constructor2.getName());
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
/**
* 获得方法
*/
private static void GetClassMethods(Class<?> clazz) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("==========================\n");
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(Modifier.toString(method.getModifiers()) + " " + method.getName());
}
System.out.println("==========================\n");
try {
Method method = clazz.getMethod("read", int.class, String.class);
for (Class parameter : method.getParameterTypes()) {
System.out.println(parameter.getName());
}
for (TypeVariable typeParameter : method.getTypeParameters()) {
System.out.println(typeParameter + " dd");
}
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
private static void GetClassFields(Class<?> clazz) {
Field[] fields = clazz.getFields(); //可访问公共字段。
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("==========================\n");
Field[] fields1 = clazz.getDeclaredFields(); //声明的所有字段。
for (Field field : fields1) {
System.out.println(field.getName());
}
System.out.println("==========================\n");
try {
Field field = clazz.getField("age");
System.out.println(field.getName());
//返回此类或接口以整数编码的 Java 语言修饰符。
System.out.println(field.getModifiers() == Modifier.PUBLIC);
System.out.println(field.getModifiers() == Modifier.PRIVATE);
} catch (Exception e) {
}
}
}
ReflectionBasic.java
package com.ifly.classpractice.day7_29.reflection;
import java.lang.reflect.*;
public class ReflectionBasic {
public static void main(String[] args) throws ReflectiveOperationException {
// getClassObject();
// getClassFields(Student.class);
getClassMethods(Student.class);
}
/**
* 获取类的Class对象
*/
private static void getClassObject() throws ReflectiveOperationException {
// Class clz1 = Class.forName("com.ifly.javaadvanced.reflection.INode");
// System.out.println("Class.forName:\n" + clz1);
Class clz2 = new Student().getClass();
System.out.println("stu.getClass():\n" + clz2);
//
// Class clz3 = Student.class;
// System.out.println("Student.class:\n" + clz3);
}
/**
* 获取字段
*
* @param clz
* @throws ReflectiveOperationException
*/
private static void getClassFields(Class clz) throws ReflectiveOperationException {
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("=========美丽的昏割线=============");
Field[] declaredFields = clz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field.getName());
}
System.out.println("=========美丽的昏割线2=============");
Field field = clz.getField("isGood");// getDeclaredField
System.out.println(field.getName());
//
System.out.println("is public:" + (field.getModifiers() == Modifier.PUBLIC));
}
/**
* 获取方法
*
* @param clz
* @throws ReflectiveOperationException
*/
private static void getClassMethods(Class clz) throws ReflectiveOperationException {
Method[] methods = clz.getMethods();// public的,也包括继承的
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println("=========美丽的昏割线=============");
Method[] declaredMethods = clz.getDeclaredMethods();// 所有的,但不包括继承的方法
for (Method method : declaredMethods) {
System.out.println(method.getName());
}
System.out.println("=========美丽的昏割线2=============");
Method method = clz.getDeclaredMethod("doSth", int.class, String.class);
System.out.println(method.getName());
method.getModifiers();//
System.out.println("=========美丽的昏割线3=============");
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterClz : parameterTypes) {
String parameterName = parameterClz.getName();
System.out.println("参数类型:" + parameterName);
}
}
/*==================昏割线:除了以上,你还能更获取更多资讯:==========================
* class隶属哪个package
* class导入哪些classes
* class(或methods, fields)的修饰符
* class/interface
* 参数
* 基类
* 实现的接口
* 内部classes
* 构造函数
* 方法
* 字段
* 方法:注解
/*===================下面,你讲可以看到更激动人心的功能:见ReflectionDynamicFeature.java======================================================
/*
* (1) 动态初始化一个对象;
* (2) 动态调用方法;
* (3) 动态改变字段的值;
* */
}
ReflectionDynamicFeature.java
package com.ifly.classpractice.day7_29.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* (1) 动态初始化一个对象; (2) 动态调用方法; (3) 动态改变字段的值;
*/
public class ReflectionDynamicFeature {
public static void main(String[] args) throws ReflectiveOperationException {
// createInstance();
// invokeMethod();
changeFieldValue();
}
/**
* 创建实例
*/
private static void createInstance() throws ReflectiveOperationException {
Class stuClass = Class
.forName("com.ifly.javaadvanced.reflection.Student");
Constructor constructor = stuClass.getConstructor();
Object obj = constructor.newInstance();
System.out.println(((Student) obj).getName());
Constructor constructor2 = stuClass.getConstructor(String.class);
Object stu2 = constructor2.newInstance("xiaoming");
System.out.println(((Student) stu2).getName());
}
/**
* 动态调用方法
*/
private static void invokeMethod() throws ReflectiveOperationException {
Class stuClass = Class
.forName("com.ifly.javaadvanced.reflection.Student");
Constructor constructor = stuClass.getConstructor();
Object obj = constructor.newInstance();
Method method = stuClass.getDeclaredMethod("sayHello", String.class);
method.invoke(obj, "xiaoming");
Method privateMethod = stuClass.getDeclaredMethod("doSth", int.class,
String.class);
privateMethod.setAccessible(true);// 设置允许调用
Object[] params = new Object[] { 123, "i hava a dream." };
Object returnValue = privateMethod.invoke(obj, params);
System.out.println(returnValue);
}
/**
* 动态设置field
*/
private static void changeFieldValue() throws ReflectiveOperationException {
Class stuClass = Class
.forName("com.ifly.javaadvanced.reflection.Student");
Constructor constructor = stuClass.getConstructor(String.class);
Object stu = constructor.newInstance("xiaoming");
Field field = stuClass.getDeclaredField("name");
field.setAccessible(true);
String nameFieldValue = (String) field.get(stu);
System.out.println(nameFieldValue);
field.set(stu, "毛泽东");
System.out.println(((Student) stu).getName());
}
}