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();
        }
    }

}
访问学生类私有属性和方法

 

posted on 2017-09-25 12:46  我可不是隔壁的老王  阅读(136)  评论(0编辑  收藏  举报