首先,认识一下Java代码 在计算机中经历的阶段 (三个阶段)
反射:将类的各个组成部分封装为其他对象
好处:
- 在程序运行中,拿到这些对象
- 可以解耦,提高程序的可扩展性
获取Class对象的方式:
1. 通过类型获得
// 语法:类名.class
// 应用场景:确定类型等
Class beansClass = 类名.class;
2 通过实例对象获得
// 语法:变量.getClass()
// 应用场景:在方法内部通过参数获得类型等
// 先给你 new一个对象
Beans beans = new Beans();
Class<? extends Beans> aClass = beans.getClass();
3 通过字符串获得
// 语法:Class.forName("全限定类名")
// 应用场景:通过配置获得字符串等
Class<?> aClass1 = Class.forName("Demo01.Beans");
同一个字节码文件(*.Class)再一次程序运行过程中,只会内加载一次 无论哪一种方式获取Class对象都是同一个
Class对象功能:
获取功能:
-
获取成员变量
Field[] getFields()
Field getField(String name)
Field[] getDeclaredFields( )
Field getDeclaredField(String name)
-
获取构造方法
Constructor<?> getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
-
获取成员方法
Method getMethods()
Method getMethod(String name, 类<?>... parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
-
获取类名
String getName()
功能演示:(获取成员变量)
Person类:
public class Person {
public int id;
private String name;
private int age;
public Person() {
}
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
}
Field[] getFields() 获取所有的成员变量
public class FieldDemo01 {
public static void main(String[] args) throws Exception {
//通过字符串的方式获取
Class<?> aClass = Class.forName("Demo02.Person");
//获取所有的成员变量
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
然而 为什么我的Person类里面有三个成员变量 可以循环只出了一个
回头 看一下我们的Person类
除了ID 其他的成员变量都是Private修饰的 那现在我们知道了Field[] getFields()
获取所有public修饰的成员变量
所以,来看 Field getField(String name)
就可以分析出 String name
获取指定名字的成员变量 ( getFields()
获取所有public修饰的成员变量) 那么 Field getField(String name)
就是 获取指定名字的public修饰的成员变量。
那么我们获取成员变量可以来干什么?
-
赋值
set(Object obj, Object value)
将指定对象参数上的此 Field对象表示的字段设置为指定的新值。 -
获取值
get(Object obj)
返回该所表示的字段的值 Field ,指定的对象上。 -
setAccessible(true)
忽略访问权限修饰符的安全检查 (后面的功能中我们都能用的到)
代码演示:(格式)
public class FieldDemo01 {
public static void main(String[] args) throws Exception {
//通过字符串的方式获取
Class<?> aClass = Class.forName("Demo02.Person");
//获取指定名字的public修饰的成员变量
Field id = aClass.getField("id");
//设置成员变量id的值
Person person = new Person();
id.set(person,8848);
//获取成员变量id的值
Object o = id.get(person);
System.out.println("id是"+o);
}
}
上面的两个功能我们学会了那么 下面的两个功能就更加简单:
Field[] getDeclaredFields( )
获取所有成员变量(不考虑修饰符)
public class FieldgetConstructorDemo01 {
public static void main(String[] args) throws Exception {
//通过字符串的方式获取
Class<?> aClass = Class.forName("Demo02.Person");
//不考虑 修饰符
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
}
}
那么Field getDeclaredField(String name)
不就是指定名字的成员变量
那我们来看一下他的 赋值取值
public class FieldgetConstructorDemo01 {
public static void main(String[] args) throws Exception {
//通过字符串的方式获取
Class<?> aClass = Class.forName("Demo02.Person");
//根据变量名称获取
Field name = aClass.getDeclaredField("name");
Person person = new Person();
//忽略访问权限修饰符的安全检查 (暴力反射 FBI! open the door)
name.setAccessible(true);
//赋值
name.set(person,"Jo级生物");
//获取
Object o = name.get(person);
System.out.println("我是 :"+o);
}
}
如果 没有setAccessible(true )私有的不能被访问 所以 会报一个 非法的访问异常
功能演示:(获取构造方法)
public class Demo01 {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("ConstructorDemo03.Person");
//构造方法 类名和方法名是相同的
//区分 : 参数不一样 而这里要求的参数类型是不同参数的Class对象
Constructor<?> constructor = aClass.getConstructor(int.class,
String.class,
int.class);
System.out.println(constructor);
}
}
Constructor:构造方法
创建对象:T newInstance(Object... initargs)
用法:
Constructor<?> constructor = aClass.getConstructor(int.class,
String.class,
int.class);
//创建对象
Object o = constructor.newInstance(1, "张三", 20);
System.out.println(o);
创建一个空参就能好说了 :
定义就是一个 可变参的形式
Constructor<?> constructor = aClass.getConstructor();
//创建对象
Object o = constructor.newInstance();
System.out.println(o);
也可以使用Class对象中的newInstance
的方法
Class<?> aClass = Class.forName("ConstructorDemo03.Person");
Object o1 = aClass.newInstance();
System.out.println(o1);
如果说 我们的构造方法是私有的
那么就可以使用 Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
其实用法与上面的(获取成员变量)基本相同:
public class Demo02 {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("ConstructorDemo03.Person");
//暴力反射
Constructor<?> dct = aClass.getDeclaredConstructor(int.class,
String.class,
int.class);
dct.setAccessible(true);
Object o = dct.newInstance(1, "张三", 20);
System.out.println(o);
}
}
功能演示: (获取成员方法)
在Person 加入了三个方法:
public class Person {
public int id;
private String name;
private int age;
public Person() {
}
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public void eat(){
System.out.println("我在喝刘一碗羊汤");
}
public void eat(int count){
System.out.println("我在刘一碗喝了"+count+"碗羊汤");
}
private void swim(){
System.out.println("我在游泳");
}
}
public class Demo01 {
/*
* 执行方法
* */
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("MethodDemo04.Person");
//获得指定名称的方法
Method method = aClass.getMethod("eat");
Person person = new Person();
//执行方法
method.invoke(person);
//如果方法中传入了参数
Method method1 = aClass.getMethod("eat",int.class);
Person person1 = new Person();
method1.invoke(person1,60);
//获取所有的public修饰的方法
Method[] methods = aClass.getMethods();
for (Method method2 : methods) {
System.out.println(method2);
}
//拿到私有的方法
Method swim = aClass.getDeclaredMethod("swim");
Person person2 = new Person();
swim.setAccessible(true);
swim.invoke(person2);
}
}
因为要获取所有的public修饰的方法 方法有很多所以就没有让他执行