Java反射
一、Annotation的原理解析
https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
二、调用构造函数
1. 走读API
在Class类中提供一下的操作方法:
取得全部构造:
publicConstructor<?>[] getConstructors()
throws SecurityException
取得指定参数类型的构造:
publicConstructor<T> getConstructor(类<?>...parameterTypes)
throws NoSuchMethodException,
SecurityException
在反射过程中是一个只认识类型不认具体对象的工具类,以上方法返回的是
java.lang.reflect.Constructor,这个类有如下方法:
取得构造方法的名称:publicString getName()
取得构造方法的修饰符:publicint getModifiers()
但是所有修饰符都是通过数字编号取得的,即如果想要取得具体的内容必须将相应的数字转为关键字,可以使用“java.lang.reflect.Modifier”类完成,这个类中提供了简单的方法使数字编号转为具体的关键字:public static String toString(int mod);
2. 实例代码1(获取全部,不指定参数)
package cn.km;
import java.io.ObjectStreamException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
class Book {
private String title;
private Double price;
public Book(String title) throwsRuntimeException, NullPointerException,ObjectStreamException {
this.title = title;
}
public Book(String title,Double price){
this.title = title;
this.price = price;
}
@Override
public String toString() {
return"书名: " + this.title + ",价格:" + this.price ;
}
}
publicclassTestDemo {
publicstaticvoid main(String[] args) throwsException{
Class<?> cls =Class.forName("cn.km.Book");
Constructor<?> cons[] = cls.getConstructors();//取得全部构造
for(inti = 0; i < cons.length; i++){
System.out.print(Modifier.toString(cons[i].getModifiers())+ " "); //获取构造函数修饰符
System.out.print(cons[i].getName()+ "("); //获取构造函数名
Class<?>params[] = cons[i].getParameterTypes();
for(intj = 0; j < params.length; j++){
System.out.print(params[j].getSimpleName()+ " arg" + j);
if(j < params.length - 1){
System.out.print(", ");
}
}
System.out.print(") ");
Class<?>exp[] = cons[i].getExceptionTypes(); //取得全部异常信息
if(exp.length > 0){
System.out.print(" throws ");
for(intx = 0; x < exp.length; x++){
System.out.print(exp[x].getSimpleName());
if(x < exp.length - 1){
System.out.print(" , ");
}
}
}
System.out.println();
}
}
}
3. 示例代码2(指定参数)
package cn.km;
import java.io.ObjectStreamException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
class Book2 {
privateString title;
privateDouble price;
Public Book2(String title,Double price)throws RuntimeException, NullPointerException,ObjectStreamException{
this.title= title;
this.price= price;
}
@Override
publicString toString() {
return "书名: " + this.title + ", 价格:" + this.price ;
}
}
public class getConstructorsWithPara {
publicstatic void main(String[] args) throws Exception{
Class<?> cls =Class.forName("cn.km.Book2");
Constructor<?>cons = cls.getConstructor(String.class,Double.class); //取得指定参数构造
Book2 book2 = (Book2)cons.newInstance("java develop",79.6);
System.out.println(book2);
}
}
三、调用普通函数
1. 走读API
清楚了构造函数的调用之后,继续普通函数,在Class类里面提供了两组普通函数获取的方法:
第一组方法:
|-public 方法[] getDeclaredMethods() throwsSecurityException
|-public 方法 getDeclaredMethod(String name,类<?>... parameterTypes)
throwsNoSuchMethodException,
SecurityException
第二组方法:
|-public 方法[] getMethods() throwsSecurityException
|-public 方法 getMethod(String name,类<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException
2. 实例代码3(getMethods和getDeclaredMethods比较)
package cn.km.method;
import java.lang.reflect.Method;
interface Message{
publicvoid print();
}
abstractclass Info{
publicabstractvoid get();
}
class MessageImpl extends Info implements Message{
@Override
publicvoid print() {} //覆盖接口中的方法
@Override
publicvoid get() {} //继承抽象类的方法
publicvoid set() {} //定义自己的方法
}
publicclass TestDemo {
publicstaticvoid main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("cn.km.method.MessageImpl");
Method met[] = cls.getMethods();
for(inti = 0; i < met.length; i++){
System.out.println(met[i]);
}
System.out.println("--------------------------------------");
Method met2[] = cls.getDeclaredMethods();
for(inti = 0; i < met2.length; i++){
System.out.println(met2[i]);
}
}
}
输出结果
使用getMethods获取的
使用getDeclaredMethods获取的是本类中定义的所有操作方法,与继承无关。。
以上的代码是利用了Method类之中的toString()方法取得了每一个方法的信息,现在要获取完整的方法信息,
取得方法的返回值类型:public 类<?> getReturnType()
取得方法的参数类型:public 类<?>[] getParameterTypes()
取得方法的异常信息:public 类<?>[] getExceptionTypes()
3. 实例代码4(获取方法的修饰符、参数类型、异常信息)
package cn.km.method;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
interface Message{
publicvoid print();
}
abstractclass Info{
publicabstractvoid get(String name,Integer age);
}
class MessageImpl extends Info implements Message{
@Override
publicvoid print() {} //覆盖接口中的方法
@Override
publicvoid get(String name,Integer age) {} //继承抽象类的方法
public String set(String name) throws Exception,NullPointerException{
returnnull;
}//定义自己的方法
}
publicclass TestDemo {
publicstaticvoid main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("cn.km.method.MessageImpl");
Method met[] = cls.getDeclaredMethods();
for(inti = 0; i < met.length; i++){
System.out.print(Modifier.toString(met[i].getModifiers()) + " "); //获取方法修饰符
System.out.print(met[i].getReturnType().getSimpleName()+" ");
System.out.print(met[i].getName() + " ( ");
//获取参数类型
Class<?>paramTypes[] = met[i].getParameterTypes();
for(intj = 0 ; j < paramTypes.length; j++){
System.out.print(paramTypes[j].getSimpleName() + " arg" + j);
if(j < paramTypes.length - 1){
System.out.print(" , ");
}
}
System.out.print(" )");
//获取抛出的异常信息
Class<?>exceptions[] = met[i].getExceptionTypes();
if(exceptions.length > 0){
System.out.print(" throws ");
for(intt = 0; t < exceptions.length; t++){
System.out.print( exceptions[t].getSimpleName() );
if(t < exceptions.length - 1){
System.out.print(" , ");
}
}
}
System.out.println();
}
}
}
在Method中提供了一个比较重要的方法:
调用本类的invoke方法:
public Object invoke(Object obj,Object...args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
在使用invoke方法的时候,一定要保证已经存在了本类的实例化对象,而方便的是,这个实例化对象可以是Object
可以直接利用Class类反射的实例化对象,而后通过Object类对象操作。而没有必要向下转型。。
4. 实例代码5(invoke无返回值)
package cn.km.method;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
class Message{
publicvoid echo(String str){
System.out.println(str);
}
}
publicclass TestDemo {
publicstaticvoid main(String[] args) throws Exception {
Class<?> cls = Class.forName("cn.km.method.Message");
Object object = cls.newInstance();
Method method = cls.getDeclaredMethod("echo", String.class);
method.invoke(object, "nihao !");
}
}
5. 实例代码6(invoke 有返回值)
package cn.km.method;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
class Message{
public String echo(String str){
return"echo: " + str;
}
}
publicclass TestDemo {
publicstaticvoid main(String[] args) throws Exception {
Class<?> cls = Class.forName("cn.km.method.Message");
Object object = cls.newInstance();
Method method = cls.getDeclaredMethod("echo", String.class);
String result = (String) method.invoke(object, " nihao !");
System.out.println(result);
}
}
在实际的代码中,简单java类之中的属性一定要进行封装、封装后的属性要按照指定的要求编写setter,getter
6. 实例代码7(利用反射实现getter,setter调用)
package cn.km.method;
import java.lang.reflect.Method;
importcom.sun.xml.internal.ws.util.StringUtils;
class Dept{
private String dname;
public String getDname() {
returndname;
}
publicvoid setDname(String dname) {
this.dname = dname;
}
}
publicclass TestDemo {
publicstaticvoid main(String[] args) throws Exception {
String className = "cn.km.method.Dept";
String property = "dname";
String value = "development";
Class<?> cls = Class.forName(className);
//获取get方法
Method setter = cls.getDeclaredMethod("set" + StringUtils.capitalize(property), String.class);
//获取set方法
Method getter = cls.getDeclaredMethod("get" + StringUtils.capitalize(property));
Object object = cls.newInstance();
//执行set方法
setter.invoke(object, value);
//执行get方法
System.out.println(getter.invoke(object));
}
}
上面有一个小的缺陷就是需要指定set的参数类型。。。。
四、调用成员
一个类中可以定义的成员:全局常量、全局变量、普通常量、普通变量,在Class类中提供了两组取得成员的方法:
第一组:
public 字段[] getFields() throws SecurityException
public 字段 getField(String name)
throws NoSuchFieldException,SecurityException
第二组:
public 字段[] getDeclaredFields() throws SecurityException
public 字段 getDeclaredField(String name)
throws NoSuchFieldException,SecurityException
五、其他
1. StringUtils.capitalize(Stringarg0)
把字符串的首字母大写。如果你传入的字符串首字符本身就是大写,不作任何改变。。