1.课堂:
所有类都是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.初始化 :为类中的所有静态数据开辟空间,赋予初始值
2.代码:
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; } }
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(); } } }