重识java反射

说到java反射,不得不说说它的功能

通过java反射机制,可以在程序中访问已经装载到JVM中的java对象的描述,实现访问、检测和修改描述java对象本身的信息的功能。java反射机制的功能十分强大,在java.lang.reflect对该功能的支持。

注意:在Object类中定义了一个getClass()方法,该方法会返回了一个类型为Class的对象。

例如: Class  NameA  =  a.getClass();     // a为A类的一个对象  

以下表格描述的是通过反射可以访问的主要描述信息:

通过反射能够访问以下类的信息:

 1.访问构造方法:

Constructor类的常用方法:

 实例1:首先创建一个Demo1类,在该类中声明一个String类型的成员变量和3个int型的成员变量,并提供一个构造方法。代码如下:

package com.study.reflect;

public class Demo1 {
String s;
int i,i1,i2;
private Demo1() {
	
}
protected Demo1(String s,int i) {
	this.s=s;
	this.i=i;
}
public Demo1(String...strings) throws NumberFormatException{
	if(strings.length>0) {
		i=Integer.valueOf(strings[0]);
	}
	if(strings.length>1) {
		i1=Integer.valueOf(strings[1]);
	}
	if(strings.length>2) {
		i2=Integer.valueOf(strings[2]);
	}
}
public void print() {
	System.out.println("s="+s);
	System.out.println("i="+i);
	System.out.println("i1="+i1);
	System.out.println("i2="+i2);
}

}

下面再编写测试类Main1,在类中通过反射访Demo1类中的所有构造方法,并将该构造方法是否允许带有可变数量的参数、入口参数类型和可能抛出的异常类型输出到控制台。代码如下:

package com.study.reflect;

import java.lang.reflect.Constructor;

public class Main1 {
public static void main(String []args) {
	//创建一个Demo1类的对象
	Demo1 demo1 = new Demo1("11","22","33");
	//获取demo1对象的Class类的对象
	Class<? extends Demo1> demoA = demo1.getClass();
	//获取所有的构造方法即构造方法的数组,一个Constructor代表一个构造方法
	Constructor<?>[] declaredConstructors = demoA.getDeclaredConstructors();
	//遍历构造方法
	for(int i=0;i<declaredConstructors.length;i++) {
		//获取当前构造方法
		Constructor<?> constructor = declaredConstructors[i];
		System.out.println("查看是否允许带有可以变数量的参数:"+constructor.isVarArgs());
		System.out.println("该构造方法的入口参数类型依次为:");
		//以Class数组的形式获得该构造方法的各个参数的类型
		Class<?>[] parameterTypes = constructor.getParameterTypes();
		for(int j=0;j<parameterTypes.length;j++) {
			//以字符串的形式输出参数的class类型
			System.out.println(" "+parameterTypes[j]);
		}
		System.out.println("该构造方法可能抛出的异常为:");
		//以Class数组的形式获得该构造方法可能抛出的异常类型
		Class<?>[] exceptionTypes = constructor.getExceptionTypes();
		for (int j = 0; j < exceptionTypes.length; j++) {
			//以字符串的形式输出可能抛出异常的class类型
			System.out.println(" "+exceptionTypes[j]);
		}
		Demo1 demo2 = null;
		while(demo2==null) {
			try {//如果该成员变量的访问权限为private,则抛出异常,即不允许访问
				if(i==2) {//通过执行默认没有参数的创建对象
					demo2 = (Demo1) constructor.newInstance();
				}
				else if(i==1) {
					//通过执行两个参数的构造方法创建对象
					demo2 = (Demo1) constructor.newInstance("7",5);
				}else {
					//通过执行具有可变数量参数的构造方法创建对象
					Object [] parameters = new Object [] {new String [] {"100","200","300"}};
					//Object [] strings = new String[] {"100","200","300"};
					demo2 = (Demo1) constructor.newInstance(parameters);
				}
			} catch (Exception e) {
				// TODO: handle exception
				System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
				/**
				 * 如果当前构造方法的权限为private,默认不允许创建通过反射利用newInstance(Object... initargs)方法创建对象。
				 * 如果先执行该方法,并将入口参数设为true,则允许创建
				 */
				constructor.setAccessible(true);//设置为允许访问
			}
			if(demo2!=null) {
				demo2.print();
				System.out.println();
			}
		}
	}
}
}

运行这个实例,当通过反射Demo1()构造方法时,输出结果如下:

 当通过反射Demo1(String s,int i)构造方法时,输出结果如下:

当通过反射构造方法Demo1(String...strings) 时,输出结果如下:

2.访问成员变量 :

Field类的常用方法:

实例2:创建一个Demo2类,在该类中一次声明一个int、float、boolean、String型的成员变量,并将他们设置为不同的权限。代码如下:

package com.study.reflect;

public class Demo2 {
int i;
public float fl;
protected boolean bl;
private String s;
}

通过反射Demo2类中的所有成员变量,将成员变量的名称和类型信息输出到控制台,并分别设置为不同的访问权限;代码如下:

package com.study.reflect;

import java.lang.reflect.Field;

public class Main2 {
public static void main(String []args) {
	Demo2 demo = new Demo2();
	Class<? extends Demo2> demo2 = demo.getClass();
	//获取所有成员变量
	Field[] declaredFields = demo2.getDeclaredFields();
	for(int i=0;i<declaredFields.length;i++) {//遍历成员变量
		Field f = declaredFields[i];
		//获取成员变量的名称
		System.out.println("名称为"+f.getName());
		//获取成员变量类型
		Class<?>  fieldType = f.getType();
		System.out.println("类型为"+fieldType);
		boolean start = true;
		while(start) {
			//如果该成员变量的访问权限为private,则抛出异常,即不允许访问
			try {
				start=false;
				//获取成员变量的值
				System.out.println("修改前的值为"+f.get(demo));
				//判断成员变量的类型是否为int型
				System.out.println("ni"+fieldType);
				if(fieldType.equals(int.class)) {
					System.out.println("利用方法setInt()方法修改成员变量的值");
					f.setInt(demo, 123);
					System.out.println("------");
				}else if(fieldType.equals(float.class)) {//判断成员变量的类型是否为float型
					System.out.println("利用方法setFloat()方法修改成员变量的值");
					System.out.println("wwwwwww");
					f.setFloat(demo, 111.1f);
				}else if(fieldType.equals(boolean.class)) {//判断成员变量的类型是否为boolean型
					System.out.println("利用方法setBoolean()方法修改成员变量的值");
					f.setBoolean(demo, true);
				}else {
					System.out.println("利用方法set()修改车成员变量的值");
					//可以为各种类型的成员变量赋值
					f.set(demo, "Success");
				}
				//获取成员变量值
				System.out.println("修改后的值为"+f.get(demo));
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
				System.out.println("在设置成员变量值时抛出异常,"+"下面执行setAccessible()方法");
				f.setAccessible(true);//设置为允许访问
				start= true;
			}
		}
	}
	
}
}

运行实例2,输出结果如下所示:

 3.访问方法:

Method类的常用方法:

 实例3:创建一个Demo3类,并编写4个典型的方法。具体代码如下:

package com.study.reflect;

public class Demo3 {
static void staticMethod() {
	System.out.println("执行staticMethod()方法");
}
public int publicMethod(int i) {
	System.out.println("执行publicMethod()方法");
	return i*10;
}
protected int protectedMethod(String s,int i) throws NumberFormatException{
	System.out.println("执行protectedMethod()方法");
	return Integer.valueOf(s)+i;
}
private String privateMethod(String...strings) {//里面参数是一个可变长度的数组,名为strings
	System.out.println("执行privateMethod()方法");
	StringBuffer stringBuffer = new StringBuffer();
	for(int i=0;i<strings.length;i++) {
		stringBuffer.append(strings[i]);
	}
	return stringBuffer.toString();
}
}

通过反射访问Demo3类中的所有方法,将各个方法的名称、入口参数类型、返回值类型等信息输出到控制台,并执行方法。代码如下:

package com.study.reflect;

import java.lang.reflect.Method;

public class Main3 {
public static void main(String []args) {
	Demo3 demo = new Demo3();
	Class<? extends Demo3> demo3 = demo.getClass();
	//获取所有方法
	Method[] declaredMethods = demo3.getDeclaredMethods();
	for(int i=0;i<declaredMethods.length;i++) {//遍历方法
		Method method = declaredMethods[i];
		//获取方法名称
		String name = method.getName();
		System.out.println("名称为:"+name);
		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 start = true;
		while(start) {
			//如果该方法的权限为private则不允许访问
			try {
				start = false;
				if("staticMethod".equals(method.getName())) {//执行没有入口参数的方法
					method.invoke(demo);
				}
				else if("publicMethod".equals(method.getName())) {
					method.invoke(demo, 12);	//执行方法
				}
				else if("protectedMethod".equals(method.getName())) {
					method.invoke(demo, "34",6); 	//执行方法
				}
				else if("privateMethod".equals(method.getName())) {
					Object [] parameters = new Object[] {new String[] {"HELLO","WORLD!"}};	//定义二维数组
					System.out.println("返回值为:"+method.invoke(demo,parameters ));
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
				System.out.println("在执行方法时抛出异常"+"下面执行setAccessible()方法:");
				method.setAccessible(true);	//设置为允许
				start=true;
			}
			
		}
        System.out.println();
	}
}
}

运行实例,输出结果:

 4.得到Class对象的3种方式

首先编写一个普通类Test类,代码如下:

package com.study.reflect;
/**
 *一个普通类
 * @author 哎呦不错呦
 *
 */
public class Test {
public Test() {
	//构造方法
}
void work() {
	System.out.println("调用了work()方法");
}
void like() {
	System.out.println("调用了like()方法");
}
}

然后在编写一个测试类ReflectTest,代码如下:

package com.study.reflect;
/**
 * 测试类,得到Class对象的3种方式
 * @author 哎呦不错呦
 *
 */
public class ReflectTest {
public static void main(String []args) throws ClassNotFoundException {
	//1.通过对象调用getClass()方法获取Class对象
	Test test  =  new Test();
	Class<? extends Test> A = test.getClass();
	
	//2.通过直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
	//  因为任何一个类都有一个隐含的静态成员变量 class
	Class B = Test.class;
	
	//3.通过 Class 对象的 forName() 静态方法来获取,用的最多,
	//  但可能抛出 ClassNotFoundException 异常
	Class C = Class.forName("com.study.reflect");
}
}

参考:java从入门到精通(第4版) 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值