Java核心技术之反射
一、class类与java反射
class textfieldc=tetxfield.getclass(); //tetxfield为jtextfield类对象
反射可访问的主要描述
1、访问构造方法
每个constructor对象代表一个构造方法,利用constructor对象可以操纵相应的构造方法。
-
getconstructors()
//获取公有 -
getconstructor(class<?>... parametertypes)
//获取指定公有 -
getdeclaredconstructors()
//获取所有 -
getdeclaredconstructor(class<?>... parametertypes)
//获取指定方法
创建demo1类,声明string类型成员变量和3个int类型成员变量,并提供3个构造方法。
package bao; public class demo1{ string s; int i,i2,i3; private demo1() { } protected demo1(string s,int i) { this.s=s; this.i=i; } public demo1(string... strings)throws numberformatexception{ if(0<strings.length) { i=integer.valueof(strings[0]); } if(1<strings.length) { i2=integer.valueof(strings[0]); } if(2<strings.length) { i3=integer.valueof(strings[0]); } } public void print() { system.out.println("s="+s); system.out.println("i="+i); system.out.println("i2="+i2); system.out.println("i3="+i3); } }
编写main类,在该类对demo1进行反射访问的所有构造方法,并将该构造方法是否允许带有可变数量的参数、入口参数和可能抛出的异常类型信息输出。
package bao; import java.lang.reflect.constructor; public class main { public static void main(string[] args) { demo1 demo=new demo1("10","20","30"); class<? extends demo1>democ=demo.getclass(); //获得所有构造方法 constructor[] declaredconstryctors=democ.getdeclaredconstructors(); for(int i=0;i<declaredconstryctors.length;i++) { constructor<?> constructor=declaredconstryctors[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 example2=null; while(example2==null) { try { if(i==2) { example2=(demo1)constructor.newinstance(); }else if(i==1) { example2=(demo1)constructor.newinstance("7",5); }else { object[] parameters=new object[] {new string[] {"100","200","300"}}; example2=(demo1)constructor.newinstance(parameters); } }catch(exception e){ system.out.println("在创建对象时抛出异常,下面执行setaccessible()方法"); constructor.setaccessible(true); //设置允许访问 } } if(example2!=null) { example2.print(); system.out.println(); } } } } /*输出结果: 查看是否允许带有可变数量的参数:true 该构造方法的入口参数类型依次为: class [ljava.lang.string; 该构造方法的入口可能抛出异常类型为: class java.lang.numberformatexception s=null i=100 i2=100 i3=100 查看是否允许带有可变数量的参数:false 该构造方法的入口参数类型依次为: class java.lang.string int 该构造方法的入口可能抛出异常类型为: s=7 i=5 i2=0 i3=0 查看是否允许带有可变数量的参数:false 该构造方法的入口参数类型依次为: 该构造方法的入口可能抛出异常类型为: 在创建对象时抛出异常,下面执行setaccessible()方法 s=null i=0 i2=0 i3=0 */
2、访问成员变量
每个field对象代表一个成员变量,利用field对象可以操纵相应的成员变量。
- getfields()
- getfield(string name)
- getdeclaredfields()
- getdeclaredfield(string name)
创建demo1类依次声明int、fioat、boolean和string类型的成员变量,并设置不同的访问权。
package bao; public class demo1{ int i; public float f; protected boolean b; private string s; }
通过反射访问demo1类中的所有成员变量,将成成员变量的名称和类型信息输出。
package bao; import java.lang.reflect.field; public class main { public static void main(string[] args) { demo1 demo=new demo1(); class democ=demo.getclass(); //获得所有成员变量 field[] declaredfield=democ.getdeclaredfields(); for(int i=0;i<declaredfield.length;i++) { field field=declaredfield[i]; system.out.println("名称为:"+field.getname()); //获取成员变量名称 class fieldtype=field.gettype(); ///获取成员变量类型 system.out.println("类型为:"+fieldtype); boolean isturn=true; while(isturn) { try { isturn=false; system.out.println("修改前的值为:"+field.get(demo)); if(fieldtype.equals(int.class)) { //判断成员变量的类型是否为int类型 system.out.println("利用方法setint()修改成员变量的值"); field.setint(demo, 168); //为int类型成员变量赋值 }else if(fieldtype.equals(float.class)){ //判断成员变量的类型是否为float类型 system.out.println("利用方法 setfloat()修改成员变量的值"); field.setfloat(demo, 99.9f); //为float类型成员变量赋值 }else if(fieldtype.equals(boolean.class)){ //判断成员变量的类型是否为boolean类型 system.out.println("利用方法 setboolean()修改成员变量的值"); field.setboolean(demo, true); //为boolean类型成员变量赋值 }else { system.out.println("利用方法 set()修改成员变量的值"); field.set(demo, "mwq"); //可以为各种类型的成员变量赋值 } //获得成员变量值 system.out.println("修改后的值为:"+field.get(demo)); }catch(exception e) { system.out.println("在设置成员变量值时抛出异常,"+"下面执行setaccesssible()方法!"); field.setaccessible(true); //设置为允许访问 isturn=true; } } system.out.println(); } } }
/*输出结果:
名称为:i
类型为:int
修改前的值为:0
利用方法setint()修改成员变量的值
修改后的值为:168
名称为:f
类型为:float
修改前的值为:0.0
利用方法 setfloat()修改成员变量的值
修改后的值为:99.9
名称为:b
类型为:boolean
修改前的值为:false
利用方法 setboolean()修改成员变量的值
修改后的值为:true
名称为:s
类型为:class java.lang.string
在设置成员变量值时抛出异常,下面执行setaccesssible()方法!
修改前的值为:null
利用方法 set()修改成员变量的值
修改后的值为:mwq
*/
3、访问方法
每个method对象代表一个方法,利用method对象可以操纵相应的方法。
- getmethods()
- getmethod(string name, class<?>... parametertypes)
- getdeclaredmethods()
- getdeclaredmethod(string name, class<?>... parametertypes)
创建demo1类,编写4个典型方法。
package bao; public class demo1{ static void staitcmethod() { system.out.println("执行staitcmethod()方法"); } public int publicmethod(int i) { system.out.println("执行publicmethod()方法"); return i*100; } protected int protectedmethod(string s,int i)throws numberformatexception { system.out.println("执行protectedmethod()方法"); return integer.valueof(s)+i; } private string privatemethod(string...strings) { system.out.println("执行privatemethod()方法"); stringbuffer stringbuffer=new stringbuffer(); for(int i=0;i<stringbuffer.length();i++) { stringbuffer.append(strings[i]); } return stringbuffer.tostring(); } }
反射访问demm1类中的所有方法,将方法的名称、入口参数类型、返回值类型等信息输出
package bao; import java.lang.reflect.field; import java.lang.reflect.method; public class main { public static void main(string[] args) { demo1 demo = new demo1(); class democ = demo.getclass(); // 获得所有方法 method[] declaredmethods = democ.getdeclaredmethods(); for (int i = 0; i < declaredmethods.length; i++) { method method = declaredmethods[i]; // 遍历方法 system.out.println("名称为:" + method.getname()); // 获得方法名称 system.out.println("是否允许带有可变数量的参数:" + method.isvarargs()); system.out.println("入口参数类型依次为:"); // 获得所有参数类型 class[] parametertypes = method.getparametertypes(); for (int j = 0; j < parametertypes.length; j++) { system.out.println(" " + parametertypes[j]); } // 获得方法返回值类型 system.out.println("返回值类型为:" + method.getreturntype()); system.out.println("可能抛出的异常类型有:"); // 获得方法可能抛出的所有异常类型 class[] exceptiontypes = method.getexceptiontypes(); for (int j = 0; j < exceptiontypes.length; j++) { system.out.println(" " + exceptiontypes[j]); } boolean isturn = true; while (isturn) { try { isturn = false; if("staitcmethod".equals(method.getname())) { method.invoke(demo); // 执行没有入口参数的方法 }else if("publicmethod".equals(method.getname())) { system.out.println("返回值为:"+ method.invoke(demo, 168)); // 执行方法 }else if("protectedmethod".equals(method.getname())) { system.out.println("返回值为:"+ method.invoke(demo, "7", 5)); // 执行方法 }else { object[] parameters = new object[] { new string[] {"m", "w", "q" } }; // 定义二维数组 system.out.println("返回值为:"+ method.invoke(demo, parameters)); } }catch(exception e) { system.out.println("在执行方法时抛出异常," + "下面执行setaccessible()方法!"); method.setaccessible(true); // 设置为允许访问 isturn = true; } } system.out.println(); } } }
/*输出结果:
名称为:publicmethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
int
返回值类型为:int
可能抛出的异常类型有:
执行publicmethod()方法
返回值为:16800
名称为:staitcmethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
返回值类型为:void
可能抛出的异常类型有:
执行staitcmethod()方法
名称为:protectedmethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
class java.lang.string
int
返回值类型为:int
可能抛出的异常类型有:
class java.lang.numberformatexception
执行protectedmethod()方法
返回值为:12
名称为:privatemethod
是否允许带有可变数量的参数:true
入口参数类型依次为:
class [ljava.lang.string;
返回值类型为:class java.lang.string
可能抛出的异常类型有:
在执行方法时抛出异常,下面执行setaccessible()方法!
执行privatemethod()方法
返回值为:
*/
二、使用annotation功能
1、定义annotation类型
在定义annotation类型时,也需要用到用来定义接口的interface关键字,不过需要在interface关键字前加一个“@”符号,即定义annotation类型的关键字为@interface,这个关键字的隐含意思是继承了java.lang.annotation.annotation接口。
public @interface nomemberannotation{
string value();
}
@interface
:声明关键字。
nomemberannotation
:注解名称。
string
:成员类型。
value
:成员名称。
定义并使用annotation类型
①定义annotation类型@constructor_annotation的有效范围为运行时加载annotation到jvm中。
package annotationbao; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; @target(elementtype.constructor) // 用于构造方法 @retention(retentionpolicy.runtime) // 在运行时加载annotation到jvm中 public @interface constructor_annotation{ string value() default "默认构造方法"; // 定义一个具有默认值的string型成员 }
②定义一个来注释字段、方法和参数的annotation类型@field_method_parameter_annotation的有效范围为运行时加载annotation到jvm中
package annotationbao; 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 descrblic(); // 定义一个没有默认值的string型成员 class type() default void.class; // 定义一个具有默认值的class型成员 }
③编写一个record类,在该类中运用前面定义annotation类型的@constructor_annotation和@field_method_parameter_annotation对构造方法、字段、方法和参数进行注释。
package annotationbao; public class record { @field_method_parameter_annotation(describe = "编号", type = int.class) int id; @field_method_parameter_annotation(describe = "姓名", type = string.class) string name; @constructor_annotation() public record() { } @constructor_annotation("立即初始化构造方法") 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 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; } }
2、访问annotation信息
如果在定义annotation类型时将@retention设置为retentionpolicy.runtime,那么在运行程序时通过反射就可以获取到相关的annotation信息,如获取构造方法、字段和方法的annotation信息。
联合以上的定义并使用annotation类型,通过反射访问record类中的annotation信息。
package annotationbao; import java.lang.annotation.*; import java.lang.reflect.*; public class main_05 { public static void main(string[] args) { class recordc = null; try { recordc = class.forname("record"); } catch (classnotfoundexception e) { e.printstacktrace(); } system.out.println("------ 构造方法的描述如下 ------"); constructor[] declaredconstructors = recordc .getdeclaredconstructors(); // 获得所有构造方法 for (int i = 0; i < declaredconstructors.length; i++) { constructor constructor = declaredconstructors[i]; // 遍历构造方法 // 查看是否具有指定类型的注释 if (constructor .isannotationpresent(constructor_annotation.class)) { // 获得指定类型的注释 constructor_annotation ca = (constructor_annotation) constructor .getannotation(constructor_annotation.class); system.out.println(ca.value()); // 获得注释信息 } annotation[][] parameterannotations = constructor .getparameterannotations(); // 获得参数的注释 for (int j = 0; j < parameterannotations.length; j++) { // 获得指定参数注释的长度 int length = parameterannotations[j].length; if (length == 0) // 如果长度为0则表示没有为该参数添加注释 system.out.println(" 未添加annotation的参数"); else for (int k = 0; k < length; k++) { // 获得参数的注释 field_method_parameter_annotation pa = (field_method_parameter_annotation) parameterannotations[j][k]; system.out.print(" " + pa.describe()); // 获得参数描述 system.out.println(" " + pa.type()); // 获得参数类型 } } system.out.println(); } system.out.println(); system.out.println("-------- 字段的描述如下 --------"); field[] declaredfields = recordc.getdeclaredfields(); // 获得所有字段 for (int i = 0; i < declaredfields.length; i++) { field field = declaredfields[i]; // 遍历字段 // 查看是否具有指定类型的注释 if (field .isannotationpresent(field_method_parameter_annotation.class)) { // 获得指定类型的注释 field_method_parameter_annotation fa = field .getannotation(field_method_parameter_annotation.class); system.out.print(" " + fa.describe()); // 获得字段的描述 system.out.println(" " + fa.type()); // 获得字段的类型 } } system.out.println(); system.out.println("-------- 方法的描述如下 --------"); method[] methods = recordc.getdeclaredmethods(); // 获得所有方法 for (int i = 0; i < methods.length; i++) { method method = methods[i]; // 遍历方法 // 查看是否具有指定类型的注释 if (method .isannotationpresent(field_method_parameter_annotation.class)) { // 获得指定类型的注释 field_method_parameter_annotation ma = method .getannotation(field_method_parameter_annotation.class); system.out.println(ma.describe()); // 获得方法的描述 system.out.println(ma.type()); // 获得方法的返回值类型 } annotation[][] parameterannotations = method .getparameterannotations(); // 获得参数的注释 for (int j = 0; j < parameterannotations.length; j++) { int length = parameterannotations[j].length; // 获得指定参数注释的长度 if (length == 0) // 如果长度为0表示没有为该参数添加注释 system.out.println(" 未添加annotation的参数"); else for (int k = 0; k < length; k++) { // 获得指定类型的注释 field_method_parameter_annotation pa = (field_method_parameter_annotation) parameterannotations[j][k]; system.out.print(" " + pa.describe()); // 获得参数的描述 system.out.println(" " + pa.type()); // 获得参数的类型 } } system.out.println(); } } }
/*输出结果:
------ 构造方法的描述如下 ------
默认构造方法
立即初始化构造方法
编号 int
姓名 class java.lang.string
-------- 字段的描述如下 --------
编号 int
姓名 class java.lang.string
-------- 方法的描述如下 --------
获得姓名
class java.lang.string
设置姓名
void
姓名 class java.lang.string
获得编号
int
设置编号
void
编号 int
*/
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!