1 反射
什么是反射
java反射 是指在运行状态中 对于任意一个类 我们都可以知到这个类的所有方法和属性 也可以调用其所有的方法和属性 这种动态获取的方式 我们称为 反射
什么是class对象
我们通过使用
反射
就是通过Class类来实现的Class
类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
反射的使用
获取class对象的三种方式
基本类
/**
*
* @author : look-word
* @date : 2022-04-05 20:49
**/
public class Student {
private String username;
private String gender;
public String getInfo() {
this.setUsername("张三");
this.setGender("男");
return this.username+"="+this.gender;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
测试代码如下
/**
* @author : look-word
* @date : 2022-04-05 20:54
**/
public class Test {
public static void main(String[] args) {
/*
1 创建对象 获取其class对象
*/
Student student = new Student();
Class extends Student> aClass = student.getClass();
System.out.println(aClass.getSimpleName());
/*
2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
*/
Class extends Student> bClass=Student.class;
System.out.println(aClass == bClass?"两者是同一对象":"两者不是同一对象");
/*
3 通过Class类的forName方法获取
*/
try {
// Class.forName(类的相对路径)
Class> cClass = Class.forName("bean.Student");
System.out.println(bClass == cClass?"两者是同一对象":"两者不是同一对象");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果如下
证明
在运行期间 一个类只有一个class对象的产生
常用的是
第三次
清晰 明了 因为 在一个项目中 可能会产生 相同名字的类解决疑惑 为什么要是用 第三种
第一种对象都有了还要反射干什么。
第二种需要导入类的包,依赖太强,不导包就抛编译错误。
第三种
,一个字符串可以传入也可写在配置文件中等多种方法。
获取Class类中的所有构造方法
基本类
public class Student {
//---------------构造方法-------------------
//(默认的构造方法)
Student(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+" 年龄:"+ age);//这的执行效率有问题,以后解决。
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
}
测试代码
/**
* 测试构造方法
* @author : look-word
* @date : 2022-04-05 21:18
**/
public class TestConstructor {
/**
* 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
*
* 1.获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
*
* 调用构造方法:
* Constructor-->newInstance(Object... initargs)
*/
public static void main(String[] args) throws Exception {
Class> student = Class.forName("bean.Student");
/*
1 获取所有共有的构造方法
*/
System.out.println("\n1 获取所有共有的构造方法");
Constructor>[] constructors = student.getConstructors();
for (Constructor> constructor : constructors) {
System.out.println(constructor);
}
/*
2 获取共有的无参构造方法 可以写 null 或者 不填
*/
System.out.println("\n2 获取共有的无参构造方法 可以写 null 或者 不填");
Constructor> constructor2 = student.getConstructor();
constructor2.newInstance();
/*
3 获取 给定参数共有的构造方法 public bean.Student(java.lang.String,int)
*/
System.out.println("\n 3 获取 给定参数共有的构造方法 public bean.Student(java.lang.String,int)");
Constructor> constructor3 = student.getConstructor(String.class, int.class);
constructor3.newInstance("张三",19);
/*
4 获取 私有给定参数的构造方法 私有 不给定参数 不传参数即可
*/
Constructor> constructor4 = student.getDeclaredConstructor(int.class);
/*
获取私有的属性 或者构造方法是 需要 设置无障碍 俗称 暴力访问
不设置 会出异常 java.lang.IllegalAccessException
*/
constructor4.setAccessible(true);
constructor4.newInstance(19);
}
}
执行结果
注意
获取私有属性的时候 一定要设置无障碍
setAccessible(true);
不设置 会出异常 java.lang.IllegalAccessException
newInstance(Object... initargs) 创建一个新实例
使用此Constructor
对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。每次是用
newInstance
创建的对象 都是不同的对象 代表不同的实例
操作成员变量
基本类
public class Student {
public Student(){
}
//**********字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
测试代码
/**
* @author : look-word
* @date : 2022-04-05 21:55
**/
public class TestField {
/*
* 获取成员变量并调用:
*
* 1.批量的
* 1).Field[] getFields():获取所有的"公有字段"
* 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
* 2.获取单个的:
* 1).public Field getField(String fieldName):获取某个"公有的"字段;
* 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
*
* 设置字段的值:
* Field --> public void set(Object obj,Object value):
* 参数说明:
* 1.obj:要设置的字段所在的对象;
* 2.value:要为字段设置的值;
*/
public static void main(String[] args) throws Exception{
Class> aClass = Class.forName("bean.Student");
Student student = new Student();
/*
获取所有的共有字段
*/
System.out.println("-------------------获取所有的共有字段--------------------");
Field[] fields = aClass.getFields();
for (Field field : fields) {
/*
filed => public java.lang.String bean.Student.username
filed => 成员变量
*/
/*
我理解为 给某个对象的 成员变量 赋值
当前的filed 为 username 因为这里只能获取为 共有属性的成员变量
* field.set(student,"zhangsan");
*/
field.set(student,"zhangsan");
System.out.println(student);
/*
field.get(student);
获取某student中的 field 的 内容
*/
Object o = field.get(student);
System.out.println(o);
/*
* 打印filed的内容 => public java.lang.String bean.Student.username
*/
System.out.println(field);
}
System.out.println("-------------------给私有字段赋值--------------------");
Field phone = aClass.getDeclaredField("phone");
phone.setAccessible(true);// 设置无障碍
phone.set(student,"110");// 赋值给student对象
System.out.println("-------------------获取私有字段--------------------");
Field phone1 = aClass.getDeclaredField("phone");
phone1.setAccessible(true);// 设置无障碍
System.out.println(phone1.get(student));//取出student对象中的phone属性的值
}
}
注意
在操作私有属性的时候 不管是获取还是设置值 都需要设置无障碍
setAccessible(true);// 设置无障碍