反射
类的加载
- 使用类时,类未被加载到内存中--加载,连接,初始化
- 加载:将class文件读入内存,并为之创建一个class对象,任何类被使用时系统都会建立一个class对象
- 连接
- 验证 是否有正确的内部结构,并和其他类协调一致
- 准备 负责为类的静态成员分配内存,并设置默认初始化值
- 解析 将类的二进制数据中的符号引用替换为直接引用
- 初始化
- 调用构造函数进行初始化
- 类初始化时机创建某个类
1. 创建类的实例
2. 类的静态变量,或者为静态变量赋值
3. 类的静态方法
4. 使用类的反射机制强制创建某个类或接口对应的java.lang.Class对象
5. 初始化某个类的子类
6. 直接使用java.exe来运行某个主类
- 类加载器
- 负责将.class文件加载到内存中,并为之生成class对象
- 类加载器的组成加载器
- Bootstrap ClassLoader根类加载器
- 引导类加载器,负责java核心类的加载
- System,String等,在jdk的lib目录下的rt.jar文件中
- Extension ClassLoader扩展类加载器
- JRE扩展目录中的jar目录
- jdk 下的jre下的lib下的ext目录
- System ClassLoader系统加载器
- jvm启动时加载java命令的class文件。以及classpath环境变量所指定的jar
- Bootstrap ClassLoader根类加载器
反射
- 定义
java反射机制是在运行状态,对应任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- Class类
- Class没有公共构造方法。
- Class对象是在加载类时由java虚拟机以及通过调用类加载器中的defineClass方法自动构造的
- 获取Class对象的三种方式(获取字节码对象--Class对象为 包名.类名)
- 通过Object对象的getClass()方法
- 通过类名.class直接获取
- 通过Class的方法forName(“类名”)
- 通过反射获取
- 通过反射获取构造方法并使用
- 返回单个
- public的:getConstructor(Class<?>...parameterTypes)
- 包含private的:getDeclaredConstructor(Class<?>...parameterTypes)
- 返回多个
- public的:getConstructors()
- 包含private的:getDeclaredConstructors()
- 返回单个
- 通过反射方式,获取构造方法,创建对象
- 获取到Class对象
- 获取指定的构造方法
- 通过构造Constructor中的方法,创建对象
Class c=Class.forName("com.peng.Person"): Constructor con=c.getConstructor(String.class,int.class); Object obj=con.newInstance("张三",12);
- 通过反射方式,获取私有构造方法,创建对象
- AccessibleObject类是Filed,Method和Constructor的父类
- 它提供了将反射的对象标记在使用时取消默认java访问控制检查的能力
- setAccessible(true/false)true为取消权限,false不取消权限检查
- 步骤
1. 获取Class 2. 获取指定的构造方法 3. 暴力访问,通过setAccessible(true)方法 4. 通过构造方法类Constructor来创建对象
Class c=Class.forName("com.peng.Person"); Constructor con=c.getDeclaredConstructor(String.class,int.class); con.setAccessible(true); Object obj=con.newInstance("小明",12);
- AccessibleObject类是Filed,Method和Constructor的父类
-
通过反射获取成员变量并使用
- 成员变量使用Filed表示
- 方法
- getFiled(String name)--public修饰的变量
- getDeclaredFiled(String name)--任意权限
- getFileds()--获取所有public的变量
- getDeclaredFileds()--获取所有变量
-
实例
Class c=Class.forName("com.peng.Person"); Fileds[] fileds=c.getDeclaredFileds(); for(Filed filed:fileds){ System.out.println(filed); }
Filed temp=Class.forName("com.peng.Person").getFiled("age");
- Filed方法
- set(obj,值)
- get(obj)
Class c=Class.forName("com.peng.Person"); Constructor con=c.getConstructor(String.class); Object obj=con.newInstance("李四"); Filed filed_name=c.getFiled("name"); filed_name.set(obj,"王五"); filed_name.get(obj);
- 通过反射获取成员方法并使用
- Method类
- 方法(Class类方法)
- getMethod(String name,Class<?>... paraterTypes)--public的有参数的方法
- getDeclaredMethod(String name,Class<?>... paraterTypes)--任意的的代参数的方法
- getMethods()--获取全部publi的方法
- getDeclaredMethods()--获取所有方法
- 方法(Class类方法)
- 使用
Class c=Class.forName("com.peng.Person"); Constructor con=c.getDeclaredConstructor(String.class); Object obj=con.newInstance("赵六"); Method method1 = c.getDeclaredMethod("addPerson",int.class); method1.setAccessible(true);//暴力访问--private Object reslute=cmethod1.invoke(obj,12);1. 获取Class对象 2. 获取构造方法 3. 通过构造方法,创建对象 4. 获取指定的方法 5. 执行找到的方法
- Method类
练习
-
将已存在的ArrayList中添加String数据(泛型的擦除)
1. 创建ArrayList<Integer>对象 list 2. 往list对象中添加Integer对象 3. 获取ArrayList的Class 4. 获取add方法 5. 添加String数据
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); Class c=Class.forName("java.util.ArrayList"); //这里的Object.class保证可以添加任何对象 Method addMethod=c.getMthod("add",Object.class); addMethod.invoke(list,"哈哈");
package com.peng.test; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Scanner; /** * @author kungfu~peng * @data 2017年10月9日 * @description */ public class Demo1 { public static void main(String[] args) throws Exception { ArrayList<Integer> list=new ArrayList<Integer>(); list.add(1); Class c=Class.forName("java.util.ArrayList"); Method me=c.getMethod("add", Object.class); me.invoke(list, "hehge"); System.out.println(list); } }
- 反射配置文件创建对象
- 读取配置文件的过程
1. Properties prop=new Properties(); 2. prop.load(new FileInputStream("person.properties")); 3. String name=prop.getProperty("name");
- 创建对象
1. Class对象 2. 构造函数创建对象
- 读取配置文件的过程
总结
- 如何获取Class对象
- 通过Object的getClass()方法
- 类名.class
- 反射Class.forName(String className)
- 通过反射,获取类中的构造函数
- Class的对象.getConstructor(参数)
- 通过反射,new对象
- 构造对象.newInstance(实参);
- 通过反射,找到方法并执行
- Class对象.getMethod(方法名,方法参数);
- Method对象.invoke(obj,方法实参);
- 通过反射,获取成员变量
- Class对象.Filed(变量名称);
- Filed对象的方法
- set(obj,实参)
- get(obj)
练习
package testt;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author kungfu~peng
* @data 2017年10月10日
* @description
*/
public class Person {
private int age;
protected String name;
String sex;
public int id;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(int age, String name, String sex, int id) {
super();
this.age = age;
this.name = name;
this.sex = sex;
this.id = id;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// 方法
/**
* 功能: 返回值类型: 参数列表:
*/
private void add() {
System.out.println("add");
}
/**
* 功能: 返回值类型: 参数列表:
*/
protected void delete() {
System.out.println("delete");
}
/**
* 功能: 返回值类型: 参数列表:
*/
void update() {
System.out.println("update");
}
/**
* 功能: 返回值类型: 参数列表:
*/
public void query(int id) {
System.out.println("query");
}
// 测试
public static void main(String[] args) throws Exception {
// 获取Class对象
Class c = Class.forName("testt.Person");
// 获取构造方法
Constructor con = c.getConstructor(int.class, String.class,
String.class, int.class);
// 通过构造方法来创建对象
Object obj = con.newInstance(12, "aa", "bb", 23);
// 获取属性
Field id_Filed = c.getDeclaredField("id");
Field name_Filed = c.getDeclaredField("name");
Field sex_Filed = c.getDeclaredField("sex");
Field age_Filed = c.getDeclaredField("age");
name_Filed.setAccessible(true);
id_Filed.setAccessible(true);
sex_Filed.setAccessible(true);
age_Filed.setAccessible(true);
// 设置属性
id_Filed.set(obj, 100);
name_Filed.set(obj, "100");
sex_Filed.set(obj, "100");
age_Filed.set(obj, 100);
// 获取属性值
System.out.println(id_Filed.get(obj));
// 获取方法
Method me = c.getDeclaredMethod("add", null);
me.setAccessible(true);
me.invoke(obj, null);
}
}
补充
- 高内聚,低耦合--提高模块内的利用率;降低模块间的依赖。
- 反射最大作用:解耦
- 一个类的内容
1. Class--代表字节码的类--代表类的类 2. Package--代表包的类 3. Field--代表方法的类 4. Method--代表方法的类 5. Constructor--代表构造方法的类 6. Annotation--代表注解的类
- 反射:剖析类,分析类的字节码,产生对应的字节码对象以及实例对象
例:模拟运行时修改配置文件不影响程序运行
- 目录结构
- src
- com.pemg.classdemo2
- Doctor.java
- Person.java
- Teacher.java
- Test.java
- com.pemg.classdemo2
- config.properties
- src
-
源代码
-
Doctor.java
package com.peng.classdemo2; import java.util.Date; /** * @author kungfu~peng * @data 2017年11月13日 * @description */ public class Doctor implements Person { private String name; private int age; private char gender; private Date date; private double salary; 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; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public void eat() { System.out.println(name + "在手术室吃饭!"); } @Override public void work() { System.out.println(name + "医生:" + date.getYear() + "年," + date.getMonth() + "月," + date.getDay() + "日" + " 在工作"); } @Override public void tax() { System.out.println(name + "交税" + salary * 0.4 + "元"); } }
-
Person.java
package com.peng.classdemo2; /** * @author kungfu~peng * @data 2017年11月13日 * @description */ public interface Person { public void eat(); public void work(); public void tax(); }
-
Teacher.java
package com.peng.classdemo2; import java.util.Date; /** * @author kungfu~peng * @data 2017年11月13日 * @description */ public class Teacher implements Person { private String name; private int age; private char gender; private Date date; private double salary; 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; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public void eat() { System.out.println(name + "在教室吃饭!"); } @Override public void work() { System.out.println(name + "老师:" + date.getYear() + "年," + date.getMonth() + "月," + date.getDay() + "日" + " 在工作"); } @Override public void tax() { System.out.println(name + "交税" + salary * 0.02 + "元"); } }
-
Test.java
package com.peng.classdemo2; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Method; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Properties; /** * @author kungfu~peng * @data 2017年11月13日 * @description 反射机制实现对类的不修改调用操作 */ public class Test { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { // 模拟运行 while (true) { Thread.sleep(10000);// 休眠期间修改config.properties的数据试试看 // 加载配置文件 Properties prop = new Properties(); prop.load(new FileInputStream(new File("src/config.properties"))); // 获取类名 String className = prop.getProperty("classname"); // 获取属性字符串 String attrName = prop.getProperty("attrname"); // 获取属性值字符串 String attrValue = prop.getProperty("attrvalue"); // 获取方法字符串 String method = prop.getProperty("methodname"); // 获取字节码对象 Class c = Class.forName(className); // 创建实例 Person p = (Person) c.newInstance(); // 获取属性名数组 String[] attrNames = attrName.split("/"); // 获取属性值数组 String[] attrValues = attrValue.split("/"); // 用setter来将属性值赋值给相应的属性--注意1setter方法名的拼接;注意2属性格式的转化 for (int i = 0; i < attrNames.length; i++) { // 获取类型 Class temp = c.getDeclaredField(attrNames[i]).getType(); // 获取setter方法 Method m = c.getMethod( "set" + Character.toString(attrNames[i].charAt(0)) .toUpperCase() + attrNames[i].substring(1), temp); // 判断类型,转换类型 if (temp.equals(String.class)) { m.invoke(p, attrValues[i]); } else if (temp == int.class || temp.equals(Integer.class)) { m.invoke(p, Integer.parseInt(attrValues[i])); } else if (temp == char.class || temp.equals(Character.class)) { m.invoke(p, attrValues[i].toCharArray()[0]); } else if (temp == Date.class) { m.invoke(p, new SimpleDateFormat().parse(attrValues[i])); } else if (double.class == temp || temp.equals(Double.class)) { m.invoke(p, Double.parseDouble(attrValues[i])); } } // 执行指定的方法 Method m = c.getMethod(method, null); m.invoke(p, null); } } }
-
config.properties文件
classname=com.peng.classdemo2.Doctor attrname=name/age/gender/date/salary attrvalue=p/23/\u7537/2017-11-13/65535 methodname=eat
-