反射
概念
将类的各个组成部分封装为其他对象,这就是反射机制。
java反射是可以让我们在运行时,通过类的class对象动态获取类的属性、方法等内部信息的机制
java代码在计算机中的经过三个阶段
- 第一个阶段:.java文件经过编译之后变成.class文件。也称源代码阶段
- 第二个阶段:类加载器加载.class文件到内存中。也称class类对象阶段
- 第三个阶段:创建对象。也称运行时阶段
反射实现借助的四个类
Class:类的对象
Constructor:类的构造方法
Field:类中的属性对象
Method:类中的方法对象
原理
java语言经过编译之后会生成一个.class对象,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。
好处
1、可以在程序的运行过程中操作对象
2、可以解耦,提高程序的可扩展性
获取Class对象的方式
- Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象(对应第一阶段,Source源代码阶段)
- 类名.class:通过类名的属性class获取(对应第二阶段,Class类对象阶段)
- 对象.getClass():getClass()方法在Object对象中定义着(对应第三阶段,Runtime运行时阶段)
- 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次。即无论通过哪一种方式获取的class对象都是同一个
Class对象的功能
获取功能
- 获取成员变量们
- Field[] getFields():获取所有public修饰的成员变量
- Field getField(Stringname):获取指定的public修饰的成员变量
- Field[] getDeclaredFields():获取所有的成员变量。不考虑修饰符
- Field getDeclaredField(String name):获取指定的成员变量
- 获取构造方法们
- Constructor<?>[] getConstructors():获取所有public修饰的构造方法
- Constructor getConstructor(类<?>… parameterTypes):获取指定的public修饰的构造方法
- Constructor<?>[] getDeclaredConstructors():获取所有的构造方法。不考虑修饰符
- Constructor getDeclaredConstructor(类<?>… parameterTypes):获取指定的构造方法
- 获取成员方法们
- Method[] getMethods():获取所有public修饰的成员方法
- Method getMethod(String name, 类<?>… parameterTypes):获取指定的public修饰的成员方法
- Method[] getDeclaredMethods():获取所有的成员方法。不考虑修饰符
- Method getDeclaredMethod(String name, 类<?>… parameterTypes):获取指定的成员方法
- 获取类名
- String getName()
Field对象的常用方法
- 设置值:void set(Object obj, Object value)
- 获取值:Object get(Object obj)
- 忽略访问权限修饰的安全检查:setAccessible(true)
Constructor对象的常用方法
- 创建对象:T newInstance(Object… initargs)
- 如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance方法
Method对象的常用方法
- 执行方法:Object invoke(Object obj, Object… args)
- 获取方法名称:String getName()
代码示例
Person类对象
package com.reflect;
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;
}
public void eat(){
System.out.println("吃东西。。。");
}
public void eat(String food){
System.out.println("吃东西。。。"+food);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
}
Class对象创建的三种方式
package com.reflect;
public class ReflectDemo01 {
/*
获取class对象的三种方式:
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(对应第一阶段,Source源代码阶段)
2. 类名.class:通过类名的属性class获取(对应第二阶段,Class类对象阶段)
3. 对象.getClass():getClass()方法在Object对象中定义着(对应第三阶段,Runtime运行时阶段)
*/
public static void main(String[] args) throws Exception {
//1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(对应第一阶段,Source源代码阶段)
Class cla1 = Class.forName("com.reflect.Person");
System.out.println(cla1);
//2. 类名.class:通过类名的属性class获取(对应第二阶段,Class类对象阶段)
Class cla2 = Person.class;
System.out.println(cla2);
//3. 对象.getClass():getClass()方法在Object对象中定义着(对应第三阶段,Runtime运行时阶段)
Person p = new Person("Chocolate",24);
Class cla3 = p.getClass();
System.out.println(cla3);
//结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次。即无论通过哪一种方式获取的class对象都是同一个
System.out.println(cla1==cla2);//true
System.out.println(cla1==cla3);//true
}
}
获取成员变量、成员方法、构造方法以及分别调用各自的方法
package com.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo02 {
public static void main(String[] args) throws Exception {
//获取成员变量
//demo01();
//获取构造方法
//demo02();
//获取成员方法
demo03();
}
private static void demo03() throws Exception {
/*
* Method[] getMethods():获取所有public修饰的成员方法
* Method getMethod(String name, 类<?>... parameterTypes):获取指定的public修饰的成员方法
* Method[] getDeclaredMethods():获取所有的成员方法。不考虑修饰符
* Method getDeclaredMethod(String name, 类<?>... parameterTypes):获取指定的成员方法
*/
Class cla = Class.forName("com.reflect.Person");
//Method[] getMethods():获取所有public修饰的成员方法
Method[] methods = cla.getMethods();
for (Method m:methods){
System.out.println(m);
}
System.out.println("==============================");
//Method getMethod(String name, 类<?>... parameterTypes):获取指定的public修饰的成员方法
Person p = new Person();
Method eat = cla.getMethod("eat");
Method eat1 = cla.getMethod("eat", String.class);
System.out.println(eat);
System.out.println(eat1);
//执行方法
eat.invoke(p);
eat1.invoke(p,"饭");
System.out.println("============================");
//获取方法名
System.out.println(eat.getName());
System.out.println("============================");
//获取类名
System.out.println(cla.getName());
}
private static void demo02() throws Exception {
/*
* Constructor<?>[] getConstructors():获取所有public修饰的构造方法
* Constructor<T> getConstructor(类<?>... parameterTypes):获取指定的public修饰的构造方法
* Constructor<?>[] getDeclaredConstructors():获取所有的构造方法。不考虑修饰符
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):获取指定的构造方法
*/
Class cla = Class.forName("com.reflect.Person");
Constructor[] constructors = cla.getConstructors();
for (Constructor c:constructors){
System.out.println(c);
}
System.out.println("==========================");
//获取指定的构造器
Constructor cons = cla.getConstructor(String.class,int.class);
System.out.println(cons);
System.out.println("============================");
//由构造器创建对象
//创建对象:T newInstance(Object... initargs)
Object obj = cons.newInstance("科比", 24);
System.out.println(obj);
System.out.println("==========================");
//如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance方法
Object obj2 = cla.newInstance();
System.out.println(obj2);
}
private static void demo01() throws Exception {
/*
* Field[] getFields():获取所有public修饰的成员变量
* Field getField(Stringname):获取指定的public修饰的成员变量
* Field[] getDeclaredFields():获取所有的成员变量。不考虑修饰符
* Field getDeclaredField(String name):获取指定的成员变量
*/
Class cla = Class.forName("com.reflect.Person");
//getFields():获取所有public修饰的成员变量
Field[] f1 = cla.getFields();
for (Field f:f1){
System.out.println(f);
}
System.out.println("===========================");
//getDeclaredFields():获取所有的成员变量。不考虑修饰符
Field[] f2 = cla.getDeclaredFields();
for (Field f:f2){
System.out.println(f);
}
System.out.println("===============================");
//getField(Stringname):获取指定的public修饰的成员变量
//获取某个成员变量,并对其进行赋值
/*
Field:成员变量
* 设置值:void set(Object obj, Object value)
* 获取值:Object get(Object obj)
* 忽略访问权限修饰的安全检查:setAccessible(true)
*/
Person p = new Person();
Field a = cla.getField("a");
a.set(p,"我是a");
Object o = a.get(p);
System.out.println(o);
System.out.println(p);
}
}