文章目录
反射
1. 什么是反射
反射是一种获取类信息的能力
什么是类信息:方法、变量(全局变量)、接口、父类构造器…
2.为什么会有发射
需要获取类信息
3. 发射是如何工作的
程序运行的三个阶段,想要反射获取类信息,必须先进入第二阶段:类对象阶段。
获取类对象的三种方案:
①在磁盘阶段:全类名就是——包名(地址)加类名(名称)
②类对象阶段:
③运行时阶段:
想要获取类信息,就必须进入类对象阶段
三种方案:
第一种:Class.forName(“全类名”)
package 反射;
public class Student {
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
}
package 反射;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
Class class2=Student.class;
Student student=new Student();
Class class3=student.getClass();
System.out.println(class1==class2);
System.out.println(class2==class3);
//最后会发现输出结果都是true,
//==比较对象的地址是否相同,
//这说明,这三个指向的地址一样
}
}
地址都是方法区的这一块
同一个对象,会在方法区里面留下同一个类对象
4. 如何获取变量信息
package 反射;
public class Student {
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
}
package 反射;
import java.lang.reflect.Field;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//类的信息全部存储在类信息中
//获取全部的全局变量信息,并进行打印---getDeclaredFields()
Field[] files=class1.getDeclaredFields();
System.out.println(Arrays.toString(files));
System.out.println("-------------------------------");
//获取public 修饰的全部变量信息,并进行打印---getFields()
Field[] files1=class1.getFields();
System.out.println(Arrays.toString(files1));
System.out.println("-------------------------------");
//获取指定的变量信息,并进行打印---getDeclaredField
Field nameField =class1.getDeclaredField("name");
System.out.println(nameField);
Field heightField=class1.getDeclaredField("height");
System.out.println(heightField);
Field ageField = class1.getDeclaredField("age");
System.out.println(ageField);
System.out.println("-------------//------------------");
//获取指定的,并且是public修饰的变量信息,并进行打印---getField
// Field nameField1 =class1.getField("name");
// System.out.println(nameField);
//报错,不能输出private修饰符修饰的
// Field heightField1=class1.getField("height");
// System.out.println(heightField);
//报错,不能输出protected修饰符修饰的
Field ageField1 = class1.getField("age");
System.out.println(ageField1);
}
}
结果
D:\develop\Java\jdk1.8.0_261\bin\java.exe "-javaagent:D:\idea\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=58405:D:\idea\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\develop\Java\jdk1.8.0_261\jre\lib\charsets.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\deploy.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\access-bridge-64.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\cldrdata.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\dnsns.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\jaccess.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\jfxrt.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\localedata.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\nashorn.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\sunec.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\sunjce_provider.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\sunmscapi.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\sunpkcs11.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\ext\zipfs.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\javaws.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\jce.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\jfr.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\jfxswt.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\jsse.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\management-agent.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\plugin.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\resources.jar;D:\develop\Java\jdk1.8.0_261\jre\lib\rt.jar;D:\summerfirst\out\production\summerfirst 反射.Test
[private java.lang.String 反射.Student.name, public java.lang.Integer 反射.Student.age, java.lang.Character 反射.Student.sex, protected java.lang.Double 反射.Student.height]
-------------------------------
[public java.lang.Integer 反射.Student.age]
-------------------------------
private java.lang.String 反射.Student.name
protected java.lang.Double 反射.Student.height
public java.lang.Integer 反射.Student.age
-------------//------------------
public java.lang.Integer 反射.Student.age
进程已结束,退出代码为 0
5. 如何获取方法的信息
package 反射;
public class Student {
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
public String color="蓝色";
public void run(){}
private int getAge(int age){
return age;
}
void aaa(String name,Integer height){
}
protected void haha(String name,int age){}
}
package 反射;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//类的信息全部存储在类信息中
//获取方法的信息
//获取所有方法的信息
Method[] declaredMethods=class1.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));
//获取public修饰的所有的方法的信息(还有来自父类object里面的)
Method[] methods=class1.getMethods();
System.out.println(Arrays.toString(methods));
//获取指定的方法
Method getAge = class1.getDeclaredMethod("getAge", int.class);//要把参数写上
Method aaa = class1.getDeclaredMethod("aaa", String.class, Integer.class);
Method run = class1.getDeclaredMethod("run");
Method hhh = class1.getDeclaredMethod("haha" ,String.class,int.class);
System.out.println(getAge);
System.out.println(aaa);
System.out.println(run);
System.out.println(hhh);
// getDeclaredMethod获取指定的,且是public的方法
//反射是获取类信息的能力
}
}
结果
6. 如何获取构造器的信息
package 反射;
public class Student {
//变量
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
public String color="蓝色";
//方法
public void run(){}
private int getAge(int age){
return age;
}
void aaa(String name,Integer height){
}
protected void haha(String name,int age){}
//构造器
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
//一般不设置私有类型的构造器
public Student(String name, Integer age, Character sex, Double height, String color) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.color = color;
}
}
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//类的信息全部存储在类信息中
//获取public修饰的,全部
Constructor[] constructors=class1.getConstructors();
System.out.println(Arrays.toString(constructors));
//获取全部
Constructor[] declaredConstructors = class1.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
//获取指定的
Constructor declaredConstructor = class1.getDeclaredConstructor(String.class,Integer.class);//传参数,不用写方法名
System.out.println(declaredConstructor);
Constructor declaredConstructor2 = class1.getDeclaredConstructor();
Constructor declaredConstructor3 = class1.getDeclaredConstructor(String.class, Integer.class, Character.class, Double.class, String.class);
System.out.println(declaredConstructor2);
System.out.println(declaredConstructor3);
}
}
结果
6. 获取构造器的类信息之后可以做什么
获取构造器之后:创建对象
package 反射;
public class Student {
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
public String color="蓝色";
public void run(){}
private int getAge(int age){
return age;
}
void aaa(String name,Integer height){
}
protected void haha(String name,int age){}
private Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
//一般不设置私有类型的构造器
public Student(String name, Integer age, Character sex, Double height, String color) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.color = color;
}
}
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//获取构造器的类信息
Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, Integer.class);
//创建对象
Student student1=(Student)declaredConstructor.newInstance("aaa",18);//传值,因为构造器需要传值
//这里需要强转,因为默认是object类型
//无参构造器
Constructor declaredConstructor1 = class1.getDeclaredConstructor();
//private修饰的数据,想要使用就必须暴力反射。
declaredConstructor1.setAccessible(true);
Student student2=(Student) declaredConstructor1.newInstance();
}
}
7. 获取方法,调用方法
package 反射;
public class Student {
private String name="张三";
public Integer age=18;
Character sex='男';
protected Double height =185.5;
public String color="蓝色";
public void run(){
System.out.println("这是run()");
}
private int getAge(int age){
System.out.println("age()");
return age;
}
void aaa(String name,Integer height){
System.out.println("aaa()");
}
protected void haha(String name,int age){
System.out.println("haha()");
}
private Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
//一般不设置私有类型的构造器
public Student(String name, Integer age, Character sex, Double height, String color) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.color = color;
}
}
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//获取构造器的类信息
Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, Integer.class);
//创建对象
Student student1=(Student)declaredConstructor.newInstance("aaa",18);//传值,因为构造器需要传值
//这里需要强转,因为默认是object类型
Method run = class1.getDeclaredMethod("run");//获取方法
Object invoke = run.invoke(student1);//使用方法——invoke()里面有两个东西,第一个是对象,第二个是参数(run方法没有参数)
//为什么里面要传对象——》所有方法要是想要运行,必须先在内存里面开辟空间
Method getAge = class1.getDeclaredMethod("getAge", int.class);
getAge.setAccessible(true);//暴力反射(因为getAge是private修饰的)
getAge.invoke(student1,18);//传对象,传参数
Method aaa=class1.getDeclaredMethod("aaa",String.class,Integer.class);
aaa.invoke(student1,"admin",199);
Method haha=class1.getDeclaredMethod("haha",String.class,int.class);
haha.invoke(student1,"admin",99);
}
}
7. 获取变量
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Class class1=Class.forName("反射.Student");
//获取构造器的类信息
Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, Integer.class);
//创建对象
Student student1=(Student)declaredConstructor.newInstance("aaa",18);//传值,因为构造器需要传值
//这里需要强转,因为默认是object类型
Field name=class1.getDeclaredField("name");
name.setAccessible(true);//暴力反射
// name.set(student1,"admin");
System.out.println(name.get(student1));
Field age=class1.getDeclaredField("age");
age.set(student1,88);//赋值取值操作
System.out.println(age.get(student1));
Field sex=class1.getDeclaredField("sex");
sex.set(student1,'女');
System.out.println(sex.get(student1));
Field height=class1.getDeclaredField("height");
height.set(student1,189.89);
System.out.println(height.get(student1));
}
}
8.练习题
package 反射;
public class Student {
private String name;
private int age;
private String address;
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
//①获取该类的构造方法来构造对象,
//②获取该类的名称和该类中的每一个变量的名称和方法的名称,并执行相关方法
//③给每一个变量赋值,并获取值
//④执行每一个构造方法meiyou
//⑤执行相应的方法
public static void main(String[] args) throws Exception{
//①获取该类的构造方法来构造对象,
//,类的信息全部存储在类信息中 获取Student类的Class对象
Class class1=Class.forName("反射.Student");
//获取全部构造器,获取构造器的类信息
Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, int.class, String.class);
//创建对象, 传值,因为构造器需要传值, 这里需要强转,因为默认是object类型
Student student1=(Student)declaredConstructor.newInstance("张三", 20, "北京");
// ②获取该类的名称和该类中的每一个变量的名称和方法的名称
System.out.println("类名称: " + class1.getSimpleName());
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
System.out.println("字段名称: " + field.getName());
}
Method[] methods = class1.getMethods();
for (Method method : methods) {
System.out.println("方法名称: " + method.getName());
}
//③给每一个变量赋值,并获取值
//代码通过getDeclaredField获取了name字段,并通过set方法给它赋了一个新值。
Field name=class1.getDeclaredField("name");
//暴力反射 如果字段是私有的,需要设置为可访问
name.setAccessible(true);
name.set(student1,"admin");
System.out.println(name.get(student1));
//代码通过getDeclaredField获取了age字段,并通过set方法给它赋了一个新值。
Field age=class1.getDeclaredField("age");
//暴力反射 如果字段是私有的,需要设置为可访问
age.setAccessible(true);
age.set(student1,18);
System.out.println(age.get(student1));
//代码通过getDeclaredField获取了name字段,并通过set方法给它赋了一个新值。
Field address=class1.getDeclaredField("address");
//暴力反射 如果字段是私有的,需要设置为可访问
address.setAccessible(true);
address.set(student1,"北京");
System.out.println(address.get(student1));
//⑤执行相应的方法
//获取方法
Method getName = class1.getDeclaredMethod("getName");
//使用方法 ——》invoke()里面有两个东西,第一个是对象,第二个是参数(run方法没有参数)
//为什么里面要传对象——》所有方法要是想要运行,必须先在内存里面开辟空间
Object studentName = getName.invoke(student1);
System.out.println("学生姓名: " + studentName);
}
}