zoukankan      html  css  js  c++  java
  • Java学习笔记(5)反射

    反射是框架设计的灵魂

    (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

    一、反射的概述

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

    以上的总结就是什么是反射

    反射就是把java类中的各种成分映射成一个个的Java对象

    例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

         (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)

    如图是类的正常加载过程:反射的原理在与class对象。

    熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

    二、通过反射获取Class类的实例三种方法

    1.创建Person类,定义Move Study两个接口,定义Student类继承了Person类来实现Move Study两个接口

    Peron类

    public class Person {
        public String name;
        int age;
    }

    Student类

    package Java基础.反射;
    
    public class Student extends Person implements Move,Study{
    
        public Student(){
            System.out.println("调用的是public Student()");
        }
    
        public Student(String school){
            this.school = school;
            System.out.println("调用的是public Student(String school)");
        }
    
        private Student(String name,int age){
            this.name = name;
            this.age = age;
            System.out.println("调用的是private Student(String name,int age)");
        }
    
        public String school;
        private String privateField;
        public void showInfo(){
            System.out.println("学校:"+this.school);
        }
    
        private void test(String name){
            System.out.println("这是私有方法test(String name)");
        }
    
        public String getSchool(){
            return this.school;
        }
    
        public void setInfo(int age){
            this.age = age;
            System.out.println("这是调用重载方法 setInfo(int age)");
        }
    
        public void setInfo(String name,String school){
            this.name = name;
            this.school = school;
            System.out.println("这是setInfo(String name,String school)方法");
        }
    
    
        @Override
        public void moveType() {
            System.out.println("坐地铁去上班");
        }
    
        @Override
        public void studyInfo() {
            System.out.println("学习java反射");
        }
    }

    Move 接口

    package Java基础.反射;
    
    public interface Move {
        void moveType();
    }

    Study接口

    package Java基础.反射;
    
    public interface Study {
        void studyInfo();
    }

    Test 测试类:获取Class类的实例3种方法

    package Java基础.反射;
    
    public class Test {
        public static void main(String[] args) {
            Person p = new Person();
            Class clazz = p.getClass();// clazz对象中包含对象p所属的Person类所有的信息
    
            //获取Class类的实例3种方法
            Class c0 = Person.class;// 通过类名.class创建指定类的实例
            Class c1 = p.getClass();// 通过一个类的实例对象的getClass()方法
            try {
                // 通过Class的静态方法forName(String className)来获取一个class实例
                // forName(String className) 参数为你要获取的class实例的类的全路径(包名.类名)
                Class c2 = Class.forName("Java基础.反射.Person");// 此种方法最常用
                System.out.println(c2);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    }

    三、通过反射获取构造器、接口、创建对象、方法、属性、指定方法、指定属性

    package Java基础.反射;
    import java.lang.reflect.*;
    import java.util.Arrays;
    
    public class Test1 {
        public static void main(String[] args) {
            //通过forname()获取Class 实例
            try {
                Class clazz = Class.forName("Java基础.反射.Student");// 获取Student类的Class实例
    
                Class superClass = clazz.getSuperclass();// 获取父类
                System.out.println(superClass.getName());
    
                Class[] interfaces = clazz.getInterfaces();// 获取当前类的所有接口
                for(Class c:interfaces){
                    System.out.println("接口:"+c.getName());
                }
    
                Constructor[] cons = clazz.getConstructors();// 获取类的公有构造方法
                System.out.println(Arrays.toString(cons));
                for(Constructor c:cons){
                    System.out.println("构造方法:"+c.getName());// 获取方法名称
                    // getModifiers(),返回数字1代表public,数字2代表 private
                    System.out.println("构造方法的修饰符:"+c.getModifiers());// 获取方法修饰符
                    Class[] paramsClazz = c.getParameterTypes();// 获取参数类型
                    for(Class pc:paramsClazz){
                        System.out.println("参数类型"+pc.getName());
                    }
    
                }
                System.out.println("--------------------------");
                Constructor[] cons1 = clazz.getDeclaredConstructors(); // 获取类的所有构造方法,包含公有和私有
                System.out.println(Arrays.toString(cons1));
                for(Constructor c:cons1){
                    System.out.println("构造方法1:"+c.getName());// 获取方法名称
                    System.out.println("构造方法的修饰符1:"+c.getModifiers());// 获取方法修饰符
                    Class[] paramsClazz = c.getParameterTypes();// 获取参数类型
                    for(Class pc:paramsClazz){
                        System.out.println("参数类型1"+pc.getName());
                    }
                }
    
                // 使用反射的构造方法来创建对象
                try {
    
                    Object obj = clazz.newInstance();// 相当于调用Student的无参公有的构造方法
                    Student stu = (Student) obj;// 将object强制转换为Student
    
                    Constructor c1 = clazz.getConstructor(String.class);// 指定获取有一个参数并且为String类型的公有构造方法,必须使用xxx.class格式
                    Student stu1 = (Student) c1.newInstance("第一中学");// newInstance实例化对象
                    System.out.println(stu1.school);
    
                    // 通过反射机制,可以强制调用私有的构造方法
                    Constructor c2 = clazz.getDeclaredConstructor(String.class,int.class);// 指定有两个参数并且为String和int类型
                    c2.setAccessible(true);// 解除私有的封装,然后就可以调用私有方法了
                    Student stu2 = (Student) c2.newInstance("Changsha",12);
                    System.out.println(stu2.name);
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                // 获取类的方法
    //            Method[] methods = clazz.getMethods();// 获取类的所有公有方法,包含了类自有的方法(如toString等方法)
                Method[] methods = clazz.getDeclaredMethods();// 获取类的声明的所有方法,包含私有和公有,不包含类自有的方法
                for(Method m:methods){
                    System.out.println("方法名:"+m.getName());
                    System.out.println("返回值类型:"+m.getReturnType());
                    System.out.println("修饰符:"+m.getModifiers());
    
                    Class[] pcs = m.getParameterTypes();// 获取参数的类型,是一个数组,方法有几个参数,数据就有几个参数类型
                    if(pcs != null && pcs.length >0){
                        for(Class pc:pcs){
                            System.out.println("参数类型:"+pc.getName());
                        }
                    }
                    System.out.println("=======================");
                }
    
                // 获取类的属性
    //            Field[] fs = clazz.getFields();// 获取类的公有属性,包含父类的公有属性
                Field[] fs = clazz.getDeclaredFields();// 获取本类(不包含父类的属性)的所有属性,包含私有
                for(Field f:fs){
                    System.out.println("修饰符:"+f.getModifiers());
                    System.out.println("属性的类型:"+f.getType());
                    System.out.println("属性的名称:"+f.getName());
                }
    
                // 获取类所在的包
                Package p = clazz.getPackage();// 获取
                System.out.println("包的名称:"+p.getName());
    
                /*
                * 注意:下面不论是反射调用setInfo还是test方法
                * 都是调用的obj对象的方法,obj对象时间上就是Stutdent对象
                *
                * */
                // 调用指定公有方法
                Constructor con = clazz.getConstructor();// 获取无参构造方法
                Object obj = con.newInstance();// 使用无参构造 创建对象
                Method m = clazz.getMethod("setInfo", String.class, String.class);// 得到名称为setInfo,参数是String,String
                m.invoke(obj, "zhangsa","第一中学");// 通过invoke方法调用,参数1 需要实例化的对象,参数2 方法所有的实际参数
    
                // 调用指定私有方法
                Method m1 = clazz.getDeclaredMethod("test", String.class);//得到名称为test,参数是String
                m1.setAccessible(true); // 解除私有封装,强制调用私有方法
                m1.invoke(obj,"李四");
    
                // 调用指定重载方法
                Method m2 = clazz.getMethod("setInfo", int.class);//setInfo 重载方法
                m2.invoke(obj, 1);
    
                // 调用有返回值方法,无入参类型
                Method m3 = clazz.getMethod("getSchool");// 获取方法名为getSchool,没有入参
                String school = (String)m3.invoke(obj);// 调用有返回值方法,但是没有参数;由于m3.invoke(obj)返回Object类型,需要通过String强制转换
                System.out.println(school);
    
                // 调用指定公有属性
                Constructor con1 = clazz.getConstructor();
                Student stu1 = (Student)con1.newInstance();
                Field f1 = clazz.getField("school"); // 获取名称为school的属性
                f1.set(stu1, "第三中学");// 对stu1对象的school 属性设置值
                String school1 = (String)f1.get(stu1); // 获取stu1对象的school属性的值
                System.out.println(school1);
    
                // 调用指定私有属性
                Field f2 = clazz.getDeclaredField("privateField");
                f2.setAccessible(true);// 强制解除私有封装
                f2.set(obj, "测试私有属性");
                String name = (String)f2.get(obj);
                System.out.println(name);
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
  • 相关阅读:
    HQ-day17 CSS样式表基础①
    SQL 常用操作
    EXCEL 批量生成SQL
    js 顺序提交表单
    js 页面回调函数
    C# excel 常用操作
    C#关于LINQ
    JS 表单验证
    关于Cookie
    js 短信验证码功能
  • 原文地址:https://www.cnblogs.com/bugoobird/p/13780826.html
Copyright © 2011-2022 走看看