zoukankan      html  css  js  c++  java
  • 反 射

    一.概述
    反射的学习,是便于能更好的理解框架编程。 目前主流的框架技术底层都是反射的机制,如:struts、spring、hibernate等
     
    反射本质上就是一种动态编程的技术,可以在运行阶段动态地创建对象以及动态地调用方法,具体由实参决定。
     
     
    引出:
    若想在写代码的时候,不能确定需要创建Person对象 还是 Student对象。而是希望程序到了运行阶段,能够自行动态地决定创建具体的那个所需对象。
    那么此时,就需要用到反射技术!
     
    如:
    Person p = new Person(); - 只能创建Person类型的对象。
    Student s = new Student(); - 只能创建Student类型的对象。
     
    void show(){ }
    void show(int i){ }
    void show(double d){ }
     
    如何使用 反射 ?
    要用反射技术,需要借助一个类: Java.lang.Class
     
    二,Class 类
     
    1、基本概念
    java.lang.Class类的实例代表应用程序的类和接口,通俗来说,就是该类的实例代表一种数据类型。
    (不是内存空间中堆区中普通对象的一块内存空间)
     
      区别于: Person p =new Person();
    Person的一个实例, 代表的是 堆区中的一块内存空间。 而java.lang.Class类的实例代表一种数据类型。
     
     
    该类没有公共的构造方法(自个不能new这个类的对象),
    class对象是在加载类的时候,由Java虚拟机,以及通过调用类加载器中的defineClass( )方法自动构造的。【构造出来即代表一种数据类型】
     
    那么要想使用Class这个类,则需要得到该类的引用!
     

    如何获取该类的引用?
    2.Class对象的获取方式(4种)
     
    a. 使用 数据类型.class 的方式可以获取该类型的Class对象。(引用数据类型,基本数据类型都适用
    b. 使用 对象.getClass() 的方式可以获取该类型的Class对象。(只适用于引用数据类型)
    【万物皆对象。所以,任何一个类都可以用 对象.getClass()方法区获取 它的class对象】
    c. 使用 包装类的TYPE属性 获取该包装类对应基本数据类型的Class对象。
    d.使用Class类的 forName() 方法获取参数类型的Class对象。 【forName()中,包名 不能省略】 (底层框架中,这种方式最常用)
     
    基本数据类型 获取class对象的途径3种:a c d
    引用数据类型 获取class对象的途径3种:a b d
      代码测试:ClassObjectTest .java
    package com.moneky1024;
    
    public class ClassObjectTest {
    
        public static void main(String[] args) throws ClassNotFoundException {
            //1.使用数据类型.class的方式来获取该类型的Class对象
                    //class java.lang.String 
                    System.out.println(String.class);//自动调用toString()方法
                    System.out.println(int.class);   //int
                    System.out.println(void.class);  //void
                    System.out.println();
                    
                    //2.使用对象.getClass()的方式来获取该类型的Class对象
                    String s1 = new String("GoodMorning");
                    System.out.println(s1.getClass());//class java.lang.String
                    
                    Integer it1 = new Integer(66);
                    System.out.println(it1.getClass());//class java.lang.Integer
                    
                    //int num = 118;
                    //System.out.println(num.getClass()); error
                    System.out.println();
                    
                    //3.使用包装类的TYPE属性来获取基本数据类型的Class对象
                    System.out.println(Integer.TYPE); // int
                    System.out.println(Integer.class);//class java.lang.Integer
                    System.out.println();
                    
                    //4.使用Class类的forName()方法获取Class对象
                    //class java.lang.String
                    System.out.println(Class.forName("java.lang.String"));
                    //System.out.println(Class.forName("int")); error
    
        }
    
    }
     
     

     
    常用方法:
    static Class forName(String className) - 获取参数指定类型的Class对象。
    T newInstance( ) - 根据Class对象创建新实例。
     
    Constructor<T> getConstructor(Class<?>... parameterTypes) - 用于获取当前Class对象对应类中指定的公共构造方法。 (获取单个)
    Constructor<?>[ ] getConstructors( ) - 获取对应类中所有的公共构造方法。 (获取多个,数组接收)
     
    Field getDeclaredField(String name) - 获取对应类中指定的成员变量。
    Field[ ] getDeclaredFields() - 获取对应类中所有的成员变量。
     
    Method getMethod(String name, Class... parameterTypes) - 用于获取对应类中指定的公共成员方法。
    Method[ ] getMethods() - 用于获取对应类中所有的公共成员方法。
     
    代码:
    package com.moneky1024;
    
    public class Person {
        
        private String name;
        private int age;
        
        public Person() {
            super();
        }
        public Person(String name, int age) {
            super();
            setName(name);
            setAge(age);
        }
        
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
        
        
    
    }
    测试类:
    package com.moneky1024;
    
    import java.lang.reflect.Constructor;
    
    public class Test {
        
        public static void main(String[] args) throws Exception {
            //1.创建Person类型的对象
            Person p = new Person();   //调用无参构造方法
            System.out.println(p);    //null 0
            System.out.println();
            
            //2.获取Person类的Class对象并创建实例打印  null 0
            System.out.println(Class.forName("xdl.day21.Person").newInstance());
            System.out.println();
            
            Person p2 = new Person("zhangfei", 30);
            System.out.println(p2); //zhangfei 30
            System.out.println();
            
            //1.获取Class对象,使用forName()方法
            Class c1 = Class.forName("xdl.day21.Person");
            //2.获取对应类中的构造方法,形参类型分别为:String 和 int        
            Constructor cs1 = c1.getConstructor(String.class, int.class);
            //3.调用该构造方法创建新实例,并指定初始值,打印新实例的结果
            System.out.println(cs1.newInstance("guanyu", 35));//guanyu 35   
        }
    }
    结果:
    class java.lang.String
    int
    void
    
    class java.lang.String
    class java.lang.Integer
    
    int
    class java.lang.Integer
    
    class java.lang.String
     

    解析代码:
        public Person(String name, int age) {
            super();
            setName(name);
            setAge(age);
        }
    Person类中的形参类型分别为: String 和 int 。
    而在getConstructor(Class<?>...parameterTypes) 中 参数要的是 class类型
     
     Constructor cs1 = c1.getConstructor(String.class, int.class);
    即,getConstructor(String.class, int.class);

    提出问题:
     在class这个类中,提供了 无参的构造 形式。但是没有 提供 有参的构造形式 去创建新实例,那如果 想创建有参的对象,怎么办?
     
    1、利用Class类中提供的 getConstructor( )方法;
    它的作用: 获取括号中填写参数,指定的类的构造方法的信息。 拿出来后,封装到 Constructor <T> 类里面。
    即, Constructor 类的对象,专门代表获取的构造方法。
     
    2、获取到构造方法后,需要再借助一个 newInstance( )方法 :
     
    调用 newInstance()的对象,使用 之前获取到的 构造方法 去构造这个新实例。
     
     
    总结:
    最终的目的是 -- 调用 newInstance(Object... initargs)
    步骤:
    要想调用 newInstance(Object... initargs) -----> 先得到 Constructor类的引用 ;
    要想得到 Constructor类的引用 -------> 先调用 getConstructor()方法;
    要想调用 getConstructor()方法 -------->先得到class对象
     

    三、 Constructor类
    java.lang.reflect.Constructor类 用于描述获取到的构造方法
     
    T newInstance(Object... initargs) - 调用当前描述的构造方法去创建新实例。
     

    四、Field类
     
    java.lang.reflect.Field 类 用于描述获取到的成员变量
     
    常用方法:
    Object get(Object obj) - 用于获取指定对象中此成员变量的数值。
    void setAccessible(boolean flag) - 参数为true表示可以访问私有成员。
    void set(Object obj, Object value) - 用于修改指定对象中当前成员变量的数值。
     
    代码:
     
    先编写一个Person.java类 (同上)
    FieldTest.java类测试:
    package com.monkey1024;
    
    import java.lang.reflect.Field;
    
    public class FieldTest {
        
        public static void main(String[] args) throws Exception{
            //1.获取Class对象括号中 是   包名+类名
            Class<?> c1 = Class.forName("com.monkey1024.Person");
            
            //2.创建一个Person类型的对象,并传递实参   //为了得到对应的构造方法       // 传参
            Person p = (Person) c1.getConstructor(String.class,int.class).newInstance("zhangfei", 30);   
            
            //3.获取对应类中指定的成员变量
            Field f1 = c1.getDeclaredField("name");     //提供 指定的成员变量 名,获得该指定的变量
            
            //4.设置可以访问私有成员变量
            f1.setAccessible(true);    //若这行代码没有,则私有变量 不能被成功访问
            
            //5.获取指定对象中此成员变量的数值并打印出来
            System.out.println(f1.get(p)); // zhangfei      f1.get(p)表示 去这个p对象中,找到名字为 name 的成员变量,并返回 这个变量
            
            //6.修改指定对象中此成员变量的数值修改为"guanyu"
            f1.set(p, "guanyu");
            System.out.println(f1.get(p)); // guanyu
        }
    
        
    
    }
    结果:
    zhangfei
    guanyu
     
     

    五、Method类
     
    java.lang.reflect.Method类 用于描述获取到的成员方法
     
    常用方法:
    Object invoke(Object obj, Object... args) - 用于obj对象调用当前方法,并传递args作为实参。
     
    代码:
    package com.monkey1024;
    
    import java.lang.reflect.Method;
    
    public class MethodTest {
    
    
        public static void main(String[] args) throws Exception {
            
            //1.获取Class对象
            Class c1 = Class.forName("com.monkey1024.Person");
            
            //2.使用有参构造方法创建该类的实例
            Person p = (Person) c1.getConstructor(String.class, int.class).newInstance("zhangfei", 30);
            
            //3.获取对应类中指定的成员方法
            Method m1 = c1.getMethod("toString");
            
            //4.使用该对象调用此方法,并打印结果
            System.out.println(m1.invoke(p));// zhangfei 30
        }
    
    }
     
    结果:
    Person [name=zhangfei, age=30]
  • 相关阅读:
    Asp.net 默认配置下,Session莫名丢失的原因及解决办法
    回发或回调参数无效。在配置中使用 enableEventValidation=true或在页面中使用 启用了事件验证。
    SQL Server事务日志意外增大的处理方法
    SQLServer数据库设计表和字段(转)
    关于SQL Server数据库设计的感悟
    如何动手组建WiFi网络
    教你在SQL Server数据库中设计表和字段
    SQL Server数据库设计表和字段的经验
    SQL Server 的通用分页显示存储过程
    翻译: jQuery1.4官方文档
  • 原文地址:https://www.cnblogs.com/penguin1024/p/11808149.html
Copyright © 2011-2022 走看看