反射
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。Java反射机制的功能十分强大,在java.lang.reflect包中提供了对该功能的支持。
访问构造方法
在通过下列一组方法访问构造方法时,将返回 Constructor 类型的对象或数组。每个Constructor 对象代表一个构造方法。
代码案例如下:
package com.mr;
public class Demo1 {
String s;
int i,i2,i3;
public Demo1(){
}
public Demo1(String s,int i) {
this.s=s;
this.i=i;
}
public Demo1(String...strings) {
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;
import java.lang.reflect.Executable;
import com.mr.Demo1;
public class Demo {
public static void main(String[] args) {
Demo1 d1=new Demo1("10","20","30");
Class<?extends Demo1>Demo1Class=d1.getClass();
Constructor[] declaredConstructors=Demo1Class.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]);
}
Demo1 d2=null;
while(d2==null) {
try {//如果构造方法的访问权限为private或protected,则出现异常,即不允许访问
if(i==2)
d2=(Demo1)constructor.newInstance();
else if(i==1)
//通过执行具有两个参数的构造方法创建对象
d2=(Demo1)constructor.newInstance("7",5);
else {
Object[]parameters=new Object[] {new String[] {"100","200","300"}};
d2=(Demo1)constructor.newInstance(parameters);
}
}catch(Exception e) {
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
constructor.setAccessible(true);//设置允许访问
}
}
if(d2!=null) {
d2.print();
System.out.println();
}
}
}
}
运行结果:
访问成员变量
在通过下列一组方法去访问成员变量时,将返回 Field 类型的对象或数组。
代码案例如下:
package com.mr;
public class Demo1 {
int i;
public float f;
protected boolean b;
private String s;
}
import java.lang.reflect.Field;
import com.mr.Demo1;
public class Demo {
public static void main(String[] args) {
Demo1 example=new Demo1();
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或protect,则抛出异常,即不允许访问
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)){//判断成员变量的类型是否为boolean型
System.out.println("利用方法setBoolean()修改成员变量的值");
field.setBoolean(example,true);//为boolean型成员变量赋值
}else{
System.out.println("利用方法set()修改成员变量的值");
field.set(example,"MWQ");//为不同类型的成员变量赋值
}
//获取成员变量值
System.out.println("修改后的值:"+field.get(example));
}catch(Exception e) {
System.out.println("在设置成员变量值时抛出异常,"+"下面执行setAccessible()方法");
field.setAccessible(true);//设置为允许访问
isTurn=true;
}
}
System.out.println();
}
}
}
运行结果:
访问成员方法
在通过下列一组方法访问成员方法时,将返回 Method 类型的对象或数组。
Annotation 注解功能
Java提供了 Annotation 注解功能 ,该功能可用于类、构造方法、成员变量、成员方法、参数等的声明中。该功能不影响程序的运行,但是会对编译器警告等辅助工具产生影响。
定义 Annotation 类型
在定义 Annotation 类型时,也需要用到用来定义接口的 interface 关键字,但需要在 interface字前加一个 “@” 符合,即定义 Annotation 类型的关键字为 @interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//用于字段、方法和参数
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)//在运行时加载Annotation到JVM中
public @interface Field_Method_Parameter_Annotation {
String describe();//定义一个没有默认值的String型成员
Class type()default void.class;//定义一个具有默认值的Class型成员
}
public class Record {
@Field_Method_Parameter_Annotation(describe="编号",type=int.class)
//注释字段
int id;
@Field_Method_Parameter_Annotation(describe="姓名",type=String.class)
String name;
@MyAnnotation()
//采用默认值注释构造方法
public Record(){
}
@MyAnnotation("立即初始化构造方法")
//注释构造方法
public Record(@Field_Method_Parameter_Annotation(describe="编号",type=int.class)int id,
@Field_Method_Parameter_Annotation(describe="姓名",type=String.class)String name){
this.id=id;
this.name=name;
}
@Field_Method_Parameter_Annotation(describe="获取编号",type=int.class)
//注释方法
public int geInt() {
return id;
}
@Field_Method_Parameter_Annotation(describe="设置编号")
//成员type采用默认值注释方法
public void seInt(
//注释方法的参数
@Field_Method_Parameter_Annotation(describe="编号",type=int.class)int id){
this.id=id;
}
@Field_Method_Parameter_Annotation(describe="获取姓名",type=String.class)
public String getName() {
return name;
}
@Field_Method_Parameter_Annotation(describe="设置姓名")
public void setName(@Field_Method_Parameter_Annotation(describe="姓名",type=String.class)String name){
this.name=name;
}
}
访问 Annotation 信息
如果在定义 Annotation 类型时将@RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的 Annotation 信息,如获取构造方法、字段和方法的 Annotation 信息。