zoukankan      html  css  js  c++  java
  • [Java-基础]反射_Class对象_动态操作

    动态性

    动态语言

    • 在程序运行时,可以改变程序结构或变量类型,典型的语言:
      • Python,ruby,javascript
      • 如:
    function test(){
        var s = "var a=3;var b=5;alert(a+b);";
        eval(s);
    }
    

    Java的动态性

    • C,C++,JAVA不是动态语言,但是JAVA有一定的动态性
    • 我们可以利用反射机制,字节码操作获得类似动态语言的特性
    • JAVA的动态性让编程的时候更加灵活

    Class类

    反射机制

    • 指的是可以于运行时加载,探知,使用编译期间完全未知的类
    • 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

    Class c=Class.forName("com.User");

    • "com.User"是字符串,是类的路径,可以动态的实时的加载这个类。
    • 加载完类之后,在堆内存中,就产生一个Class类型的对象,一个类只有一个Class对象,这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象像一面镜子,透过这个镜子看到类的结构。所以称之为反射、

    先简单写一个com.User

    public class User {
        /**
         *
         */
        private int id;
        private int age;
        private String uname;
    
        public User() {
    
        }
    
        public User(int id,int age,String uname){
            super();
            this.id=id;
            this.age=age;
            this.uname=uname;
        }
        public String getUname() {
            return uname;
        }
    
        public void setUname(String uname) {
            this.uname = uname;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    }
    

    获取Class对象的方式

    • 获取Class对象的三种方式
    • 1 Object ——> getClass();
    • 2 任何数据类型(包括基本数据类型int,数组等)都有一个“静态”的class属性
    • 3 通过Class类的静态方法:forName(String className)(常用)
    public class Demo01 {
    
        public static void main(String []args){
            //第一种  Object ——> getClass();
            User user1 = new User();
            Class clazz1=user1.getClass();
            System.out.println(clazz1.hashCode());
    
            //第二种 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
            Class clazz2 = User.class;
            System.out.println(clazz2.hashCode());
    
            //第三种:通过Class类的静态方法:forName(String  className)(常用)
            String path="com.fanshe.User";
            try {
                Class clazz3=Class.forName(path);
                System.out.println(clazz3.hashCode());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    

    这三种方法得到的hashcode是一样的,这验证了一个类只有一个Class对象:一个工厂可以有很多辆车,但可能只有一张图纸。

    反射机制的常见作用

    反射的使用主要就是获取到了Class对象之后,通过调用Class对象的方法来操纵。

    public class Demo02 {
        public static void main(String[] args) throws NoSuchMethodException {
            //第三种:通过Class类的静态方法:forName(String  className)(常用)
            String path="com.fanshe.User";
            try {
                Class clazz3=Class.forName(path);
                //获得类的名字
                System.out.println("
    获取类的名字: ");
                System.out.println(clazz3.getName());//包名加类名
                System.out.println(clazz3.getSimpleName());//类名
    
                //获取属性信息
                System.out.println("
    获取属性信息: ");
                Field[] field=clazz3.getFields();
                Field[] field1=clazz3.getDeclaredFields();
                System.out.println(field.length+"  "+field1.length);//前者只能读取public的
                Field field2 = clazz3.getDeclaredField("id");
                for(Field temp:field1){
                    System.out.println("属性: "+temp);
                }
    
                //获取方法的属性
                System.out.println("
    获取方法的属性: ");
                Method[] methods = clazz3.getDeclaredMethods();
                Method method = clazz3.getMethod("setUname", String.class);//单一方法
                Method method1 = clazz3.getMethod("getUname",null);
                for(Method temp:methods){
                    System.out.println("方法: "+temp);
                }
    
                //获得构造器的信息
                System.out.println("
    获得构造器信息: ");
                Constructor[] constructors = clazz3.getDeclaredConstructors();
                for(Constructor temp:constructors){
                    System.out.println("构造器: "+temp);
                }
                Constructor constructor = clazz3.getDeclaredConstructor(int.class,int.class,String.class);
                System.out.println("有参构造器:"+clazz3);
             } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    运行结果

    获取类的名字: 
    com.fanshe.User
    User
    
    获取属性信息: 
    0  3
    属性: private int com.fanshe.User.id
    属性: private int com.fanshe.User.age
    属性: private java.lang.String com.fanshe.User.uname
    
    获取方法的属性: 
    方法: public int com.fanshe.User.getId()
    方法: public java.lang.String com.fanshe.User.getUname()
    方法: public void com.fanshe.User.setUname(java.lang.String)
    方法: public void com.fanshe.User.setId(int)
    方法: public int com.fanshe.User.getAge()
    方法: public void com.fanshe.User.setAge(int)
    
    获得构造器信息: 
    构造器: public com.fanshe.User()
    构造器: public com.fanshe.User(int,int,java.lang.String)
    有参构造器:class com.fanshe.User
    

    通过反射API的动态操作

    public class Demo03 {
        public static void main(String []args){
            //第三种:通过Class类的静态方法:forName(String  className)(常用)
            String path="com.fanshe.User";
            try {
                Class clazz3=Class.forName(path);
            /*通过反射API调用构造方法,构造对象*/
    
                //其实是调用了User的无参方法
                User user = (User)clazz3.newInstance();
                user.setUname("大王");
                System.out.println(user.getUname());
                //获得方法
                Constructor<User> constructor = clazz3.getDeclaredConstructor(int.class,int.class,String.class);
                //通过实际的参数来调用
                User user1 = constructor.newInstance(1001,18,"美云");
                System.out.println(user1.getUname());
            /*通过反射API调用普通方法*/
               //user1.setUname("小七");
               User user2 =(User) clazz3.newInstance();
                Method method = clazz3.getDeclaredMethod("setUname",String.class);
                method.invoke(user2,"小七");
                System.out.println(user2.getUname());
    
            /*通过反射API操作属性*/
                User user3 = (User)clazz3.newInstance();
                Field f =clazz3.getDeclaredField("uname");
                f.setAccessible(true);
                f.set(user3,"小赖");
                System.out.println(user3.getUname());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }
    

    运行结果明显

    大王
    美云
    小七
    小赖
    

    这样写有什么好处呢?可以发现setUname 是字符串,传的参数也是变量,这样的变量我们就可以从文件中读取,可以从数据库中读取,总之可以从其他地方传过来,这样就实现了动态的调用,动态创建类。

    参考

    [1] https://www.cnblogs.com/nullcodeworld/p/8878747.html

    [2] b站:av29578196

  • 相关阅读:
    2、从0开始学算法 时间/空间复杂度(如何知道你的代码性能如何?)
    1、从0开始学算法 概述
    机器学习(五):通俗易懂决策树与随机森林及代码实践
    机器学习(四):通俗理解支持向量机SVM及代码实践
    机器学习(三):理解逻辑回归及二分类、多分类代码实践
    HDU 2492 Ping pong (树状数组)
    yum更新失败
    webpack3配置rules的问题
    置顶帖汇总
    2021.07.03软件更新公告
  • 原文地址:https://www.cnblogs.com/smallocean/p/12360677.html
Copyright © 2011-2022 走看看