什么是反射
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射有什么用
1,在运行时判断任意一个对象所属的类;
2,在运行时构造任意一个类的对象;
3,在运行时判断任意一个类所具有的成员变量和方法;
4,在运行时调用任意一个对象的方法;
5,生成动态代理。
实现Java反射的类
1)Class:它表示正在运行的Java应用程序中的类和接口
2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
4)Method:提供关于类或接口中某个方法信息
注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
编写Java反射程序的步骤:
1)必须首先获取一个类的Class对象
例如:
Class c1 = Test.class;
Class c2 = Class.forName(“com.reflection.Test”);
Class c3 = new Test().getClass();
2)然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构 注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
Field
Constructor
Method
在此给出一个总结性的例子:
package com.gbx;
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;
interface IBase{
void show();
}
class Base{
}
class Person extends Base implements IBase{
private int id;
public String name;
protected int[] ages;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(int id, String name, int[] ages) {
super();
this.id = id;
this.name = name;
this.ages = ages;
}
@Override
public void show() {
System.out.println("人物信息为:" +id + " " + name + " " + ages);
}
}
public class Test {
/*
* 动态获取指定类的各种信息
* 1,在运行时判断任意一个对象所属的类;
* 2,在运行时构造任意一个类的对象;
* 3,在运行时判断任意一个类所具有的成员变量和方法;
* 4,在运行时调用任意一个对象的方法;
*/
public static void test1() throws ClassNotFoundException{
Class c1 = Class.forName("com.gbx.Person");
Class c2 = Person.class;
Class c3 = new Person().getClass();
/*
* 获取类所在包名, 通过输出可以看到, 这三种方式得到的Class是一样的
*/
String packe1 = c1.getPackage().toString();
String packe2 = c2.getPackage().toString();
String packe3 = c3.getPackage().toString();
System.out.println(" packe1 = " + packe1 + "\n packe2 = " + packe2 + "\n packe3 = " + packe3);
System.out.println("c1 == c2 : " + (c1 == c2) + "c2 == c3" + (c2 == c3));
/*
* 获得类的访问修饰符
*/
int mod = c1.getModifiers();
//可以输出看看
//System.out.println(Modifier.toString(0) + " : " + Modifier.toString(1) + " : " +Modifier.toString(2) + " : " + Modifier.toString(3) + ":" + Modifier.toString(4));
System.out.println(Modifier.toString(mod));
/*
* 获取制定类的完全限定名字
*/
String calssName = c1.getName();
System.out.println("calssName = " + calssName);
/*
* 获取指定类的父类
*/
Class superCalss = c1.getSuperclass();
System.out.println("superClassName = " + superCalss.getName());
/*
* 获取指定类的实现的接口
*/
Class[] interfaces = c1.getInterfaces();
for (Class inf : interfaces) {
System.out.println("interface name : " + inf.getName());
}
//一下三部分的获取对于我们来说至关重要。。分别是:构造函数, 成员变量, 成员方法
/*
* 获取指定类的构造函数 涉及的类:Constructor
*/
Constructor[] constructors = c1.getConstructors();
System.out.println("构造方法有:");
for (Constructor c : constructors) {
//访问修饰符
mod = c.getModifiers();
String modfier = Modifier.toString(mod);
//构造函数名字
String name = c.getName();
System.out.print(modfier + " " + name + "(");
//参数列表
Class[] paramTypes = c.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i) {
if (i > 0) {
System.out.print(",");
}
if (paramTypes[i].isArray()) {
System.out.print(paramTypes[i].getComponentType().getName() + " [] ");
} else {
System.out.print(paramTypes[i].getName());
}
}
System.out.println(")");
}
/*
* 获取指定类的成员变量 涉及到的类 Field
*/
Field[] fields = c1.getDeclaredFields();
System.out.println("声明的成员变量有:");
for (Field field : fields) {
mod = field.getModifiers();
String modifier = Modifier.toString(mod);
System.out.print(modifier + " ");
Class type = field.getType();
if (type.isArray()) {
System.out.print(type.getComponentType().getName() + " ");
} else {
System.out.print(type.getName() + " ");
}
String name = field.getName();
System.out.println(name);
}
/*
* 获取指定类的成员方法 涉及的类Method
*/
Method[] methods = c1.getDeclaredMethods();
System.out.println("成员方法有:");
for (Method method :methods) {
mod = method.getModifiers();
String modifer = Modifier.toString(mod);
System.out.print(modifer + " ");
Class returnType = method.getReturnType();
if (returnType.isArray()) {
System.out.print(returnType.getComponentType().getName() + " ");
} else {
System.out.print(returnType.getName() + " ");
}
String name = method.getName();
System.out.print(name + " ( ");
Class[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i) {
if (i > 0){
System.out.println(",");
}
if (paramTypes[i].isArray()) {
System.out.print(paramTypes[i].getComponentType().getName());
} else {
System.out.print(paramTypes[i].getName());
}
}
System.out.println(" )");
}
}
/*
* 生成动态代理。
*/
public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class c1 = Class.forName("com.gbx.Person");
Person p = (Person)c1.newInstance();
System.out.println("id = " + p.getId());
System.out.println("name = " + p.getName());
Method method = c1.getDeclaredMethod("setName", String.class);
method.setAccessible(true); //通过这一步设置我们甚至可以访问private的成员
method.invoke(p, "小明");
System.out.println("id = " + p.getId());
System.out.println("name = " + p.getName());
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
test1();
test2();
}
}
输出:
packe1 = package com.gbx
packe2 = package com.gbx
packe3 = package com.gbx
c1 == c2 : truec2 == c3true
calssName = com.gbx.Person
superClassName = com.gbx.Base
interface name : com.gbx.IBase
构造方法有:
public com.gbx.Person(int,java.lang.String,int [] )
public com.gbx.Person()
声明的成员变量有:
private int id
public java.lang.String name
protected int ages
成员方法有:
public void setId ( int )
public void show ( )
public java.lang.String getName ( )
public int getId ( )
public void setName ( java.lang.String )
id = 0
name = null
id = 0
name = 小明
反射调用参数维数组的方法:
public class DemoTest {
/*
* 利用反射对参数是数组的方法的调用。
* 由于JDK5之前没有可变参数, 我们如果实现参数任意的话,就需要使用object[]来实现
* JDK5出现之后我们有了可变参数的就很方便了,但是为了兼容之前的代码,我们的可变参数接受数组,
* 然后将数组中的变量一个一个的放入对应的对应的变量。
* 如果方法参数是数组,例如public void show(String[] res)
* method.invoke(1,2);第二个参数接受的是的可变参数,我们传入一个数组的话,他会将数组中的第一
* 个值作为res的。后边的继续作为下一个参数。所以不会找到
*/
@Test
public void test() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class clazz = Class.forName("com.cn.gbx.Person");
Method method = clazz.getMethod("main",String[].class);
method.invoke(null, new Object[]{new String[]{"a", "b"}});// 第一种解决方案
}
@Test
public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Person p = new Person();
Class<?> clazz = Class.forName("com.cn.gbx.Person");
Method method = clazz.getMethod("show", String[].class);
method.invoke(p, (Object)new String[]{"aa","bb"}); //第二种解决方案
}
}
package com.cn.gbx;
public class Person {
public static void main(String[] args) {
System.out.println("main invoke ...");
}
public void show(String[] res) {
System.out.println("string[] res");
for (String s : res) {
System.out.println(s);
}
}
}