首先先要明确:
所有类都是Object的子类!
所有类的对象都是Class的实例!
反射机制:
在程序运行期间,对于任意一个类,都能知道这个类中所有的属性和方法! (私有的也可以)
对于任意一个对象,我们都能够访问这个对象的所有的属性和方法!
这种动态获取类的信息和动态的调用对象的方法或者属性的功能,我们称之为java中的反射!
Animal有两个实现类 一个是Dog 一个是Cat
Animal animal=new Dog(); //在代码编译期间 我们就确定了animal的值
Animal animal=??;
//01.代码编译期间 我们不确定了animal的值 静态
//02.代码运行期间 我们才能确定了animal的值 动态
java虚拟机提供了我们java程序的运行环境!
其中java虚拟机最重要的任务: 就是管理类和对象的生命周期!
类的生命周期: 从我们类开始加载 连接 初始化 这三步开始的!
加载 连接 初始化 这三步 都执行完毕,才算类的初始化完成!
01.加载 :查询并加载我们类的2进制文件(.class文件)
02.连接:包含3个步骤
001.验证:确保需要加载类的正确性
002.准备:为类中的所有静态数据开辟空间,并赋予默认值
003.解析:把类中的 final ReflectDemo this$0(符号引用) 转换成直接引用
03.初始化 :为类中的所有静态数据开辟空间,赋予初始值
下面先创建一Student类
package cn.bdqn.bean;
import java.util.Date;
/**
* 学生对象的实体类
*/
public class Student {
public int age; // 学生年龄
protected String name;// 学生姓名
private Date birthday = new Date();// 学生生日
char sex; // 学生性别
static {
System.out.println("这是Student类中的静态代码块");
}
{
System.out.println("这是Student类中的普通代码块");
}
public Student() {
System.out.println("这是Student类中的无参构造");
}
/**
* 私有的方法
*/
private double getSum(double number) {
return number + 10;
}
public Student(int age, String name, Date birthday, char sex) {
super();
this.age = age;
this.name = name;
this.birthday = birthday;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
创建测试类
package cn.bdqn.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.junit.Test;
import cn.bdqn.bean.Student;
public class ReflectDemo {
/**
* 全类名(完整限定名)cn.bdqn.test.ReflectDemo
* 包名+类名
*
* 完整路径 /Reflect/src/cn/bdqn/test/ReflectDemo.java
*
*
* 完整限定名 是我们反射的基础!
* 问题:
* 01.一个包中可能出现两个相同的类吗?? 不能
* 02.完整限定名就是来确保我们类的唯一性
* 03.程序怎么获取完整限定名呢?
*/
@Test
public void test01() {
// 三种方式获取我们的完整限定名
try {
System.out.println("第一种方式 :Class.forName()===>"
+ Class.forName("cn.bdqn.bean.Student").getName());
System.out.println("第二种方式 :类名.Class===>" + Student.class.getName());
System.out.println("第三种方式 :对象名.getClass()===>"
+ new Student().getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取类的包名 类名 访问修饰符
*/
@Test
public void test02() {
try {
Class c = Class.forName("cn.bdqn.bean.Student");
System.out.println("所在的包:" + c.getPackage().getName());
System.out.println("全类名:" + c.getName());
System.out.println("简写的类名:" + c.getSimpleName());
// 获取类的修饰符
int num = c.getModifiers();
System.out.println(num);
// 通过Modifier的toString()就可以把int类型转换成对应的修饰符
System.out.println(Modifier.toString(num));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取类中所有的属性相关内容
*
* 所有的属性,方法,构造方法 都有修饰符!
* 不同的访问修饰符 访问权限不一样!
* Class类中给我们提供了两个方案来获取属性,方法,构造方法!
01.获取所有的
getDeclared系列
02.获取public修饰的
get系列
*/
@Test
public void test03() {
try {
Class c = Class.forName("cn.bdqn.bean.Student");
// Field[] fields = c.getFields(); 只是获取public
Field[] fields = c.getDeclaredFields(); // 获取所有
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
// 获取所有属性的访问修饰符 default的int值是0 没有对应的字符串类型
for (int i = 0; i < fields.length; i++) {
System.out.println(Modifier.toString(fields[i].getModifiers()));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 创建对象
*/
@Test
public void test04() {
// Student stu = new Student(); 耦合
try {
Class c = Class.forName("cn.bdqn.bean.Student");
Student stu = (Student) c.newInstance(); // 相对耦合
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 访问对象的私有属性
*/
@Test
public void test05() {
try {
Class c = Class.forName("cn.bdqn.bean.Student");
Student stu = (Student) c.newInstance();
Field field = c.getDeclaredField("birthday");
// 打开访问私有属性的开关
field.setAccessible(true);
System.out.println(field.get(stu));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 访问对象的私有方法
*/
@Test
public void test06() {
try {
Class c = Class.forName("cn.bdqn.bean.Student");
Student stu = (Student) c.newInstance();
Method method = c.getDeclaredMethod("getSum", double.class);
method.setAccessible(true);
// 执行方法
double sum = (Double) method.invoke(stu, 50.0);
System.out.println(sum);
} catch (Exception e) {
e.printStackTrace();
}
}
}