• Java动态性之反射机制(reflection)


    说到反射机制,第一次接触的人可能会比较懵,反射?什么反射?怎么反射?反射是干嘛的?下面我将在这篇文章中讲讲Java的反射机制


    不过在这之前,还有一个问题需要解决,标题名中的动态性,说起动态性,我先介绍介绍动态语言和静态语言

    静态语言

      静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。 例如:C++、Java、Delphi、C#等。

    动态语言

      动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。 例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等。并且动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。

      这时可能你就会有疑问了,既然Java属于静态语言,又怎么会有动态性?其一就是Java存在与动态性相关的机制:反射机制。Java通过反射机制,可以在程序运行时加载,探知和使用编译期间完全未知的类,并且可以生成相关类对象实例,从而可以调用其方法或则改变某个属性值。所以JAVA也可以算得上是一个半动态的语言


     

    下面来讲讲反射机制

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

      反射的原理在于Class对象

        看一看程序加载的过程

    从图中大概可以看出反射是干什么用的了,那接下来就讲讲有关反射的其他方面

      反射的API

        反射API用来生成JVM中的类、接口或则对象的信息。
        - Class类:反射的核心类,可以获取类的属性,方法等信息。
        - Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
        - Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
        - Constructor类: Java.lang.reflec包中的类,表示类的构造方法。

     


     

    下面就来讲讲怎么使用反射了  

    1.步骤

    • 获取想要操作的类的Class对象
    • 调用Class类中的方法
    • 使用反射API来操作这些信息

     2.获取Class对象的方法

    //假设我们有一个Student类
    方法一、(推荐)
        Class clas = Class.forName("first.Student");//“”里写的是类的全路径
    
    方法二、
        Student stu = new Student();
        Class clas = stu.getClass();
    
    方法三、
        Class clas = Student.Class;
                

    可以试试用两个不同的方法获取clas1和clas2,然后System.ou.println(clas1==clas2)看看会输出什么,原因在图上

    3.获取构造方法、字段、main方法并调用

    Student.java

    public class Student {
        public String name;
        protected int age;
        char sex;
        private String phoneNum;
        
        public static void main(String[] args) {
    
            System.out.println("main方法执行了。。。");
    
        }
        //---------------构造方法-------------------
        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) {
            this.name=name;this.age=age;
            System.out.println("姓名:" + name + "年龄:" + age);// 这的执行效率有问题,以后解决。
        }
    
        // 受保护的构造方法
        protected Student(boolean n) {
            System.out.println("受保护的构造方法 n = " + n);
        }
    
        // 私有构造方法
        private Student(int age) {
            System.out.println("私有的构造方法   年龄:" + age);
        }
        
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", sex=" + sex
                    + ", phoneNum=" + phoneNum + "]";
        }
    }

    Constructors.java(构造方法)

    package first;
    
    import java.lang.reflect.Constructor;
    
    public class Constructors {
        public static void main(String[] args) throws Exception {
            
            Class clas=Class.forName("first.Student");
            
            System.out.println("所有公有构造方法");
            Constructor[] conArry=clas.getConstructors();
            for(int i=0;i<conArry.length;i++) {
                System.out.println(conArry[i]);
            }
            
            System.out.println("所有的构造方法");
            conArry=clas.getDeclaredConstructors();
            for(int i=0;i<conArry.length;i++) {
                System.out.println(conArry[i]);
            }
            
            System.out.println("获取公有无参的构造方法");
            Constructor con=clas.getConstructor(null);
            System.out.println("con="+con);
            Object obj=con.newInstance();
            
            System.out.println("获取私有构造方法,并调用");
            con=clas.getDeclaredConstructor(char.class);
            System.out.println(con);
            //con.setAccessible(true);//暴力访问,针对private方法和字段时使用
            obj=con.newInstance('a');//创建对象
        }
    }

    输出

    所有公有构造方法
    public first.Student(char)
    public first.Student()
    public first.Student(java.lang.String,int)
    所有的构造方法
    protected first.Student(boolean)
    private first.Student(int)
    public first.Student(char)
    public first.Student()
    first.Student(java.lang.String)
    public first.Student(java.lang.String,int)
    获取公有无参的构造方法
    con=public first.Student()
    调用了公有、无参构造方法执行了。。。
    获取私有构造方法,并调用
    public first.Student(char)
    姓名:a

    Fields.java(字段)

    package first;
    
    import java.lang.reflect.Field;
    
    public class Fields {
    
        public static void main(String[] args)throws Exception {
            // TODO Auto-generated method stub
            Class StuClass=Class.forName("first.Student");
            
            System.out.println("获取所有公有的字段");
            Field[] fieldArry=StuClass.getFields();
            for(Field f:fieldArry) {
                System.out.println(f);
            }
            System.out.println("获取所有的字段(包括私有、受保护、默认的)");
            fieldArry=StuClass.getDeclaredFields();
            for(Field f:fieldArry) {
                System.out.println(f);
            }
            System.out.println("获取公有字段并调用");
            Field f = StuClass.getField("name");
            System.out.println(f);
            Object obj=StuClass.getConstructor().newInstance();
            StuClass.getConstructor(String.class,int.class).newInstance("a",10);
            f.set(obj, "b");
            Student stu=(Student)obj;
            System.out.println(stu.name);
            
            System.out.println("获取私有字段并调用");
            f = StuClass.getDeclaredField("phoneNum");
            System.out.println(f);
            f.setAccessible(true);//暴力反射,解除私有限定
            f.set(obj, "18888889999");
            System.out.println("验证电话:" + stu);
        }
        
    
    }

    输出

    获取所有公有的字段
    public java.lang.String first.Student.name
    获取所有的字段(包括私有、受保护、默认的)
    public java.lang.String first.Student.name
    protected int first.Student.age
    char first.Student.sex
    private java.lang.String first.Student.phoneNum
    获取公有字段并调用
    public java.lang.String first.Student.name
    调用了公有、无参构造方法执行了。。。
    姓名:a年龄:10
    b
    获取私有字段并调用
    private java.lang.String first.Student.phoneNum
    验证电话:Student [name=b, age=0, sex=

    Main.java

    package first;
    
    import java.lang.reflect.Method;
    
    public class Main {
        public static void main(String[] args) {
            try {
                // 1、获取Student对象的字节码
                Class clazz = Class.forName("first.Student");
    
                // 2、获取main方法
    
                Method methodMain = clazz.getMethod("main", String[].class);// 第一个参数:方法名称,第二个参数:方法形参的类型,
    
                // 3、调用main方法
                // methodMain.invoke(null, new String[]{"a","b","c"});
                // 第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组
                // 这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
                methodMain.invoke(null, (Object) new String[] {});// 方式一
                // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    未完待续。。。。。

     

     

    参考文章:

    https://blog.csdn.net/sinat_38259539/article/details/71799078

     

  • 相关阅读:
    there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
    使用Mybatis-Generator自动生成Dao、Model、Mapping相关文件
    ActiveMQ使用示例之Queue
    JMS基本概念之一
    @ActiveMQ简单介绍以及安装
    Spring中 @Autowired注解与@Resource注解的区别
    classpath: 和classpath*:的区别
    Mybatis整合Spring
    @MyBatis主键返回
    Intellij Idea @Autowired取消提示
  • 原文地址:https://www.cnblogs.com/csu-lmw/p/9676170.html
Copyright © 2020-2023  润新知