java基础-反射机制
反射:框架设计的灵魂1、反射的概念class是一切反射的根源,JAVA反射机制是在运行状态中,对于任何一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制使用反射的好处:可以在程序运行过程中,操作这些对象。可以解耦,提高程序的可扩展性。java程序的三个阶段:Source源代码
反射:框架设计的灵魂
1、反射的概念
- class是一切反射的根源,JAVA反射机制是在运行状态中,对于任何一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
- 使用反射的好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
java程序的三个阶段:
- Source源代码阶段:纯java代码(.java),当代码被编译以后变成字节码文件(.class)
- Class类对象阶段:通过类加载器将字节码文件(.class)加载进内存
- RunTime运行时阶段:程序创建对象
获取class对象三种方式
- Class.forName(“类名”)
- 多用于配置文件,将类名定义在配置文件中然后加载类
- 类名.class
- 多用于参数的传递
- 对象.getClass()
- 多用于对象的获取字节码的方式
获取class对象案例:
person对象:
public class Person
{
private String name;
private int age;
public Person() {}
public Person(String name, int age)
{
this.name = 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;}
}
获取class对象案例:
public class ReflectDemo1
{
public static void main(String[] args) throws Exception
{
//1.Class.forName("全类名")
Class cls1 = Class.forName("com.domain.Person");
System.out.println(cls1);//class com.domain.Person
//2.类名.class
Class cls2 = Person.class;
System.out.println(cls2);//class com.domain.Person
//3.对象.getClass()
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);//class com.domain.Person
// == 比较三个对象
System.out.println(cls1 == cls2);//true
System.out.println(cls1 == cls3);//true
}
}
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
2、Class对象功能
2.1 获取功能
-
获取成员变量们
- Field[] getFields() 获取所有public修饰的成员变量
- Field getField(String name) 获取指定名称的 public修饰的成员变量
- Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
- Field getDeclaredField(String name) 获取指定名称的成员变量,不考虑修饰符
-
获取构造方法们
-
Constructor<?>[] getConstructors() 获取所有public修饰的构造方法
-
Constructor getConstructor(Class<?>… parameterTypes) 获取指定名称public修饰的构造方法
-
Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法,不考虑修饰符
-
Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取指定名称的构造方法,不考虑修饰符
-
-
获取成员方法们:
-
Method[] getMethods() : 获取所有public修饰的方法
-
Method getMethod(String name, Class<?>… parameterTypes) : 获取public修饰的指定名称的方法
-
Method[] getDeclaredMethods() 获取所有的方法,不考虑修饰符
-
Method getDeclaredMethod(String name, Class<?>… parameterTypes) 获取指定名称的方法,不考虑修饰符
-
-
获取全类名
- String getName()
2.2 功能案例
提供person实体类:
public class Person
{
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person() {}
public Person(String name, int age)
{
this.name = 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;}
}
2.2.1 Field:成员变量
操作:
-
设置值
- void set(Object obj, Object value)
-
获取值
- get(Object obj)
-
忽略访问权限修饰符的安全检查
- setAccessible(true) : 暴力反射
测试filed类:
import com.domain.Person;
import java.lang.reflect.Field;
public class ReflectDemo2
{
public static void main(String[] args) throws Exception
{
//0.获取Person的Class对象
Class personClass = Person.class;
/*
* @Descript 获取成员变量们
* Field[] getFields(): 获取所有public修饰的成员变量
* Field getField(String name): 获取指定名称的 public修饰的成员变量
*
* Field[] getDeclaredFields(): 获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name)
*/
//1.Field[] getFields(): 获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields)
{
System.out.println(field);//public java.lang.String com.domain.Person.a
}
System.out.println("---------------");
//2.Field getField(String name): 获取指定名称的 public修饰的成员变量
Field a = personClass.getField("a");
//获取成员变量a的值
Person p = new Person();
Object value1 = a.get(p);
System.out.println(value); //null
//设置a的值
a.set(p,"张三");
System.out.println(p);
//Person{name='null', age=0, a='张三', b='null', c='null', d='null'}
System.out.println("---------------");
//3.Field[] getDeclaredFields(): 获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields)
{
System.out.println(declaredField);
//private java.lang.String com.domain.Person.name
//private int com.domain.Person.age
//public java.lang.String com.domain.Person.a
//protected java.lang.String com.domain.Person.b
//java.lang.String com.domain.Person.c
//private java.lang.String com.domain.Person.d
}
//4.Field getDeclaredField(String name): 获取指定名称的成员变量,不考虑修饰符
Field d = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);//null
}
}
2.2.2 Constructor:构造方法
创建对象:
-
T newInstance(Object… initargs)
-
如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
import com.domain.Person;
import java.lang.reflect.Constructor;
public class ReflectDemo3
{
public static void main(String[] args) throws Exception
{
//0.获取Person的Class对象
Class personClass = Person.class;
/* @Description 获取构造方法们
* Constructor<?>[] getConstructors() 获取所有public修饰的构造方法
* Constructor<T> getConstructor(class<?>... parameterTypes) 获取指定名称public修饰的构造方法
*
* Constructor<T> getDeclaredConstructor(class<?>... parameterTypes) 获取所有的构造方法,不考虑修饰符
* Constructor<?>[] getDeclaredConstructors() 获取指定名称的构造方法,不考虑修饰符
*/
//Constructor<T> getConstructor(类<?>... parameterTypes) 获取指定名称public修饰的构造方法
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);//public com.domain.Person(java.lang.String,int)
//创建对象
Object person = constructor.newInstance("张三", 23);
System.out.println(person);
//Person{name='张三', age=23, a='null', b='null', c='null', d='null'}
System.out.println("---------------");
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);//public com.domain.Person()
//创建对象
Object person1 = constructor1.newInstance();
System.out.println(person1);
//Person{name='null', age=0, a='null', b='null', c='null', d='null'}
//使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
Object o = personClass.newInstance();
System.out.println(o);
//Person{name='null', age=0, a='null', b='null', c='null', d='null'}
}
}
2.2.3 Method:方法对象
执行方法:
- Object invoke(Object obj, Object… args)
public class ReflectDemo4
{
public static void main(String[] args) throws Exception
{
//0.获取Person的Class对象
Class personClass = Person.class;
/*
* Method[] getMethods() 获取所有public修饰的方法
* Method getMethod(String name, Class<?>... parameterTypes) 获取public修饰的指定名称的方法
* Method[] getDeclaredMethods获取所有的方法,不考虑修饰符
* Method getDeclaredMethod(String name, Class<?>... parameterTypes获取指定名称的方法,不考虑修饰符
*/
//获取指定名称的方法
Method eat_method = personClass.getMethod("eat");
Person p = new Person();
//指定方法
eat_method.invoke(p);//eat...
Method eat_method2 = personClass.getMethod("eat",String.class);
//执行方法
eat_method2.invoke(p,"饭");//eat饭
System.out.println("----------------");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods)
{
System.out.println(method);
//获取方法名称
String name = method.getName();
System.out.println(name);
}
}
}
获取方法名称:
- String getName():获取方法名
public class ReflectDemo4
{
public static void main(String[] args) throws Exception
{
//0.获取Person的Class对象
Class personClass = Person.class;
Person p = new Person();
System.out.println("----------------");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods)
{
//获取方法名称
String name = method.getName();
System.out.println(name);
}
}
}
2.2.4 获取全类名
- String getName()
public class ReflectDemo4
{
public static void main(String[] args) throws Exception
{
//0.获取Person的Class对象
Class personClass = Person.class;
//获取类名
String className = personClass.getName();
System.out.println(className);//com.domain.Person
}
}
3、黑马案例
需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
- 实现:
- 配置文件
- 反射
- 步骤:
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
创建pro.properties文件:
className = com.domain.Person
methodName = eat
创建ReflectTest类:
public class ReflectTest {
public static void main(String[] args) throws Exception {
//可以创建任意类的对象,可以执行任意方法
/*
* 前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
* */
//1.加载配置文件
//1.1创建Properties对象
Properties pro = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream in = classLoader.getResourceAsStream("pro.properties");
pro.load(in);
//2.获取配置文件中的定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
4、反射工具类
public class ReflectUtils
{
/**
* @Descript 获取无参构造函数
* @param className
* @return
*/
public static Object createObject(String className)
{
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
try
{
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 获取一个参数的构造函数 已知className
* @param className
* @param pareTyple
* @param pareVaule
* @return
*/
public static Object createObject(String className, Class pareTyple, Object pareVaule)
{
Class[] pareTyples = new Class[]{pareTyple};
Object[] pareVaules = new Object[]{pareVaule};
try
{
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 获取构造方法 已知类
* @param clazz
* @return
*/
public static Object createObject(Class clazz)
{
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return createObject(clazz, pareTyples, pareVaules);
}
/**
* @Descript 获取单个参数的构造方法 已知类
* @param clazz
* @param pareTyple
* @param pareVaule
* @return
*/
public static Object createObject(Class clazz, Class pareTyple, Object pareVaule)
{
Class[] pareTyples = new Class[]{pareTyple};
Object[] pareVaules = new Object[]{pareVaule};
return createObject(clazz, pareTyples, pareVaules);
}
/**
* @Description 获取多个参数的构造方法 已知className
* @param className
* @param pareTyples
* @param pareVaules
* @return
*/
public static Object createObject(String className, Class[] pareTyples, Object[] pareVaules)
{
try
{
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/**
*@Descript 获取构造方法
* @param clazz
* @param pareTyples
* @param pareVaules
* @return
*/
public static Object createObject(Class clazz, Class[] pareTyples, Object[] pareVaules)
{
try
{
Constructor ctor = clazz.getDeclaredConstructor(pareTyples);
ctor.setAccessible(true);
return ctor.newInstance(pareVaules);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 执行无参方法
* @param obj
* @param methodName
* @return
*/
public static Object invokeInstanceMethod(Object obj, String methodName)
{
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
}
/**
* @Descript 执行一个参数的方法
* @param obj
* @param methodName
* @param pareTyple
* @param pareVaule
* @return
*/
public static Object invokeInstanceMethod(Object obj, String methodName, Class pareTyple, Object pareVaule)
{
Class[] pareTyples = {pareTyple};
Object[] pareVaules = {pareVaule};
return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
}
/**
* @Descript 执行多个参数的方法
* @param obj
* @param methodName
* @param pareTyples
* @param pareVaules
* @return
*/
public static Object invokeInstanceMethod(Object obj, String methodName, Class[] pareTyples, Object[] pareVaules)
{
if (obj == null)
{
return null;
}
try {
//调用一个private方法 //在指定类中获取指定的方法
Method method = obj.getClass().getDeclaredMethod(methodName, pareTyples);
method.setAccessible(true);
return method.invoke(obj, pareVaules);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 执行无参静态方法
* @param className
* @param method_name
* @return
*/
public static Object invokeStaticMethod(String className, String method_name)
{
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
}
/**
* @Descript 执行一个参数的静态方法
* @param className
* @param method_name
* @param pareTyple
* @param pareVaule
* @return
*/
public static Object invokeStaticMethod(String className, String method_name, Class pareTyple, Object pareVaule)
{
Class[] pareTyples = new Class[]{pareTyple};
Object[] pareVaules = new Object[]{pareVaule};
return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
}
/**
* @Descript 执行多个参数的静态方法
* @param className
* @param method_name
* @param pareTyples
* @param pareVaules
* @return
*/
public static Object invokeStaticMethod(String className, String method_name, Class[] pareTyples, Object[] pareVaules)
{
try
{
Class obj_class = Class.forName(className);
return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 无参静态方法
* @param method_name
* @return
*/
public static Object invokeStaticMethod(Class clazz, String method_name)
{
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules);
}
/**
* @Descript 一个参数静态方法
* @param clazz
* @param method_name
* @param classType
* @param pareVaule
* @return
*/
public static Object invokeStaticMethod(Class clazz, String method_name, Class classType, Object pareVaule)
{
Class[] classTypes = new Class[]{classType};
Object[] pareVaules = new Object[]{pareVaule};
return invokeStaticMethod(clazz, method_name, classTypes, pareVaules);
}
/**
* @Descript 多个参数的静态方法 已知类
* @param clazz
* @param method_name
* @param pareTyples
* @param pareVaules
* @return
*/
public static Object invokeStaticMethod(Class clazz, String method_name, Class[] pareTyples, Object[] pareVaules)
{
try
{
Method method = clazz.getDeclaredMethod(method_name, pareTyples);
method.setAccessible(true);
return method.invoke(null, pareVaules);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 获取属性值
* @param className
* @param obj
* @param filedName
* @return
*/
public static Object getFieldObject(String className, Object obj, String filedName)
{
try
{
Class obj_class = Class.forName(className);
return getFieldObject(obj_class, obj, filedName);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 获取属性值
* @param clazz
* @param obj
* @param filedName
* @return
*/
public static Object getFieldObject(Class clazz, Object obj, String filedName)
{
try
{
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(obj);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* @Descript 设置属性值
* @param clazz
* @param obj
* @param filedName
* @return
*/
public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule)
{
try
{
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
field.set(obj, filedVaule);
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* @Descript 设置属性值
* @param className
* @param obj
* @param filedName
* @param filedVaule
*/
public static void setFieldObject(String className, Object obj, String filedName, Object filedVaule)
{
try
{
Class obj_class = Class.forName(className);
setFieldObject(obj_class, obj, filedName, filedVaule);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
/**
* @Descript 静态变量获取值
* @param className
* @param filedName
* @return
*/
public static Object getStaticFieldObject(String className, String filedName)
{
return getFieldObject(className, null, filedName);
}
/**
* @Descript 静态变量获取值
* @param clazz
* @param filedName
* @return
*/
public static Object getStaticFieldObject(Class clazz, String filedName)
{
return getFieldObject(clazz, null, filedName);
}
/**
* @Descript 静态变量设置值
* @param classname
* @param filedName
* @return
*/
public static void setStaticFieldObject(String classname, String filedName, Object filedVaule)
{
setFieldObject(classname, null, filedName, filedVaule);
}
/**
* @Descript 静态变量设置值
* @param clazz
* @param filedName
* @return
*/
public static void setStaticFieldObject(Class clazz, String filedName, Object filedVaule)
{
setFieldObject(clazz, null, filedName, filedVaule);
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)