一、简介
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。
反射机制主要提供一下功能:
在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法;
简单示例:
package com.wbf.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person {
public static final String FIELD = "field";
private int age;
private String name;
public Person(){}
public Person(int age, String name){
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ReflectDemo {
public static void main(String[] args) {
Person per = new Person(20, "shangsan");
//返回对象per的运行时类,即:com.wbf.reflect.Person
//public final Class<?> getClass()
//per.getClass()得到的是com.wbf.reflect.person类,用Class类声明的对象类接收
//等价于:Person extends Class
//那么,Person类的实例对象per也可认为是Class类的实例对象
//以此类推,所有类的对象实际上都是Class类的实例
Class pc = per.getClass();
System.out.println(pc.getName());
System.out.println(pc.getSimpleName());
System.out.println(pc.getPackage());
Constructor[] cons = pc.getDeclaredConstructors();//pc.getConstructors()
//返回一个包含某些 Field对象的数组,这些对象反映此 Class对象所表示的类或接口的所有可访问公共字段
Field[] fields = pc.getDeclaredFields();//pc.getFields()
Method[] methods = pc.getDeclaredMethods();//pc.getMethods()
for (int i = 0; i < cons.length; i++)
{
Constructor con = cons[i];
System.out.print(con.getName() + "、");//输出构造方法名称
}
System.out.println();
for (int j = 0; j < fields.length; j++)
{
Field field = fields[j];
System.out.print(field.getName() + "、");//输出字段名称
}
System.out.println();
for (int k = 0; k < methods.length; k++)
{
Method m = methods[k];
System.out.print(m.getName() + "、");//输出方法名称
}
}
}
二、Class类的使用
Class类在开发中最常见的用法就是实例化对象的操作,即可以通过一个给定的字符串(此字符串包含了完整的“包.类”的路径)来实例化一个类的对象。
1)通过无参构造实例化对象:如果想要通过Class类本身实例化其他类的对象,则可以使用newInstance()方法,但是必须保证被实例化的类中存在一个无参构造方法。
package com.wbf.reflect;
class Student {
private int age;
private String name;
public Student(){}
public Student(int age, String name){
this.setAge(age);
this.setName(name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "姓名:" + this.getName() + ", 年龄: " + this.getAge();
}
}
public class ClassDemo02 {
public static void main(String args[]) throws Exception {
//获取Student类对应的Class类的实例
Class<?> c = Class.forName("com.wbf.reflect.Student");
//实例化Student类,调用无参构造方法
Student s = (Student)c.newInstance();
s.setAge(20);
s.setName("wbf");
//调用toString()方法
System.out.println(s);
}
}
2)通过有参构造实例化对象:a. 通过Class类中的getConstructors()取得本类中的全部构造方法; b. 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数; c. 之后通过Constructor实例化对象
public class ClassDemo02 {
public static void main(String args[]) throws Exception {
//获取Student类对应的Class类的实例
Class<?> c = Class.forName("com.wbf.reflect.Student");
Constructor[] cons = c.getConstructors();
//通过有参构造方法实例化对象
Student s = (Student)cons[1].newInstance(20, "wbf");
System.out.println(s);
}
}
三、反射的基本应用
package com.wbf.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
interface China {
public static final String NATIONAL = "China";
public static final String AUTHOR = "wbf";
public void sayChina();
public String sayHello(String name, int age);
}
class Person implements China {
private String name;
private int age;
public Person(){}
public Person(String name){
this.name = name;
}
public Person(String name, int age){
this(name);
this.age = age;
}
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;
}
@Override
public void sayChina() {
System.out.println("作者:" + AUTHOR + ", 国籍: " + NATIONAL);
}
@Override
public String sayHello(String name, int age) {
return "你好!我叫" + this.name + ", 今年" + this.age + "岁!";
}
}
public class ClassDemo03 {
public static void main(String args[]) throws Exception {
//获取Person类对应的Class类的实例
Class<?> c = Class.forName("com.wbf.reflect.Person");
//1.取得一个类所实现的全部接口
Class<?> interfaces[] = c.getInterfaces();
for (int i = 0; i < interfaces.length; i++)
{
//输出接口名称
System.out.println("实例化的接口名称: " + interfaces[i].getName());
}
//2.取得父类
Class<?> superC = c.getSuperclass();
System.out.println("父类名称: " + superC.getName());
//3.取得全部构造方法
Constructor<?> cons[] = c.getConstructors();
for (int i = 0; i < cons.length; i++)
{
Class<?> ps[] = cons[i].getParameterTypes();
System.out.print("构造方法: ");
System.out.print(Modifier.toString(cons[i].getModifiers()) + " ");//取出权限
System.out.print(cons[i].getName());
System.out.print("(");
for (int j = 0; j < ps.length; j++)
{
System.out.print(ps[j].getName() + " arg" + j);
if (j < ps.length - 1)
{
System.out.print(",");
}
}
System.out.println("){}");
}
//4.取得全部方法,参数类型,返回值类型,异常类型等
//在IDE中就使用此种方法:如当"."的时候会出现一个类的全部方法
Method m[] = c.getMethods();
for (int k = 0; k < m.length; k++)
{
System.out.println(m[k].getName());//输出方法名称
}
//5.取得全部属性
Field[] fs1 = c.getFields();//取得父类的公共属性
Field[] fs2 = c.getDeclaredFields();//取得本类属性
System.out.print("父类公共属性: ");
for (int i = 0; i < fs1.length; i++)
{
System.out.print(fs1[i].getName() + "、");
}
System.out.print("\n" + "本类属性: ");
for (int i = 0; i < fs2.length; i++)
{
System.out.print(fs2[i].getName() + "、");
}
}
}
四、反射机制的深入应用
反射除了可以获取一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。
1)通过反射调用类中方法
package com.wbf.reflect;
import java.lang.reflect.Method;
class People {
private int age;
private String name;
public People(){}
public People(int age, String name){
this.setAge(age);
this.setName(name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayChina(){
System.out.println("Welcome to China!");
}
public String sayHello(String name, int age){
return "我是: " + name + ", 今年: " + age + "岁!!!";
}
}
public class ClassDemo04 {
public static void main(String[] args) throws Exception {
//获取People类对应的Class类的实例对象
Class<?> c = Class.forName("com.wbf.reflect.People");
//根据方法名称和参数类型,获取方法对应的Method对象
//此方法没有参数
Method m = c.getMethod("sayChina");
m.invoke(c.newInstance());//调用方法,必须传递对象实例
m = c.getMethod("sayHello", String.class, int.class);
//调用方法,必须传递对象实例和两个参数值
String returnMess = (String)m.invoke(c.newInstance(), "wbf", 20);
System.out.println(returnMess);
}
}
2)调用setter和getter方法
public class ClassDemo05 {
public static void main(String[] args) throws Exception {
//获取People类对应的Class类的实例对象
Class<?> c = Class.forName("com.wbf.reflect.People");
Object obj = c.newInstance();
setter(obj, "name", "zhangsan", String.class);
System.out.println(getter(obj, "name"));
setter(obj, "age", 20, int.class);
System.out.println(getter(obj, "age"));
}
public static void setter(Object obj, String att, Object value, Class<?> type) throws Exception {
Method m = obj.getClass().getMethod("set" + initStr(att), type);
m.invoke(obj, value);
}
public static Object getter(Object obj, String att) throws Exception {
Method m = obj.getClass().getMethod("get" + initStr(att));
return m.invoke(obj);
}
public static String initStr(String att){
return att.substring(0, 1).toUpperCase() + att.substring(1);
}
}
2)通过反射操作属性
public class ClassDemo04 {
public static void main(String[] args) throws Exception {
//获取People类对应的Class类的实例对象
Class<?> c = Class.forName("com.wbf.reflect.People");
People p = (People)c.newInstance();
Field nameField = c.getDeclaredField("name");//表示name属性
Field ageField = c.getDeclaredField("age");//表示age属性
nameField.setAccessible(true);//将name属性设置成可被外部访问
nameField.set(p, "lisi");//设置name属性内容
ageField.setAccessible(true);
ageField.set(p, 25);
//通过get取得属性内容
System.out.println("姓名: " + nameField.get(p) + ", 年龄: " + ageField.get(p));
}
}
但是通过反射操作属性时最好通过setter及getter方法,因为以上程序是通过扩大属性访问权限后直接操作属性的,但是在开发中属性时必须封装的。
2)通过反射操作数组
反射机制不仅可以用在类上,还可以应用在任意的引用数据类型的数据上,当然,这本身就包含了数组,即可以使用反射操作数组。在反射操作包java.lang.reflect中使用Array类表示一个数组,可以通过此类获取数组长度、数组内容等。
package com.wbf.reflect;
import java.lang.reflect.Array;
public class ClassArrayDemo {
public static void main(String[] args) {
int temp[] = {1, 2, 3};
Class<?> c = temp.getClass().getComponentType();
//获取数组类型名称和数组大小
System.out.println(c.getName() + Array.getLength(temp));
//输出数组元素
for (int i=0; i<Array.getLength(temp); i++)
{
System.out.print(Array.get(temp, i) + "、");
}
Array.set(temp, 0, 10);//修改数组元素内容
System.out.print(Array.get(temp, 0));
}
}
在应用中还可以通过Array类根据已有的数组类型来开辟新的数组对象。
package com.wbf.reflect;
import java.lang.reflect.Array;
public class ClassArrayDemo {
public static void main(String[] args) {
int temp[] = {1, 2, 3};
int newTemp[] = (int[])arrayInc(temp, 5);
print(newTemp);
System.out.println();
String t[] = {"aaa", "bbb", "ccc"};
String nt[] = (String[])arrayInc(t, 8);
print(nt);
}
public static Object arrayInc(Object obj, int len){
Class<?> c = obj.getClass();//得到数组的Class对象
Class<?> arr = c.getComponentType();
Object newO = Array.newInstance(arr, len);
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newO, 0, co);
return newO;
}
public static void print(Object obj){
Class<?> c = obj.getClass();
if (!c.isArray())
return;
Class<?> arr = c.getComponentType();
System.out.println(arr.getName() + Array.getLength(obj));
for (int i=0; i<Array.getLength(obj); i++)
{
System.out.print(Array.get(obj, i) + "、");
}
}
}