Java反射机制(reflect)

一、简介

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。

反射机制主要提供一下功能:

在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;

简单示例:

package com.wbf.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person {
	public static final String FIELD = "field";
	private int age;
	private String name;
	
	public Person(){}
	public Person(int age, String name){
		this.age = age;
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

public class ReflectDemo {
	public static void main(String[] args) {
		Person per = new Person(20, "shangsan");
		//返回对象per的运行时类,即:com.wbf.reflect.Person
		//public final Class<?> getClass()
		//per.getClass()得到的是com.wbf.reflect.person类,用Class类声明的对象类接收
		//等价于:Person extends Class
		//那么,Person类的实例对象per也可认为是Class类的实例对象
		//以此类推,所有类的对象实际上都是Class类的实例
		Class pc = per.getClass();
		System.out.println(pc.getName());
		System.out.println(pc.getSimpleName());
		System.out.println(pc.getPackage());
		
		Constructor[] cons = pc.getDeclaredConstructors();//pc.getConstructors()
		//返回一个包含某些 Field对象的数组,这些对象反映此 Class对象所表示的类或接口的所有可访问公共字段
		Field[] fields = pc.getDeclaredFields();//pc.getFields()
		Method[] methods = pc.getDeclaredMethods();//pc.getMethods()
		
		for (int i = 0; i < cons.length; i++)
		{
			Constructor con = cons[i];
			System.out.print(con.getName() + "、");//输出构造方法名称
		}
		System.out.println();
		for (int j = 0; j < fields.length; j++)
		{
			Field field = fields[j];
			System.out.print(field.getName() + "、");//输出字段名称
		}
		System.out.println();
		for (int k = 0; k < methods.length; k++)
		{
			Method m = methods[k];
			System.out.print(m.getName() + "、");//输出方法名称
		}
	}
}

二、Class类的使用

Class类在开发中最常见的用法就是实例化对象的操作,即可以通过一个给定的字符串(此字符串包含了完整的“包.类”的路径)来实例化一个类的对象。

1)通过无参构造实例化对象:如果想要通过Class类本身实例化其他类的对象,则可以使用newInstance()方法,但是必须保证被实例化的类中存在一个无参构造方法。

package com.wbf.reflect;

class Student {
	private int age;
	private String name;
	
	public Student(){}
	public Student(int age, String name){
		this.setAge(age);
		this.setName(name);
	}

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "姓名:" + this.getName() + ", 年龄: " + this.getAge();
	}
}

public class ClassDemo02 {
	public static void main(String args[]) throws Exception {
		//获取Student类对应的Class类的实例
		Class<?> c = Class.forName("com.wbf.reflect.Student");
		//实例化Student类,调用无参构造方法
		Student s = (Student)c.newInstance();
		s.setAge(20);
		s.setName("wbf");
		//调用toString()方法
		System.out.println(s);
	}
}
2)通过有参构造实例化对象:a. 通过Class类中的getConstructors()取得本类中的全部构造方法; b. 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数; c. 之后通过Constructor实例化对象
public class ClassDemo02 {
	public static void main(String args[]) throws Exception {
		//获取Student类对应的Class类的实例
		Class<?> c = Class.forName("com.wbf.reflect.Student");
		Constructor[] cons = c.getConstructors();
		//通过有参构造方法实例化对象
		Student s = (Student)cons[1].newInstance(20, "wbf");
		System.out.println(s);
	}
}

三、反射的基本应用

package com.wbf.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

interface China {
	public static final String NATIONAL = "China";
	public static final String AUTHOR = "wbf";
	public void sayChina();
	public String sayHello(String name, int age);
}

class Person implements China {
	
	private String name;
	private int age;
	
	public Person(){}
	public Person(String name){
		this.name = name;
	}
	public Person(String name, int age){
		this(name);
		this.age = age;
	}
	
	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;
	}
	@Override
	public void sayChina() {
		System.out.println("作者:" + AUTHOR + ", 国籍: " + NATIONAL);
	}
	@Override
	public String sayHello(String name, int age) {
		return "你好!我叫" + this.name + ", 今年" + this.age + "岁!";
	}
}

public class ClassDemo03 {
	public static void main(String args[]) throws Exception {
		//获取Person类对应的Class类的实例
		Class<?> c = Class.forName("com.wbf.reflect.Person");
		//1.取得一个类所实现的全部接口
		Class<?> interfaces[] = c.getInterfaces();
		for (int i = 0; i < interfaces.length; i++)
		{
			//输出接口名称
			System.out.println("实例化的接口名称: " + interfaces[i].getName());
		}
		
		//2.取得父类
		Class<?> superC = c.getSuperclass();
		System.out.println("父类名称: " + superC.getName());
		
		//3.取得全部构造方法
		Constructor<?> cons[] = c.getConstructors();
		for (int i = 0; i < cons.length; i++)
		{
			Class<?> ps[] = cons[i].getParameterTypes();
			System.out.print("构造方法: ");
			System.out.print(Modifier.toString(cons[i].getModifiers()) + " ");//取出权限
			System.out.print(cons[i].getName());
			
			System.out.print("(");
			for (int j = 0; j < ps.length; j++)
			{
				System.out.print(ps[j].getName() + " arg" + j);
				if (j < ps.length - 1)
				{
					System.out.print(",");
				}
			}
			System.out.println("){}");
		}
		
		//4.取得全部方法,参数类型,返回值类型,异常类型等
		//在IDE中就使用此种方法:如当"."的时候会出现一个类的全部方法
		Method m[] = c.getMethods();
		for (int k = 0; k < m.length; k++)
		{
			System.out.println(m[k].getName());//输出方法名称
		}
		
		//5.取得全部属性
		Field[] fs1 = c.getFields();//取得父类的公共属性
		Field[] fs2 = c.getDeclaredFields();//取得本类属性
		System.out.print("父类公共属性: ");
		for (int i = 0; i < fs1.length; i++)
		{
			System.out.print(fs1[i].getName() + "、");
		}
		System.out.print("\n" + "本类属性: ");
		for (int i = 0; i < fs2.length; i++)
		{
			System.out.print(fs2[i].getName() + "、");
		}
	}
}

四、反射机制的深入应用

反射除了可以获取一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。

1)通过反射调用类中方法

package com.wbf.reflect;

import java.lang.reflect.Method;

class People {
	private int age;
	private String name;
	
	public People(){}
	public People(int age, String name){
		this.setAge(age);
		this.setName(name);
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void sayChina(){
		System.out.println("Welcome to China!");
	}
	public String sayHello(String name, int age){
		return "我是: " + name + ", 今年: " + age + "岁!!!";
	}
}

public class ClassDemo04 {
	public static void main(String[] args) throws Exception {
		//获取People类对应的Class类的实例对象
		Class<?> c = Class.forName("com.wbf.reflect.People");
		//根据方法名称和参数类型,获取方法对应的Method对象
		//此方法没有参数
		Method m = c.getMethod("sayChina");
		m.invoke(c.newInstance());//调用方法,必须传递对象实例
		
		m = c.getMethod("sayHello", String.class, int.class);
		//调用方法,必须传递对象实例和两个参数值
		String returnMess = (String)m.invoke(c.newInstance(), "wbf", 20);
		System.out.println(returnMess);
	}
}
2)调用setter和getter方法
public class ClassDemo05 {
	public static void main(String[] args) throws Exception {
		//获取People类对应的Class类的实例对象
		Class<?> c = Class.forName("com.wbf.reflect.People");
		Object obj = c.newInstance();
		setter(obj, "name", "zhangsan", String.class);
		System.out.println(getter(obj, "name"));
		
		setter(obj, "age", 20, int.class);
		System.out.println(getter(obj, "age"));
	}
	
	public static void setter(Object obj, String att, Object value, Class<?> type) throws Exception {
		Method m = obj.getClass().getMethod("set" + initStr(att), type);
		m.invoke(obj, value);
	}
	public static Object getter(Object obj, String att) throws Exception {
		Method m = obj.getClass().getMethod("get" + initStr(att));
		return m.invoke(obj);
	}
	public static String initStr(String att){
		return att.substring(0, 1).toUpperCase() + att.substring(1);
	}
}

2)通过反射操作属性

public class ClassDemo04 {
	public static void main(String[] args) throws Exception {
		//获取People类对应的Class类的实例对象
		Class<?> c = Class.forName("com.wbf.reflect.People");
		People p = (People)c.newInstance();
		Field nameField = c.getDeclaredField("name");//表示name属性
		Field ageField = c.getDeclaredField("age");//表示age属性
		
		nameField.setAccessible(true);//将name属性设置成可被外部访问
		nameField.set(p, "lisi");//设置name属性内容
		ageField.setAccessible(true);
		ageField.set(p, 25);
		
		//通过get取得属性内容
		System.out.println("姓名: " + nameField.get(p) + ", 年龄: " + ageField.get(p));
	}
}
但是通过反射操作属性时最好通过setter及getter方法,因为以上程序是通过扩大属性访问权限后直接操作属性的,但是在开发中属性时必须封装的。
2)通过反射操作数组

反射机制不仅可以用在类上,还可以应用在任意的引用数据类型的数据上,当然,这本身就包含了数组,即可以使用反射操作数组。在反射操作包java.lang.reflect中使用Array类表示一个数组,可以通过此类获取数组长度、数组内容等。

package com.wbf.reflect;

import java.lang.reflect.Array;

public class ClassArrayDemo {
	public static void main(String[] args) {
		int temp[] = {1, 2, 3};
		Class<?> c = temp.getClass().getComponentType();
		//获取数组类型名称和数组大小
		System.out.println(c.getName() + Array.getLength(temp));
		//输出数组元素
		for (int i=0; i<Array.getLength(temp); i++)
		{
			System.out.print(Array.get(temp, i) + "、");
		}
		Array.set(temp, 0, 10);//修改数组元素内容
		System.out.print(Array.get(temp, 0));
	}
}
在应用中还可以通过Array类根据已有的数组类型来开辟新的数组对象。
package com.wbf.reflect;

import java.lang.reflect.Array;

public class ClassArrayDemo {
	public static void main(String[] args) {
		int temp[] = {1, 2, 3};
		int newTemp[] = (int[])arrayInc(temp, 5);
		print(newTemp);
		
		System.out.println();
		
		String t[] = {"aaa", "bbb", "ccc"};
		String nt[] = (String[])arrayInc(t, 8);
		print(nt);
	}
	
	public static Object arrayInc(Object obj, int len){
		
		Class<?> c = obj.getClass();//得到数组的Class对象
		Class<?> arr = c.getComponentType();
		Object newO = Array.newInstance(arr, len);
		int co = Array.getLength(obj);
		System.arraycopy(obj, 0, newO, 0, co);
		return newO;
	}
	
	public static void print(Object obj){
		
		Class<?> c = obj.getClass();
		if (!c.isArray())
			return;
		Class<?> arr = c.getComponentType();
		System.out.println(arr.getName() + Array.getLength(obj));
		for (int i=0; i<Array.getLength(obj); i++)
		{
			System.out.print(Array.get(obj, i) + "、");
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值