欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java核心技术之反射

程序员文章站 2022-07-03 22:42:38
目录一、class类与java反射1、访问构造方法2、访问成员变量3、访问方法二、使用annotation功能1、定义annotation类型2、访问annotation信息总结一、class类与ja...

一、class类与java反射

class textfieldc=tetxfield.getclass(); //tetxfield为jtextfield类对象

反射可访问的主要描述

Java核心技术之反射

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:成员名称。

Java核心技术之反射

定义并使用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

*/

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!