文章目录
反射
耦合度:过个模块的关联关系(高内聚,低耦合)
反射发生在运行期
定义
反射:解析类的信息,获取字节码对象,然后产生实例对象的过程
被加载到内存中的字节码文件(有且只有一份)的类名的透明操作(想得到类里的任何数据都可以)
效率相对较低
反射使用的类:
Class
在运行状态中,对于任意一个类,都能获取属性和方法;
对于任意一个对象,都可以调用属性和方法;
我们就把可以动态获取和调用属性和方法的过程,叫反射
反射在平时写程序的时候,基本不用,通常完成框架
- 特点:使工程更加灵活,效率相对硬编码低
缺点
-
反射打破了封装原则
-
反射跳过了类型检查
代表类的类Class
不管使用哪一种方法获取对象的Class对象,都相等,在内存中有且只有一份
已知类名
Class<E> xxx = 类名.class
//只知道类名的情况下
//字符串的字节码对象
Class<String> clz = String.class;
//class java.lang.String
//接口的字节码对象
Class<List> clz1 = List.class;
//interface java.util.List
//数组的字节码对象
Class<int[]> clz2 = int[].class;//class [I
//基本类型的字节码对象
Class<Integer> clz3 = int.class;//int
已知对象
使用对象的getClass()方法,获取Class对象
Class<E> xxx = 对象名.getClass();
//已知对象,使用对象的getClass()方法,获取Class对象
Student stu = new Student();
Class clazz2 = stu.getClass();
String str = "abc";
Class<String> clz = (Class<String>) str.getClass();
框架中最经常用的方法,来获取Class对象
Class<E> xxx = Class.forName("包名.类名");
forName()
获取Class对象:首先检查内存中是否存在字节码文件
- 如果存在,返回Class对象
- 如果没有加载到内存,那么先加载该类的字节码文件到内存,返回该类的Class对象
Class clazz3 = Class.forName("cn.sxh.Student");
System.out.println(clazz3);//class cn.sxh.Student
代表构造方法的类Constructor
通过反射获取构造方法,使用构造方法创建对象
newInstance()
:调用指定类的无参构造
Class[] cs: getParameterTypes()
:获取所有的参数类型
isPrimitive()
:判断是否是基本类型避免有的类没有无参构造
public static Object clone1(Object o) throws IllegalAccessException, InstantiationException, InvocationTargetException { //1.获取原对象的字节码对象 Class<Object> clz = (Class<Object>) o.getClass(); //把所有构造方法放到数组中,只拿数组中第一个元素,保证一定会拿到一个构造方法 Constructor<Object> c = (Constructor<Object>) clz.getDeclaredConstructors()[0]; Class[] cs = c.getParameterTypes(); //新建数组,用于存储参数值 Object[] os = new Object[cs.length]; //定义遍历,表示os数组下标 int index = 0; //遍历cs数组 for (Class i : cs) { //每个i代表构造方法的每个参数类型 //判断是否是基本数据类型 if (i.isPrimitive()) { //判断是否是字符类型 if (i char.class) { //判断类型是否一致 os[index++] = '\u0000'; } if (i boolean.class) { os[index++] = false; } if (i float.class) { os[index++] = 0.0f; } if (i double.class) { os[index++] = 0.0; } //整形 os[index++]=0; }else { os[index++] = null; } } //2.获取实例对象---克隆对象 Object obj = c.newInstance(os); //3.获取原对象身上的所有属性 Field[] fields = clz.getDeclaredFields(); //4.把原对象所有属性赋值给实例对象(克隆)身上 for (Field field : fields) { field.setAccessible(true); field.set(obj, field.get(o)); } return obj; }
获取所有的非私有的构造方法
类名.class.getConstructors()
:Constructors[ ]
//获取所有的非私有的构造方法
Constructor[] cons = Student.class.getConstructors();
for(Constructor con : cons) {
System.out.println(con);
}
获取指定的构造方法
- 获取无参的构造方法:
类名.class.getConstructor(null);
:Constructor<类名>
Constructor<Student> con1 = Student.class.getConstructor(null);
//通过无参的构造方法创建对象
Student stu1 = con1.newInstance();
stu1.sleep();
stu1.name = "admin";
stu1.eat("苹果");
获取有参的构造方法:
getConstructor(String.class,int.class);
:参数对应构造方法的参数列表的类型的Class类型
String:
String.class
int:
int.class
//有参的构造方法
Class<Student> clz = Student.class;
Constructor<Student> con2 = clz.getConstructor(String.class,int.class);
Student stu2 = con2.newInstance("张三",20);
stu2.eat("包子");
获取非公开的构造方法
getDeclaredConstructor()
:获取指定的非公开的构造方法
setAccessible(true)
:暴力破解,允许突破修饰符权限传入值
Class<String> clz = String.class;
//获取有参构造
Constructor<String> con;
con = clz.getDeclaredConstructor(char[].class,boolean.class);
con.setAccessible(true);//暴力破解
String s = con.newInstance(new char[]{
'a','b'},true);
System.out.println(s);
代表属性的类Field
获取类的所有非私有属性
getFields()
:Field[ ] 返回所有非私有的成员变量,存在数组中
getModifiers()
:int 返回成员变量的访问修饰符,public-1
getName()
:String 返回成员变量的名字
getType()
:String 返回成员变量的类型(int,String,double……)
Class clazz = Student.class;
Student stu = (Student) clazz.newInstance();
//获取类的所有非私有属性
Field[] fields = clazz.getFields();
for(Field field : fields) {
System.out.println(field.getModifiers());
System.out.println(field.getName());
System.out.println(field.getType());
}
获取指定的属性
类名.class.getField(String name);
:name为要获取的类的成员变量名,返回类型:Field
//获取指定的属性
Field field1 = Student.class.getField("name");
给属性设置值,获取值
set(obj,String);
给变量赋值
- obj : 对象名,在该对象的变量中操作属性
- String :内容,要设置属性的内容
get(obj)
获取变量的值
- obj :要获取该变量的对象
//给属性设置值,获取值
field1.set(stu, "张三");
System.out.println(field1.get(stu));
获取私有属性,设置值,获取值
类名.class.getDeclaredField(String name);
获取变量age
setAccessible(true);
设置私有属性访问权限
//获取私有属性,设置值,获取值
Field field2 = Student.class.getDeclaredField("age");
field2.setAccessible(true);//设置私有属性访问权限
field2.set(stu, 22);
System.out.println(field2.get(stu));
代表方法的类Method
获取所有的非私有成员方法
类名.class.getMethods();
: Method[ ]
- 将类中所有的非私有方法返回到一个Method类型的数组中
getModifiers()
:int 获取方法的访问修饰符
getReturnType()
:String 获取方法的返回类型
getName()
:String 获取方法的名字
Class clazz = Student.class;
//获取所有的非私有成员方法
Method[] methods = clazz.getMethods();
for(Method method:methods) {
System.out.print(method.getModifiers()+"\t");
System.out.print(method.getReturnType()+"\t");
System.out.println(method.getName());
}
获取指定的成员方法
类名.class.getMethod(String name,Class parameterType);
name
:获取的方法的名称parameterType
:获取的该方法的参数的Class类型,如果方法没有参数列表,就写null
- String:
String.class
- int:
int.class
- 等等
调用方法:
invoke(Object obj,Object args);
- obj:要调用该方法的对象的对象名
- args:该方法的参数列表,方法为无参时,写null
//获取指定的成员方法
Method m1 = clazz.getMethod("eat", String.class);
//创建对象,clazz = Student.class,没有获取构造方法,所有要强制类型转换
Student stu = (Student) clazz.newInstance();
m1.invoke(stu, "苹果");
获取私有的成员方法
类名.class.getDeclaredMethod(String name,Class parameterType);
name
:获取的方法的名称parameterType
:获取的该方法的参数的Class类型,如果方法没有参数列表,就写null
- String:
String.class
- int:
int.class
- 等等
因为是私有的方法,要设置访问权限才可使用
setAccessible(true)
设置私有成员方法的访问权限
//获取私有的成员方法
Method m2 = clazz.getDeclaredMethod("study",null);
m2.setAccessible(true);
m2.invoke(stu,null);
代表注解的类Annotation
配置文件利用反射
配置文件
配置文件通过类似键值对的方式存放数据
路径通过16进制的Unicode码来表示
className:表示类名
- \u6848:案
- \u4f8b:例
- DDC:类名
\u6848\u4f8b.DDC
:案例.DDCmethodName:表示方法名
- qi:DDC中的方法名称
className=\u6848\u4f8b.DDC
methodName=qi
类中加载配置文件
加载配置文件要通过IO流读取配置文件的内容
Properties
:读取配置文件的类
load(InputStream input)
:加载配置文件
Properties p = new Properties();
InputStream input = new FileInputStream("pro.properties");
p.load(input);
提取类路径和方法名
getProperty(String Key);
:获取配置文件中的key值
- key:配置文件中的key值
String className = p.getProperty("className");
String methodName = p.getProperty("methodName");
通过反射创建对象,调用方法
Class clazz = Class.forName(className);
Method m = clazz.getMethod(methodName, null);
m.invoke(clazz.newInstance(), null);
DDC类
public class DDC {
public void qi() {
System.out.println("骑电动车出去兜风");
}
}