1.Class类与Java反射
Java中反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述, 实现访问、检测和修改描述Java对象本身信息的功能。
所有Java类均继承了Object类,在Object类中定义了一个getClass()方法,该方法返回一个类型为Class的对象。
Class textFieldC = textField.getClass(); //textField为 JTextField类的对象。
利用Class类的对象textFieldC,可以访问用来返回该对象的textField对象的描述信息。
通过反射可访问的主要描述信息
在通过getFields()和getMethods()方法依次获得权限为public的成员变量和方法时,将包含从超类中继承到的成员变量和方法;
通过方法getDeclaredFields() 和getDeclaredMethods()只是获得在本类中定义的所有成员变量和方法。
(a).访问构造方法
通过下列一组方法访问构造方法时,将返回Constructor类型的对象或数组。每个Constructor对象代表一个构造方法,利用Constructor对象可以操纵相应的构造方法。
getConstructors()。
getConstructor(Class<?>…parameterTypes)。
getDeclaredConstructors()。
getDeclaredConstructor(Class<?>…parameterTypes)。
是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。
两种访问一个入口参数类型依次为String和int型的构造方法
objectClass.getDecclaredConstructor(String.class,int.class);
objectClass.getDecclaredConstructor(new Class[]{String.class,int.class}});
Constructor类的常用方法
getModifiers()方法的返 回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以以字符串的形式获得所有修饰符。
Modifier类中的常用解析方法
判断对象constructor所代表的构造方法是否被private修饰,以及以字符串形式获得该构造方法的所有修饰符的典型代码如下:
int modifiers=constructor.getModifiers();
boolean isEmbellishByPrivate=Modifier.Private(modifiers);
String embellishment=Modeiier.toString(modiiers);
public class Example_01{
String s;
int i,i2,i3;
private Example_01(){
}
protected Example_01(String s,int i){
this.s=s;
this.i=i;
}
public Example_01(String...strings)throws NumberFormatException{
if(0<strings.length)
i=Integer.valueOf(strings[0]);
if(1<strings.length)
i2=Integer.valueOf(strings[1]);
if(2<strings.length)
i3=Integer.valueOf(strings[2]);
}
public void print(){
System.out.println("s="+s);
System.out.println("i="+i);
System.out.println("i2="+i2);
System.out.println("i3="+i3);
}
}
import java.lang.reflect.Constructor;
public class Main_01{
public static void main(String[] args){
Example_01 example=new Example_01("10","20","30");
Class<?extends Example_01>exampleC=example.getClass();//获得构造方法
Constructor[] declaredConstructors=exampleC.getDeclaredConstructors();
for(int i=0;i<declaredConstructors.length;i++){//遍历构造方法
Constructor<?>constructor=declaredConstructors[i];
System.out.println("查看是否允许带有可变量的参数:"+constructor.isVarArgs());
System.out.println("该构造方法的入口参数:");
Class[] parameterTypes=constructor.getParameterTypes();//获得所有参数类型
for(int j=0;j<parameterTypes.length;j++){
System.out.println(""+parameterTypes[j]);
}
System.out.println("该构造方法可能抛出大的异常类型为:");
Class[] exceptionTypes=constructor.getExceptionTypes();//获得所有可能的异常信息类型
for(int j=0;j<exceptionTypes.length;j++){
System.out.println(""+exceptionTypes[j]);
}
Example_01 example2=null;
while(example2==null){
try{//如果该成员变量的访问权限为private。则抛出异常,即不允许访问
if(i==2)//通过执行默认没有 参数的构造方法来创建对象
example2=(Example_01)constructor.newInstance();
else if(i==1)
//通过执行具有两个参数的构造方法创建对象
example2=(Example_01)constructor.newInstance("7",5);
else{ //通过执行具有可变量参数的构造方法创建对象
Object[] parameters=new Object[]{new String[] {"100","200","300"}};
example2=(Example_01)constructor.newInstance(parameters);
}
}catch(Exception e){
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
constructor.setAccessible(true);//设置为允许访问
}
}
if(example2!=null){
example2.print();
System.out.println();
}
}
}
}
访问成员变量
通过下列一组方法访问成员变量时,将返回Field类型的对象或数组。每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。
getFields()。
getField(String name)。
getDeclaredFields()。
getDeclaredField(String name)。
如果是访问指定的成员变量,可以通过该成员变量的名称来访问。如访问一个Bird的成员变量:
object. getDeclaredField(“Brid”);
Field类的常用方法
public class Example_02{
int i;
public float f;
protected boolean b;
private String s;
}
import java.lang.reflect.Field;
public class Main_02{
public static void main(String[] args){
Example_02 example=new Example_02();
Class exampleC=example.getClass();
//获得所有成员变量
Field[] declaredFields= exampleC.getDeclaredFields();
for(int i=0;i<declaredFields.length;i++){
Field field=declaredFields[i];
System.out.println("名称为:"+field.getName());//获得成员变量名称
Class fieldType=field.getType();//获得成员变量类型
System.out.println("类型为:"+fieldType);
boolean isTurn=true;
while(isTurn){
//如果该成员变量的访问权限为private。则抛出异常,即不允许访问
try{
isTurn=false;
//获得成员变量值
System.out.println("修改当前的值为:"+field.get(example));
if(fieldType.equals(int.class)){//判断成员变量的类型是否为int型
System.out.println("利用方法setInt()修改成员变量的值");
field.setInt(example,168);//为int型成员变量赋值
}else if(fieldType.equals(float.class)){//判断成员变量的类型是否为float型
System.out.println("利用方法setFloat()修改成员变量的值");
field.setFloat(example,99.9F);//为float型成员变量赋值
}else if(fieldType.equals(boolean.class)){
System.out.println("利用方法setBoolean()修改成员变量的值");
field.setBoolean(example,true);
}else{
System.out.println("利用方法set()修改成员变量的值");
field.set(example,"MVQ");//可以为各种类型成员变量赋值
}
//获得成员变量值
System.out.println("修改后的值为:"+field.get(example));
}catch(Exception e){
System.out.println("在设置成员变量值时抛出异常,"
+"下面执行setAccessible()方法");
field.setAccessible(true);//设置为允许访问
isTurn=true;
}
}
System.out.println();
}
}
}
访问方法
在通过下列一组方法访问方法时,将返回Method类型的对象或数组。每个Method对象代表一个方法,利用Method对象可以操纵相应的方法
getMethods()。
getMethod(String name, Class<?>…parameterTypes)。getDeclaredMethods()。
getDeclaredMethod(String name, Class<?>…parameterTypes)。
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。如访问一个名称为print、入口参数类型依次为String和int型的方法。两种方法都可以实现。
objectClass.getDeclaredMethod(“print”, String.class, int.class);
objectClass.getDeclaredMethod(“print”, new Class[]{String.class, int.class });
Method类的常用方法
2.使用Annotation功能
Java中提供了Annotation功能,该功能可用于类、构造方法、成员变量、方 法、参数等的声明中。
(1).定义Annotation类型
定义Annotation类型的关键字为 @interface,这个关键字的隐含意思是继承了java.lang.annotation.Annotation接口。
public @interface NoMemberAnnotaion{
}
上面定义的的Annotation类型@NoMemberAnnotation未包含任何成员,这样的Annotation类型被称为marker annotation。
下面定义了一个只包含一个 成员的Annotation类型
public @interfce OneMemberAnnoation{
String value();
}
String:成员类型。可用的成员类型有String、Class、primitive、 enumerated和annotation,以及所列类型的数组。
value:成员名称。如果在所定义的Annotation类型中只包含一个成员, 通常将成员名称命名为value。
定义包含多个成员的Annotation类型
public @interace MoreMemberAnnotatioin{
String describe();
Class type();
}
在为Annotation类型定义成员时,也可以为成员设置默认值
public @interface DefautValueAnnotation{
String escribe()default"<默认值>";
Class typedefault"<默认值>";
}
定义Annotation类型时,还可以通过Annotation类型**@Target来设置 Annotation类型适用的程序元素种类**。未设置@Target,则表示适用于所有程序元素。*
枚举类ElementType中的枚举常量用来设置@Targer*。
枚举类ElementType中的枚举常量
通过Annotation类型**@Retention可以设置Annotation的有效范围。**如果未设置@Retention,Annotation的有效范围为枚举常量CLASS表示的范围。
枚举类 RetentionPolicy中的枚举常量用来设置@Retention
枚举类RetentionPolicy中的枚举常量
(2).访问Annotation信息
在定义Annotation类型时将@Retention设置为 RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的 Annotation信息,如获取构造方法、字段和方法的Annotation信息。
Constructor、Field和Method均继承了AccessibleObject类,在 AccessibleObject中定义了3个关于Annotation的方法
a.方法 isAnnotationPresent(Class<? extends Annotation> annotationClass)用 来查看是否添加了指定类型的Annotation,如果是则返回true,否则返回false.
b.方法**getAnnotation(ClassannotationClass)**用来获得指定类型的Annotation,如果存在则返回相应的对象,否则返回null
c.方法 getAnnotations()用来获得所有的Annotation,该方法将返回一个Annotation数组。
在类Constructor和Method中还定义了方法getParameterAnnotations(), 用来获得为所有参数添加的Annotation,将以Annotation类型的二维数组返回,在数组中的顺序与声明的顺序相同,如果没有参数则返回一个长度为0的数组;如果存在未添加Annotation的参数,将用一个长度为0的嵌套数组占位。