Java 反射初次尝试
一.反射的概述
1.1 何为反射
在Java官方给的教程中这样描述Java的反射机制Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.
反射通常用来检测和修改正在Java虚拟机中运行的程序.
在我个人的理解是:它就像脚本语言中eval()函数一样,可以动态的执行一段代码.Java可以说是静态语言(像C,C++)和动态语言(Python,脚本)的混合体,在运行时通过虚拟机解释执行,所以实现反射机制也相对的容易.
1.2 反射的用途
反射的优点:
- 允许程序在运行时通过反射取得任何一个已知名称的class的内部信息,包括:
正在运行中的类的属性信息,正在运行中的类的方法信息,正在运行中的类的构造信息,正在运行中的类的访问修饰符,注解等等。这使得程序的变得更加的灵活.这也是各种框架设计的灵魂所在. - 各种IDE的类浏览器和代码提示
- 调试和测试功能 :调试器需要能够检车类的私有成员.一些测试框架可以通过反射获得该类私有成员,来保证代码的覆盖率
反射的缺点 :
- 反射更加的消耗性能
- 可以访问类的私有成员,这既是优点,也是缺点.可能破坏代码的可移植性
二.Classes
在Java中一个类型不是引用类型(reference)就是原始类型(primitive). 一个类(Class), 枚举(enums),数组(arrays)只要继承了Object都是引用类型.对于各种类型的对象,JVM将会初始化一个不变的Java.lang.Class,来提供方法去修改一个对象的属性(包括 成员变量,类型信息) 这个Class也提供创建新的classes和新的对象(Object). 最重要的时它提供了所有反射API的入口地址(entry point).
2.1 获得类对象
所有反射操作的入口地址都在java.lang.Class.除了java.lang.reflect.ReflectPermission,在java.lang.reflect包下的类都没有public的构造器.为了获得这些class,有一下的几个方法.
- Object.getClass()
Object.getClass()
这个要求是这个对象必须继Object.例如
Class c="foo".getClass();
//返回String的class
其他的一些例子:
Class c=System.console.getClass()
//返回java.io.Console的class
enum E{A,B}
Clss c=A.getClass //返回枚举类型 E对应的Class
byte[] bytes = new byte[1024] //数组也是引用类型,所以可以获得对应的class
Set<String> s = new HashSet<String>();
Class c = s.getClass();
//返回java.util.HashSet.
Class中提供了一个getName()的方法,我们可以打印查看具体的类型
-
Class.forName()
通过一个完整的类的名称获得对应的Class类.这种方法通过一个静态的方法Class.forName()
Class c =Class.forName(com.duke.MyLocalServiceProvider)
//下面的代码需要保证对应的数组类型存在,才可以获取到
//一个Double[]类型
Class cDoubleArray =Class.forName("[D");
// 一个String[][]类型
Class cStringArray = Class.forName("[[Ljava.lang.String")
其实,每个primitive都有对应的包装类,每个包装类都已一个TYPE的常量,我们可以通过它来获得对应的primitive类型对应的包装类的Class
例如:
Class c = Double.TYPE;
Class c = Void.TYPE;
-
一些获得Class的其他方法
例如 :Class.getSuperclass()Class.getClasses()返回该类中的所有公共的类,接口,枚举,或者继承的成员对应的Class
Class<?>[] c = Character.class.getClasses();
// Character.Subset 和 Character.UnicodeBlock.
2.2关于Class的一些语法
primitive类型不可获得对应的Class
boolean b ;
Class c =b.getClass() //错误
Class c =boolean.Class() //正确
Class.getDeclaredClasses() 返回这个类中声明的Class
三. 检测类的修饰和类型
一个类用于一些修饰词来影响程序的结果
例如 :
public protected private
abstract
static
final
strictfp // 精确浮点
public class Main {
@Schedule(hour = 13)
@Schedule(hour = 23)
public static void main(String[] args) {
try {
Class<?> c= Class.forName("com.company.Main");
System.out.printf("Class:%n %s%n%n",c.getCanonicalName());
System.out.printf("Modifiers:%n %s%n%n",
Modifier.toString(c.getModifiers()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出:
Class:
com.company.Main
Modifiers:
public
四. 获取类的成员
4.1 常用的API
这里列出一张表格,跟清晰描述,每个方法的用途
注意:
构造器是不可以被继承的,
List of members只会获得所有的public修饰的
4.2实例
public class Test {
public int id=0;
private String name="Main";
public Test(int id) {
this.id = id;
}
public Test(int id, String name) {
this.id = id;
this.name = name;
}
public Test() {
}
public static void main(String[] args) {
Test test = new Test();
Class c= test.getClass();
Constructor[] constructors;
constructors=c.getConstructors();
for(int i =0;i<constructors.length;i++)
{
System.out.println(Modifier.toString(constructors[i].getModifiers())
+ "参数");
Class[] parameterTypes=constructors[i].getParameterTypes();
for(int j=0;j<parameterTypes.length;j++)
System.out.println(parameterTypes[j].getCanonicalName());
}
}
}
输出:
public参数
public参数
int
java.lang.String
public参数
int
这里我们也可以获得我们想要的构造方法,使用getDeclaredConstructor()
try {
constructors = c.getDeclaredConstructor(); //获得无参构造器
System.out.print(Modifier.toString(constructors.getModifiers()) + );
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
获得Test(int ,String)的构造器
Class[] p = {int.class,String.class};
try {
constructors = c4.getDeclaredConstructor(p);
System.out.print(Modifier.toString(constructors.getModifiers()) + "参数:");
Class[] parametertypes = constructors.getParameterTypes();
for (int j = 0; j < parametertypes.length; j++) {
System.out.print(parametertypes[j].getName() + " ");
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
4.3创建实例
到了这里我们已经可以获得我们想要的构造器,那么该如何使用那?这里需要调用对应的newInstance()方法了.
Class[] p = {int.class,String.class};
constructors = c.getDeclaredConstructor(p);
try {
constructor=c.getConstructor(p);
constructor.newInstance(23,"HUA");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
输出:
the id is 23 the name is HUA
4.4调用私有构造器
只需要设置constructor.setAccessible(true);即可
4.5调用类的私有方法
Method method =c.getDeclaredMethod("welcome",new Class[]{String.class});
method.setAccessible(true); //可以调用私有方法
method.invoke(test,"hello");
输出 :
this is test privste method
hello
4.6获取类私有属性
Field field = c.getDeclaredField("name");
field.setAccessible(true);
field.set(test,"HuaTest");
System.out.println(field.get(test));
输出:
HuaTest