框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
概述:
通俗的说,所谓的反射,就是"在程序的运行过程中", 动态的获取到一个类的各个组成部分(成员变量, 成员方法, 构造方法...), 这就是反射机制.
可以将反射理解为对类的一种解刨, 可以解刨到类的心, 肝, 脾..等
解刨的一个类, 实际上就是解刨这个类的字节码文件.
好处:
1. 可以在程序运行过程中,操作这些对象。
2. 可以解耦,提高程序的可扩展性。
Java代码的三个阶段
获取Class对象的方式:
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
* 多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着。
* 多用于对象的获取字节码的方式
* 结论:
同一个类的字节码文件(*.class)在一次程序运行过程中,只会被加载一次.
不论通过哪一种方式获取的Class对象都是同一个。
代码演示:
public static void main(String[] args) throws Exception {
//1.Class.forName("全类名")。将字节码文件加载进内存,返回Class对象
Class cls1 = Class.forName("com.itheima_01.Person");
System.out.println(cls1); //class com.itheima_01.Person
//2.类名.class:通过类名的属性class获取
Class cls2 = Person.class;
System.out.println(cls2); //class com.itheima_01.Person
//3.对象.getClass:getClass()方法在Object类中定义
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3); //class com.itheima_01.Person
//使用==,判断是否是同一个对象
System.out.println(cls1==cls2); //true
System.out.println(cls1==cls3); //true
}
Class对象功能:
* 获取功能:
1. 获取成员变量们
* Field[] getFields() : //获取所有public修饰的成员变量
* Field getField(String name) //获取指定名称的public修饰的成员变量
* Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name) //获取指定名称的成员变量,不考虑修饰符
2. 获取构造方法们
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(Class<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
3. 获取成员方法们:
* Method[] getMethods()
* Method getMethod(String name, Class<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, Class<?>... parameterTypes)
4. 获取全类名
* String getName()
* Field:成员变量
* 操作:
1. 设置值
* void set(Object obj, Object value)
2. 获取值
* get(Object obj)
3. 忽略访问权限修饰符的安全检查
* Constructor:构造方法
* 创建对象:
* T newInstance(Object... initargs)
* 如果使用空参数构造方法创建对象,操作可以简化:
Class对象的newInstance方法
* setAccessible(true):暴力反射
* Method:方法对象
* 执行方法:
* Object invoke(Object obj, Object... args)
* 获取方法名称:
* String getName:获取方法名
代码演示:
1.获取成员变量们
public static void main(String[] args) throws Exception {
/*
1. 获取成员变量们
* Field[] getFields() : //获取所有public修饰的成员变量
* Field getField(String name) //获取指定名称的public修饰的成员变量
* Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name) //获取指定名称的成员变量,不考虑修饰符
*/
//获取Person的class对象
Class personClass = Person.class;
//Field[] getFields() : //获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
//遍历fields数组
for (Field field : fields) {
System.out.println(field);
}
//Field getField(String name) //获取指定名称的public修饰的成员变量
Field a = personClass.getField("a");
System.out.println(a);
System.out.println("----------");
//获取成员变量a的值
Person p = new Person();
Object value1 = a.get(p);
System.out.println(value1);
//设置成员变量a的值
a.set(p, "张三");
System.out.println(p);
System.out.println("----------");
//Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//Field getDeclaredField(String name) //获取指定名称的成员变量,不考虑修饰符
Field d = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true); //暴力反射
//获取d的值
Object value2 = d.get(p);
System.out.println(value2);
}
2. 获取构造方法们
public static void main(String[] args) throws Exception {
/*
2. 获取构造方法们
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(Class<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
*/
//获取Person的class对象
Class personClass = Person.class;
//Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor); //public cn.itcast.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<?>[] getConstructors()
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1); //public cn.itcast.domain.Person()
//创建空参对象
Object person1 = constructor1.newInstance();
System.out.println(person1); //Person{name='null', age=0, a='null', b='null', c='null', d='null'}
Object person2 = personClass.newInstance();
System.out.println(person2); //Person{name='null', age=0, a='null', b='null', c='null', d='null'}
}
3. 获取成员方法们
public static void main(String[] args) throws Exception {
/*
3. 获取成员方法们:
* Method[] getMethods()
* Method getMethod(String name, Class<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, Class<?>... parameterTypes)
*/
//获取Person的class对象
Class personClass = Person.class;
//Method getMethod(String name, Class<?>... parameterTypes) 获取指定方法名称
Method eat_Method1 = personClass.getMethod("eat");
System.out.println(eat_Method1);
Person p = new Person();
//执行方法
eat_Method1.invoke(p);
Method eat_Method2 = personClass.getMethod("eat",String.class);
eat_Method2.invoke(p,"饭");
System.out.println("-----------");
//Method[] getMethods() 获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
String name = method.getName();
System.out.println(name);
}
System.out.println("------------");
//4. 获取全类名 String getName()
String personName = personClass.getName();
System.out.println(personName); //com.itheima_01.Person
}
案例:
* 需求:
写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
* 实现条件:
1. 配置文件
2. 反射
* 实现步骤:
1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2. 在程序中加载读取配置文件
3. 使用反射技术来加载类文件进内存
4. 创建对象
5. 执行方法
代码演示:
public static void main(String[] args) throws Exception {
//创建类的加载器
//InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream("pro.properties");
InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream("pro.properties");
//创建Properties对象
Properties pro = new Properties();
pro.load(is);
//获取配置文件中的信息
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//获取类的路径
Class cls = Class.forName(className);
//获取构造方法
Constructor constructor = cls.getConstructor(String.class,int.class);
//创建有参对象
Object o1 = constructor.newInstance("张三",23);
System.out.println(o1);
//创建无参对象
Object o = cls.newInstance();
System.out.println(o);
//获取方法
Method method = cls.getMethod("eat",String.class);
Method method1 = cls.getMethod("study");
//调用方法
method.invoke(o1,"馒头");
method1.invoke(o1);
}
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;
}
// getter/setter 方法
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;
}
//重写toString方法
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
//成员方法
public void eat() {
System.out.println("eat");
}
public void eat(String food) {
System.out.println("eat" + food);
}
public void sleep(){
System.out.println("好好休息");
}
pro.properties 配置文件
className=com.itheima_01.Student
methodName=study