反射机制
定义
反射机制是在运行状态
中所使用:
- 对于任何一个类,都能够知道这个类的所有属性和方法。
- 对于任意一个对象,都能够调用它的任意一个方法和属性。
功能
- 运行时判断
任意一个对象
所属的类 - 运行时构造
任意一个类
的对象 - 运行时判断
任意一个类
所具有的成员变量和方法 - 运行时调用
任意一个对象
的方法 - 生成动态代理
获取反射对象(反射入口)
// 第一种方法
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();
}
}
添加反射,原方法内不需要修改代码,避免代码耦合性。