反射和注解
- 反射
通过反射机制,可以访问到已经加载到jvm中的对象的信息,实现访问、检测、和修改描述java对象本身信息的功能。
所有的Class类均继承Object类,定义可以getClass方法,可以返回一个Class类型的对象。利用该对象,可以访问该类型的信息。
- 访问构造方法(Constructor)
通过下列方法,可以返回一个Constructor对象或者数组,每个对象代表一个构造方法。
访问方法 |
返回值类型 |
说明 |
getConstructors() |
Constructor数组 |
获得所有权限为public的构造方法 |
getConstructor(Class<?>...parametertypes) |
Constructor对象 |
根据参数类型获得权限为public的指定构造方法 |
getDeclaredConstructors() |
Constructor数组 |
获得所有的构造方法 |
getDeclaredConstructor(Class<?>...parametertypes) |
Constructor对象 |
根据参数类型获得指定构造方法 |
如果根据参数类型访问一个构造方法,一下两种方式都可以是实现:
getDeclaredConstructor(String.class,int.class);
);
getDeclaredConstructor(new Class[]{String.class,int.class});
Constructor类的常用方法如下所示:
方法 |
说明 |
返回类型 |
IsVarArgs() |
判断构造方法中是否含有可变数量的参数 |
Boolean |
getParameterTypes() |
返回参数类型 |
Class数组 |
getExceptionTypes() |
返回构造方法可以抛出的异常的类型 |
Class数组 |
newInstance(Object...initargs) |
通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示为无参构造方法 |
|
setAccessible() |
不允许利用权限为private的构造方法创建新对象,执行此方法并将入口参数设置为true可以允许创建 |
|
getModifiers() |
获得权限修饰符代表的整数 |
Int |
|
|
|
实例代码:
package constructor;
public class Person { private String name; private int age;
public Person(){} //无参构造方法
public Person(String nmae,int age){ //有参 this.name=name; this.age=age; }
private Person(String name){ this.name=name; this.age=20; }
public Person(String...strings){ this.name=strings[0]; this.age=strings.length;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } }
package constructor;
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier;
public class PersonTest {
public static void main(String[] args) { // TODO Auto-generated method stub /*Person p1=new Person(); Person p2=new Person("sxb",20); Person p3=new Person("sss","xxx","bbb"); String p3name=p3.getName(); int p3age=p3.getAge(); System.out.println(p3name); System.out.println(p3age);*/ try { method1(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
public static void method1() throws NoSuchMethodException, SecurityException{ //Class p=Person.class;
//Class<? extends Person>p1=person.getClass(); Class<?> p1=null;
try { p1=Class.forName("constructor.Person"); } catch (Exception e) { // TODO: handle exception }
//不论怎么获得p1,p1必须是object类型
Constructor[] con1=p1.getConstructors(); //获得权限为public的构造方法,返回的是一个Constructor型数组 System.out.println("con1:"+con1);
//获取指定的权限为public的构造方法,返回一个Constructor对象,如果没有参数则为默认构造方法 Constructor<?> con2=p1.getConstructor(String.class,int.class); System.out.println("con2:"+con2); System.out.println("是否含有可变参数"+con2.isVarArgs()); System.out.println("包含的参数:"+con2.getParameterTypes()); System.out.println("该构造方法会抛出的异常:"+con2.getExceptionTypes()); System.out.println("创建一个对象:"); Person pTest=null; try { pTest=(Person) con2.newInstance("sxb",20); System.out.println("对象创建成功"); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } String pTestName=pTest.getName(); System.out.println(pTestName);
//获取参数为可变类型的构造方法 Constructor<?> con3=p1.getConstructor(String[].class); System.out.println("con3:"+con3);
//获取所有的构造方法,不仅限于public Constructor[] con4=p1.getDeclaredConstructors(); //遍历输出con4中的方法 for(int a=0;a<con4.length;a++){ Constructor<?> conn=con4[a]; System.out.println(conn); } System.out.println("///////////创建对象/////////////");
try { Person pp=(Person) p1.newInstance(); pp.setName("nametest"); System.out.println(pp.getName()); } catch (InstantiationException | IllegalAccessException e) { // TODO Auto-generated catch block System.out.println("创建对象出错"); e.printStackTrace(); } int mod=con2.getModifiers(); System.out.println(Modifier.isPublic(mod)); }
}
|
- 成员变量(Field)
通过以下方法返回Field类型的对象或数组,每个对象代表了一个成员变量
getFields() |
数组形式返回权限为public的所有成员变量 |
getFields(String name) |
获取权限为public指定名称的成员变量,返回一个Field对象 |
getDeclaredFields() |
数组形式返回所有成员变量 |
getDeclaredFields() |
获取指定名称的成员变量,返回一个Field对象 |
Field类提供了以下方法,用来对成员变量进行访问。
getName |
获得该成员变量的名称 |
getType |
获得表示该成员变量的Class类型的对象 |
get(Object obj) |
获得指定对象中成员变量的值,返回值为Object类型 |
set(Object obj,Object value) |
将指定obj对象中的成员变量的值设置为value |
getInt(Object obj) |
获得指定对象中int类型的成员变量的值 |
setInt(Object obj,Object value) |
将指定对象中int类型的成员变量设置为value |
getFloat(Object obj) |
|
setFloat(Object obj,Object va) |
|
getBoolean(Object obj) |
|
setBoolean(Object obj,Boolean value) |
|
setAccessible(boolean glag) |
忽略private权限直接访问私有成员变量 |
getModifiers() |
获得一个代表修饰符的整数 |
代码示例:
package field;
public class Person { private String name; private int age; public int grade; public String home; protected boolean sex; public void setGrade(int grade){ this.grade=grade; } }
package field;
import java.lang.reflect.Field;
public class PersonTest { public static void main(String[] args){ test1(); } public static void test1(){ //操作成员变量的四个方法 /*1、getField() * */ Class<?> p1=Person.class; Person p2=new Person();
try { //获取权限为public的指定名称的成员变量,返回一个Field对象 Field f1=p1.getField("grade"); System.out.println("输出f1"+f1); //获得f1的名字 String name1=f1.getName(); System.out.println("f1对象所表示的成员变量的名称"+name1); //获得表示该成员变量的Class对象 Class<?> type=f1.getType(); System.out.println("f1所表示成员变量的类型"+type);
try { f1.getInt(p2); f1.setInt(p2, 88); System.out.println("p2中类型为int的成员变量"+f1.getInt(p2)); } catch (IllegalArgumentException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IllegalAccessException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }
//获得该成员变量的值 try {
f1.get(p1);//获得指定成员变量中的值,并返回 System.out.println("p1对象中f1所表示成员变量的值"+f1.get(p1)); } catch (IllegalArgumentException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { f1.set(p2, 6);//将指定对象中f1所代表的成员变量赋值 f1.get(p2);//获得指定成员变量中的值,并返回 System.out.println("p2对象中f1所表示成员变量的值:"+f1.get(p2)); } catch (IllegalArgumentException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); }
} catch (NoSuchFieldException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }
Field[] array1=p1.getFields(); //获取所有权限为public的成员变量,返回一个Field类型数组 for(int a=0;a<array1.length;a++){ System.out.println(array1[a]); } System.out.println("权限为public的成员变量数量是"+array1.length);
try { p1.getDeclaredField("name"); System.out.println(p1.getDeclaredField("name")); //获取指定成员变量 } catch (NoSuchFieldException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }
p1.getDeclaredFields(); //返回一个包含所有成员变量的Field数组
} }
|
3访问方法
package methods;
public class Person {
private String name;
private void Method1(){
System.out.println("我是方法1");
}
protected void Method2(String...strings){
System.out.println("我是方法2");
for(int a=0;a<strings.length;a++){
System.out.println(strings[a]);
}
}
public void Method3()throws NullPointerException{
System.out.println("我是方法3");
}
public void Method4(String name,int age)throws NullPointerException{
System.out.println("姓名:"+name+"年龄"+age);
}
}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
package methods;
import java.lang.reflect.Method;
/*获取Method对象的四种方法
* 1、getMethod("MethodName",参数类型...) //获得指定的权限为public的方法,返回一个Method对象
* 2、getMethods()获取权限为public的所有方法,返回一个Method数组
* 3、getDeclaredMethod("MethodName",参数类型...) //获得指定的的方法,返回一个Method对象
* 4、getDeclaredMethods()获取所有方法,返回一个Method数组
* */
public class PersonTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Class<?> p1=Person.class;
try {
Method m1=p1.getMethod("Method4",String.class,int.class);
m1.getName();
int mm=m1.getModifiers();
Object[] array=m1.getParameterTypes();
for(int b=0;b<array.length;b++){
System.out.println("方法参数类型"+array[b]);
}
System.out.println(m1.getName());
//获得返回类型
Class<?> type=m1.getReturnType();
System.out.println(type);
//获得抛出的异常
Class[] array2=m1.getExceptionTypes();
for(int b1=0;b1<array2.length;b1++){
System.out.println("抛出的异常为:"+array2[b1]);
}
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- 注解(Annotation)
注解,就是给程序看的解释性的语言,其作用就相当于配置文件的存在。其存在的意义在于以下几点:
优点:
方便的使程序员看到相关项的关联位置及关联方式等信息。
缺点:
由于注解是存在于程序之上的,所以每次对注解进行修改后就必须要对源代码进行重新编译才会生效。
首先定义一个Annotation类型
@Target(ElementType.CONSTRUCTOR) //用于构造方法
@Retention(RetentionPolicy.RUNTIME) //运行时加载到jvm中
public @interface FirstAnnotation { //定义一个用来注释构造方法的annotation类型
//String value(); 四种成员类型:String 、Class、primitive、enumerated
//如果只包含一个成员标量,则默认为value
String value() default "<默认值>"; //为成员变量设置默认值
//String value(); //为成员变量设置默认值
//用@Target设置Annotation类型的程序元素种类,如果没有设置,则表示适用于所有的程序元素
/*枚举类ElementType中的枚举常量,用来设置@Target
* 枚举常量、、、、、说明
* ANNOTATION_TYPE 表示适用于Annotation类型
* TYPE 表示适用于类、接口、枚举,以及Annonation类型
* CONSTRUCTOR 表示用于构造方法
* FIELD 表示用于成员变量
* METHOD 表示用于成员方法
* PARAMETER 表示用于参数
* LOCAL_VARIABLE 表示用于局部变量
* PACKAGE 表示用于包
* */
/*通过@Retention可以设置Annotation的有效范围
* RetentionPolicy中的枚举常量用来设置@Retention,如果没有设置,则表示枚举常量CLASS表示的范围
* 枚举常量、、、、、说明
* SOURCE 表示不编译ANNOTATION到类文件中,有效范围最小
* CLASS 表示编译到类文件中,但是运行时不加载Annotation到jvm中
* RUNTIME 表示运行时加载到jvm中,有效范围最大
*
* */
}
再定义一个用来注释成员变量、方法、参数的Annotation类型
//用于成员变量、方法和参数
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Field_Method_Parameter_Annotation {
String describe();
Class type() default void.class;
}
定义一个普通类,并对其元素进行注释
package annotation;
import java.beans.ConstructorProperties;
public class Record {
@Field_Method_Parameter_Annotation(describe="编号",type = int.class)
//注释字段
int id;
@Field_Method_Parameter_Annotation(describe="姓名",type=String.class)
String name;
@FirstAnnotation()
//采用默认值注释构造方法
public Record(){}
@FirstAnnotation("立即初始化构造方法")
public Record( //注释构造方法
@Field_Method_Parameter_Annotation(describe="编号",type=int.class)int id,
@Field_Method_Parameter_Annotation(describe="姓名",type=String.class)String name){
this.name=name;
this.id=id;
}
@Field_Method_Parameter_Annotation(describe="获得编号",type=int.class)
public int getId(){
return id;
}
@Field_Method_Parameter_Annotation(describe="设置编号")
public void setId( //注释方法的参数
@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)
Constructor、Field、Method都继承了AccessibleObject,AccessibleObject中定义了三个方法:
isAnnotationPresent(Class<? extends Annotation> annotationclass); :判断元素是否添加了指定的annotation返回boolean
getAnnotation(Class<T> annotationclass)获得指定类型的annotation,如果存在,则返回相应的对象,否则返回null;
getAnnotations()用来获得所有的annotation,该方法将返回一个annotation数组
此外:Constructor、Method中还定义了方法getParameterAnnotation(),用来获得为所有参数添加的annotation,将以annotation类型的二维数组返回。
如果没有参数则返回一个长度为0的数组,如果存在没有添加annotation的参数,则用一个长度为0的嵌套数组占位。
package annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
public class RecordTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Class<?> o=Record.class;
Method1(o);
}
//构造方法访问Annotation
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void Method1(Class<?> o){
Constructor[] cons=o.getDeclaredConstructors();
for(int i=0;i<cons.length;i++){
System.out.println("当前i为: "+i);
Constructor con=cons[i];
//查看是否具有指定类型的注释
if(con.isAnnotationPresent(FirstAnnotation.class)){
//获得指定类型的注释
FirstAnnotation ca=(FirstAnnotation)con.getAnnotation(FirstAnnotation.class);
System.out.println(ca.value());
}
Annotation[][] pa=con.getParameterAnnotations(); //获得参数的注释
System.out.println("test");
System.out.println(pa.length);
for(int j=0;j<pa.length;j++){
System.out.println("test1");
//获得指定参数注释的长度
int len=pa[j].length;
System.out.println("len"+len);
if(len==0)
System.out.println("存在没有添加Annotation的参数");
else
for(int k=0;k<len;k++){
//获得参数的著述
Field_Method_Parameter_Annotation paa=(Field_Method_Parameter_Annotation)pa[j][k];
System.out.println("describe: "+paa.describe()); //获得参数藐视
System.out.println("type: "+paa.type());
}
System.out.println(" ");
}
}
}
public void Method2(Class<?> o){
}
public void Method3(Class<?> o){
}
}