Java反射机制

反射机制

定义

反射机制是在运行状态中所使用:

  • 对于任何一个类,都能够知道这个类的所有属性和方法。
  • 对于任意一个对象,都能够调用它的任意一个方法和属性。

功能

  • 运行时判断任意一个对象所属的类
  • 运行时构造任意一个类的对象
  • 运行时判断任意一个类所具有的成员变量和方法
  • 运行时调用任意一个对象的方法
  • 生成动态代理

获取反射对象(反射入口)

//  第一种方法
Date date = new Date();
Class<?> c = date.getClass();//  使用泛型通配符接收泛型对象

//  第二种方法
Class<?> b = Date.class;

//  第三种方法(使用最多的方法)
try{
	Class<?> a = class.forName("java.util.Date");// 全类名
}catch(ClassNotFoundException e){
	e.printStackTrace();
}

反射实例化

public class Person
{
    public Person()
    {
        System.out.println("Non Arguments Constructor");
    }
    
    @Override
    public String toString()
    {
        return "toString";
    }
}
Class<?> c = Class.forName("study.Person");
Person person = (Person)c.newInstance();// 获取对象实例
System.out.println(person);

通过反射获取对象属性与方法

Person

private String name;
private String age;
public String time;
// 省略getter、setter
public Person() {
	super();
}
public Person(String name, String age) {
	super();
	this.name = name;
	this.age = age;
}
private Person(String name,String age,String time) {
	super();
	this.name = name;
	this.age = age;
	this.time = time;
}
public void say() {
	System.out.println("Person Say!");
}
private void sayHello(String name) {
	System.out.println("Say Hello!" + name);
}
@Override
public String toString() {
	return "Person [name=" + name + ", age=" + age + ", time=" + time + "]";
}

Student

private String name;
private String number;
// 省略getter、setter
@Override
public String toString() {
	return "Student [name=" + name + ", number=" + number + "]";
}
public void say() {
	System.out.println("Student Say!");
}

ReflectFieldAndMethod

static Class<?> flect = null;
// 获取反射的三种方式
static {
	try {
		// 加载反射第一种方式
		flect = Class.forName("com.hellowy.reflection.Person");
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}
public static void main(String[] args) {
	// 获取对象的全部方法
	Method[] declaredMethods = flect.getDeclaredMethods();
	for(Method declaredMethod:declaredMethods) {
		System.out.println(declaredMethod);
	}
	System.out.println("----------------");
	// 获取对象的全部属性
	Field[] declaredFields = flect.getDeclaredFields();
	for(Field declaredField:declaredFields) {
		System.out.println(declaredField);
	}
	System.out.println("----------------");
	// 获取对象的公共方法(父类、接口)
	Method[] methods = flect.getMethods();
	for(Method method:methods) {
		System.out.println(method);
	}
	System.out.println("----------------");
	// 获取对象的公共属性(父类、接口)
	Field[] fields = flect.getFields();
	for(Field field:fields) {
		System.out.println(field);
	}
	System.out.println("----------------");
	// 获取对象实例
	Person person = null;
	try {
		person = (Person)flect.newInstance();
		person.setAge("18");
		System.out.println(person);
	} catch (Exception e) {
		e.printStackTrace();
	}
	System.out.println("----------------");
	// 控制对象私有属性及方法
	try {
		// 控制私有属性
		Field declaredField = flect.getDeclaredField("age");// 属性名
		declaredField.setAccessible(true);// 开启访问权限(私有属性)
		declaredField.set(person, "30");
		System.out.println(person);
		System.out.println("----------------");
		// 控制私有方法
		Method declaredMethod = flect.getDeclaredMethod("say", String.class);// 方法名、参数类型
		declaredMethod.setAccessible(true);// 开启访问权限(私有方法)
		declaredMethod.invoke(person, "Tom");// 执行方法
	} catch (Exception e) {
		e.printStackTrace();
	}
}

获取对象全部(公共)属性(方法)时,只需在方法中添加Declared关键字即可,方便记忆。

通过反射访问对象的private属性、方法时,需要提前开启访问权限,否则将会抛出can not access a member of class xxx with modifiers "private"异常。

通过反射获取构造方法

static Class<?> flect = null;
static {
	try {
		flect = Class.forName("com.hellowy.reflection.Person");
	} catch (Exception e) {
		e.printStackTrace();
	}
}
public static void main(String[] args) {
	// 获取对象的公共构造方法
	Constructor<?>[] constructors = flect.getConstructors();
	for(Constructor constructor:constructors) {
		System.out.println(constructor);
	}
	System.out.println("----------------");
	// 获取对象的全部构造方法(包含私有构造方法)
	Constructor<?>[] declaredConstructors = flect.getDeclaredConstructors();
	for(Constructor declaredConstructor:declaredConstructors) {
		System.out.println(declaredConstructor);
	}
	System.out.println("----------------");
	// 获取对象的指定公共构造方法
	try {
		// 方法内实参填写参数类型,无参则不填
		Constructor<?> constructor = flect.getConstructor(String.class,String.class);
		/* 通过构造方法实例化对象,可以实例化有参对象
			* flect.newInstance()只能实例化无参对象
			*/
		Person person = (Person)constructor.newInstance("zs","20");
		System.out.println(person);
	} catch (Exception e) {
		e.printStackTrace();
	}
	System.out.println("----------------");
	// 获取对象的指定私有构造方法
	try {
		Constructor<?> declaredConstructor = flect.getDeclaredConstructor(String.class,String.class,String.class);
		declaredConstructor.setAccessible(true);// 设置私有属性前开启访问权限
		Person person = (Person)declaredConstructor.newInstance("zs","30","2020");
		System.out.println(person);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

通过反射动态调用方法

class.txt

classname=com.hellowy.reflection.Student
methodname=say

DynamicInvocation

Properties prop = new Properties();
try {
	prop.load(new FileReader("class.txt"));
} catch (Exception e) {
	e.printStackTrace();
}
String className = prop.getProperty("classname");// 注意属性文件中声明全类名,否则无法加载
String methodName = prop.getProperty("methodname");
Class<?> flect = null;
try {
	flect = Class.forName(className);// 获取反射对象
	Method method = flect.getMethod(methodName);// 获取反射对象方法
	method.invoke(flect.newInstance());// 执行反射对象方法(根据反射类建立新的实例)
} catch (Exception e) {
	e.printStackTrace();
}

通过反射越过泛型检查

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//		list.add("String");// 无法通过此种方式添加
Class<?> flect = list.getClass();
try {
	Method method = flect.getMethod("add", Object.class);
	method.invoke(list, "String");
	System.out.println(list);// 1 2 3 string
}  catch (Exception e) {
	e.printStackTrace();
}

不建议这样使用,容易造成数据混乱。

为任意对象的属性赋值

PropertyUtil

/**
* 
* @param obj 赋值对象
* @param propertyName 赋值属性
* @param value 值
*/
public static void setProperty(Object obj,String propertyName,Object value){
Class<?> flect = obj.getClass();
try {
	Field field = flect.getDeclaredField(propertyName);
	field.setAccessible(true);
	field.set(obj, value);
} catch (Exception e) {
	e.printStackTrace();
}
}

Test

Person person = new Person();
PropertyUtil.setProperty(person, "name", "zs");
PropertyUtil.setProperty(person, "age", "30");
Student stu = new Student();
PropertyUtil.setProperty(stu, "name", "ls");
PropertyUtil.setProperty(stu, "number", 30);
System.out.println(person);
System.out.println(stu);

将反射应用于工厂模式

  • 单例模式
package com.test;

abstract class Fruit
{
	abstract public void eat();
}

class Apple extends Fruit
{
	public void eat()
	{
		System.out.println("吃苹果");
	}
}

class Orange extends Fruit
{
	public void eat()
	{
		System.out.println("吃橘子");
	}
}

class Factory
{
	/**
	 * 对象工厂
	 * @param name 对象名
	 * @return 对象实例
	 */
	public static Fruit getInstance(String name)
	{
		switch(name)
		{
		case "苹果":
			return new Apple();
		case "橘子":
			return new Orange();
		default:
			return null;
		}
	}
}

public class Test {
	public static void main(String[] args) {
		Fruit f = Factory.getInstance("苹果");
		f.eat();
	}
}

  • 改进后的工厂模式(使用反射)
class Factory
{
	/**
	 * 反射构造对象工厂
	 * @param name 对象全类名
	 * @return 对象实例
	 */
	public static Fruit getInstance(String name)
	{
		try {
			Class<?> flect = Class.forName(name);
			return (Fruit)flect.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}
public class Test {
	public static void main(String[] args) {
		Fruit f = Factory.getInstance("com.test.pear");// 对象全类名
		f.eat();
	}
}

添加反射,原方法内不需要修改代码,避免代码耦合性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值