内置注解
@Override:限定重写父类方法,作用范围成员方法
@SuppressWarnings:抑制编译器警告,作用范围类、成员属性、成员方法。
@Deprecated:标示已过时,作用范围类、成员属性、成员方法。
public @interface MyAnnotation{
}
@interface:注解关键字
MyAnnotation:注解的名字
@MyAnnotation
public class Demo {}
通过Java的反射机制可以更深入的控制程序的运行过程
反射
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身的信息的功能。
众所周知,所有的Java类均继承了Object类,在Object类中定义一个getClass()方法,该方法返回一个类型为Class的对象。
获取到Class类对象
通过反射可访问的主要描述信息
组成部分 访问方法 返回类型 说明
包路径 getPackage() Package对象 获得该类的存放路径
类名称 getName() String对象 获得该类的名称
基础类 getSuperclass() Class对象 获得该类继承的类
实现接口 getInterfaces() Class型数组 获得该类实现的所有接口
构造方法 getConstructors() Constructor型数组 获得所有权限为public的构造方法
getConstructor() Constructor对象 获得权限为public的指定构造方法
getDeclaredConstructors() Constructor型数组 获得所有构造方法
getDeclaredConstructor() Constructor对象 获得指定构造方法
方法 getMethods() Method型数组 获得所有权限为public的方法
getMethod() Method对象 获得权限为public的指定方法
getDeclaredMethods() Method型数组 获得所有方法
getDeclaredMethod() Method对象 获得指定方法
成员变量 getFields() Field型数组 获得所有权限为public的成员变量
getFfield() Field对象 获得权限为public的指定成员变量
getDeclaredFfields() Field型数组 获得所有成员变量
getDeclaredFfield() Field对象 获得指定成员变量
内部类 getClasses() Class型数组 获得所有权限为public的内部类
getDeclaredClasses() Class型数组 获得所有内部类
内部类的声明类 getDeclaringClass() Class对象 如果该类为内部类,则返回他的成员类,否则返回null
getName会返回包名+类名
getpackage会返回包名
访问构造方法
在通过下列一组方法访问构造方法时,将返回 Constructor 类型的对象或数组。每个Constructor 对象代表一个构造方法。
例题16.1
package 练习;
public class Demo1_161 {//反射一个类的所有构造方法
String s;
int i,i2,i3;
//定义1个String变量和3个int变量和3个构造方法
private Demo1_161() {
}
protected Demo1_161(String s, int i) {
this.s=s;
this.i=i;
}
public Demo1_161(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 练习.Demo1_161;
public class ConsDemo1_161 {
public static void main(String[] args) {
Demo1_161 d1=new Demo1_161("10","20","30");
Class c1=d1.getClass();
//获得所有构造方法
Constructor[]dConstructor=c1.getDeclaredConstructors();
for(int i=0;i<dConstructor.length;i++) {//遍历构造方法
Constructor c=dConstructor[i];
System.out.println("查看是否允许带有可变量的参数:"+c.isVarArgs());
System.out.println("该构造方法的入口参数类型依次为:");
Class[]pT=c.getParameterTypes();//获取所有参数类型
for(int j=0;j<pT.length;j++) {
System.out.println(""+pT[j]);
}
System.out.println("该构造方法可能抛出的异常类型为:");
//获得所有可能抛出的异常信息类型
Class[]eT=c.getExceptionTypes();
for(int j=0;j<eT.length;j++) {
System.out.println(""+eT[j]);
}
Demo1_161 d2=null;
while(d2==null) {
try {//如果构造方法的访问权限为private或protected,则抛出异常。即不允许访问
if(i==2)//通过执行默认没有参数的构造方法创建对象
d2=(Demo1_161)c.newInstance();
else if(i==1)
//通过执行具有两个参数的构造方法创建对象
d2=(Demo1_161)c.newInstance("7",5);
else {
//通过执行具有可变数量参数的构造方法创建对象
Object[]parametes=new Object[] {new String[] {"100","200","300"}};
d2=(Demo1_161)c.newInstance(parametes);
}
}
catch(Exception e) {
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
c.setAccessible(true);//设置为允许访问
}
}
if(d2!=null) {
d2.print();
System.out.println();
}
}
}
}
访问成员变量
在通过下列一组方法去访问成员变量时,将返回 Field 类型的对象或数组。
例题16.2
package 练习;
public class Demo2_162 {//反射一个类的所有变量
//定义一个int,float,boolean,String类型的变量,并赋予不同的访问权限
int i;
public float f;
protected boolean b;
private String s;
}
import java.lang.reflect.Field;
import 练习.Demo2_162;
public class FieldDemo_162 {
public static void main(String[]args) {
Demo2_162 example=new Demo2_162();
Class eC=example.getClass();
Field[]dF=eC.getDeclaredFields();//获取所有成员变量
for(int i=0;i<dF.length;i++) {//遍历成员变量
Field field=dF[i];
System.out.println("名称为:"+field.getName());//获得成员变量名称并输出
Class fT=field.getType();//获得成员变量类型
System.out.println("类型为:"+fT);
boolean isTurn=true;
while(isTurn) {
//如果该成员变量的访问权限为private或protected,则抛出异常,即不允许访问
try {
isTurn=false;
//获得成员变量值
System.out.println("修改前的值为:"+field.get(example));
if(fT.equals(int.class)) {//判断成员变量的类型是否为int型
System.out.println("利用方法setInt()修改成员变量的值");
field.setInt(example,168);//为int型成员变量赋值
}
else if(fT.equals(float.class)){//判断成员变量的类型是否为float型
System.out.println("利用方法setFloat()修改成员变量的值");
field.setFloat(example,99.9F);//为float型成员变量赋值
}else if(fT.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 类型
例题16.4
package 练习;
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 Constructor_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 类型时将@RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的 Annotation 信息,如获取构造方法、字段和方法的 Annotation 信息。