zoukankan      html  css  js  c++  java
  • Java基础——反射

    今天学到Java基础中的反反射。依照我学习后的个人理解呢,反射就是一套获取类、属性、方法等的工具吧。(其实,感觉学完反射后,有点像喝凉水,解渴但确实我也没体会出它有什么味道,我可能没有学到精髓吧。自己都能感觉少点什么。这是我Java基础学习的最后一个部分了,我想再复习一遍,然后再学习其他的。也想有时间看看JVM和计算机系统之类的书。总觉得自己不是科班出身,思路上有些短板。要继续努力咯。)

    在学习反射之前,我先回忆了一下可变参数。

    public static void main(String[] args) {
                test();//调用方法1
                test("JAVA");//调用方法2
                test("JAVA","工程师");//调用方法3
                test(new String[]{"水果","电器"});//调用方法4
            }
        
            static void test(String ... array){  
                //直接打印:System.out.println(array);
                for(String str:array){  //利用增强for遍历
                System.out.println(str);
                }
            }

    之所以回忆可变参数呢,是因为它与反射的应用有点像。如果将一个方法定义为可变参数,在调用的时候传参的限制就少了一大截。在反射当中呢,我们利用一些方法,得到类的实例对象,那么类里面的方法、属性等,就尽收眼底。在前面的学习中知道了,方法、属性等都有静态的和非静态的,私有的和非私有的之分,那么我们在调用的时候,想取哪一块,或者说只想取得哪一块,是不是也可以想个办法实现呢?这时候,反射就出现了,现今我对它的理解就只有这些了。继续努力吧。

    一、反射的概念

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

    Java反射机制主要提供了以下功能:

    -- 在运行时判断任意一个对象所属的类;

    -- 在运行时构造任意一个类的对象;

    -- 在运行时判断任意一个类所具有的成员变量和方法;

    -- 在运行时调用任意一个对象的方法;

    -- 生成动态代理。

    JDK中,与反射相关的类,主要有以下几个

    //java.lang包下

    Class 类

    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)    和关键字 void 也表示为 Class 对象。

    关于Class类JDK里面的解释:

    public final
        class Class<T> implements java.io.Serializable,
                                  java.lang.reflect.GenericDeclaration,
                                  java.lang.reflect.Type,
                                  java.lang.reflect.AnnotatedElement {
        private static final int ANNOTATION= 0x00002000;
        private static final int ENUM      = 0x00004000;
        private static final int SYNTHETIC = 0x00001000;
    
        private static native void registerNatives();
        static {
            registerNatives();
        }
    
        /*
         * Constructor. Only the Java Virtual Machine creates Class
         * objects.
         */
        private Class() {}

    Class类JDK里的一些方法(个人觉得读起来很舒服,自己想记录一下)

    public String toString() {
            return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
                + getName();
        }//应该是三元表达式
    public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    public static Class<?> forName(String name, boolean initialize,
                                       ClassLoader loader)
            throws ClassNotFoundException
        {
            Class<?> caller = null;
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                // Reflective call to get caller class is only needed if a security manager
                // is present.  Avoid the overhead of making this call otherwise.
                caller = Reflection.getCallerClass();
                if (loader == null) {
                    ClassLoader ccl = ClassLoader.getClassLoader(caller);
                    if (ccl != null) {
                        sm.checkPermission(
                            SecurityConstants.GET_CLASSLOADER_PERMISSION);
                    }
                }
            }
            return forName0(name, initialize, loader, caller);
        }
    private static native Class<?> forName0(String name, boolean initialize,
                                                ClassLoader loader,
                                                Class<?> caller)
            throws ClassNotFoundException;
    public T newInstance()
            throws InstantiationException, IllegalAccessException
        {
            if (System.getSecurityManager() != null) {
                checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
            }
    
            // NOTE: the following code may not be strictly correct under
            // the current Java memory model.
    
            // Constructor lookup
            if (cachedConstructor == null) {
                if (this == Class.class) {
                    throw new IllegalAccessException(
                        "Can not call newInstance() on the Class for java.lang.Class"
                    );
                }
                try {
                    Class<?>[] empty = {};
                    final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                    // Disable accessibility checks on the constructor
                    // since we have to do the security check here anyway
                    // (the stack depth is wrong for the Constructor's
                    // security check to work)
                    java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction<Void>() {
                            public Void run() {
                                    c.setAccessible(true);
                                    return null;
                                }
                            });
                    cachedConstructor = c;
                } catch (NoSuchMethodException e) {
                    throw new InstantiationException(getName());
                }
            }
            Constructor<T> tmpConstructor = cachedConstructor;
            // Security check (same as in java.lang.reflect.Constructor)
            int modifiers = tmpConstructor.getModifiers();
            if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                if (newInstanceCallerCache != caller) {
                    Reflection.ensureMemberAccess(caller, this, null, modifiers);
                    newInstanceCallerCache = caller;
                }
            }
            // Run constructor
            try {
                return tmpConstructor.newInstance((Object[])null);
            } catch (InvocationTargetException e) {
                Unsafe.getUnsafe().throwException(e.getTargetException());
                // Not reached
                return null;
            }
        }
    public String getName() {
            String name = this.name;
            if (name == null)
                this.name = name = getName0();
            return name;
        }
    // cache the name to reduce the number of calls into the VM
        private transient String name;
        private native String getName0();

    还有很多,暂不记录了。。。。。

    //java.lang.reflect  包下
    Constructor 代表构造函数
    Method 代表方法
    Field 代表字段
    Array 与数组相关

    二、Class类的说明

    常用的得到Class类的方法
     // Class c=new Class(); 不可以,因为它被私有化了
    1) Class c=Student.class;   //用类名.class 就可以得到Class类的实例
    2) Student stu=new Student();
    Class c=stu.getClass();   //用对象名.getClass();
    3) Class c=Class.forName("com.mysql.jdbc.Driver");
    //例一  通过调用无参的构造函数,创建类对象
    public class Test {
        public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Class clazz=Dog.class;
        Dog dog=(Dog)clazz.newInstance();
        dog.shout();
        }
    }
                
    class Dog{
        void shout(){
        System.out.println("汪汪");
        }
    }

    通过例一,我并没有看出来利用反射的好处,呃~~

    //例二 上例的改写
    Class clazz=Class.forName("com.weiboo.Dog"); //注意,必须是类的全部
    Dog dog=(Dog)clazz.newInstance();
    dog.shout();
    //例三  (运行本类,Dog 和 Cat 类,必须有一个无参的构造函数)
    public class Test {
        public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Dog dog=(Dog)createObj(Dog.class);
        dog.shout();
                    
        Cat cat=(Cat)createObj(Cat.class);
        cat.speak();
        }
                        
    static Object createObj(Class clazz) throws InstantiationException, IllegalAccessException{
        return clazz.newInstance();  //调用的是newInstance() 方法创建的类对象,它调用的是类中无参的构造方法
    }
        }
            
    class Dog{
        void shout(){
        System.out.println("汪汪");
        }
    }
            
    class  Cat{
        void speak(){
        System.out.println("喵~~~");        
        }
    }

    三、反射中的其他的类的说明

    1) Constructor

    代表类中的构造函数     Class 类提供了以下四个方法

    public Constructor<?>[] getConstructors()      //返回类中所有的public构造器集合,默认构造器的下标为0

    public Constructor<T> getConstructor(Class<?>... parameterTypes)   //返回指定public构造器,参数为构造器参数类型集合

    public Constructor<?>[] getDeclaredConstructors()  //返回类中所有的构造器,包括私有的

    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //返回任意指定的构造器,包括私有的

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    //例子 得到某个类中指定的某个构造函数所对应的 Constructor对象
    class Test2 {
        public static void main(String[] args) throws InstantiationException,
                IllegalAccessException, ClassNotFoundException,
                NoSuchMethodException, SecurityException, IllegalArgumentException,
                InvocationTargetException {
            Class<Cat> clazz = Cat.class;
    
            Constructor<Cat> c = clazz.getConstructor(int.class, String.class);
            Cat cat = (Cat) c.newInstance(20, "加飞猫");
            cat.speak();
        }
    
        class Cat {
            private String name;
            private int age;
    
            public Cat(int age, String name) {
                this.age = age;
                this.name = name;
            }
    
            public Cat(String content) {
                System.out.println("这是构造函数得到的参数" + content);
            }
    
            void speak() {
                System.out.println("喵~~~");
                System.out.println("我的名字是" + this.name + "我的年龄是" + this.age);
            }
        }
    }
    /例子 访问类中的私有构造函数
    Class clazz=Cat.class;
    Constructor c=clazz.getDeclaredConstructor();
    c.setAccessible(true);  //让私有成员可以对外访问
    Cat cat=(Cat) c.newInstance();  //对于私有的来说,能不能行?
    cat.speak();

    2) Method 代表类中的方法

    Class 类提供了以下四个方法

    public Method[] getMethods()    //获取所有的共有方法的集合,包扩继承的

    public Method getMethod(String name,Class<?>... parameterTypes) // 获取指定公有方法 参数1:方法名 参数2:参数类型集合 

    public Method[] getDeclaredMethods()  //获取所有的方法(包扩私有的),除了继承来的

    public Method getDeclaredMethod(String name,Class<?>... parameterTypes) //获取任意指定方法,除来了继承来的

    //调用类中的私有方法
    main 函数
    Class  clazz=Cat.class;
    //调用一个不带参数的方法
    Method m=clazz.getDeclaredMethod("speak");
    m.setAccessible(true);
    Cat c=new Cat();
    m.invoke(c);  //让方法执行
                    
                        
    //调用一个带参数的方法
    Method m=clazz.getDeclaredMethod("eat", int.class,String.class);
    m.setAccessible(true);
    Cat c=new Cat();
    m.invoke(c, 20,"鱼");    
    
    class  Cat{
    private String name;
    private int age;
                            
    Cat(){    
    }
    public Cat(int age,String name){
        this.age=age;
        this. name=name;
        }
                            
    public Cat(String content){
        System.out.println("这是构造函数得到的参数"+content);
        }
                            
        private void speak(){
        System.out.println("喵~~~");        
        System.out.println("我的名字是"+this.name+"我的年龄是"+this.age);
        }
                            
        private void eat(int time,String something){
        System.out.println("我在"+time +"分钟内吃了一个"+something);
        }
    }
    例子 查看一个类中的所有的方法名
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        Class  clazz=Cat.class;
                            
        /*Method []  methodList=clazz.getMethods() ; //查看所有的公有方法,包扩继承的
        for(Method m:methodList){
        System.out.println(m.getName());
        }*/
        Method []  methodList=clazz.getDeclaredMethods(); //查看所有的方法,包扩私有的,但不包扩继承的
        for(Method m:methodList){
        System.out.println(m.getName());
        }
    }

    3) Field 代表字段

    public Field getDeclaredField(String name)  // 获取任意指定名字的成员

    public Field[] getDeclaredFields()  // 获取所有的成员变量,除了继承来的

    public Field getField(String name)  // 获取任意public成员变量,包含继承来的

    public Field[] getFields() // 获取所有的public成员变量

    //例子 访问字段
    public class Test {
        public static void main(String[] args) throws Exception {
        Class clazz=Cat.class;
                             
        /* Field field= clazz.getField("home");
        Cat c=new Cat();
        Object obj=field.get(c);
        System.out.println(obj); // 家*/
                             
        Cat cat=new Cat();
        Field  [] fieldList= clazz.getDeclaredFields();
        for(Field f:fieldList){  //访问所有字段
        f.setAccessible(true);
        System.out.println(f.get(cat)); 
                                       }
            }
    }                            
    class  Cat{
        private String name="黑猫";
        private int age=2;
        public String home="家";
    }

    四、反射的应用

    用一个例子来说明一下,比较两个同类对象中的所有字段,不同的并把它输出来。

    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            Student stu1 = new Student(24, "李磊", "工程大学", "女");
            Student stu2 = new Student(20, "王一", "师大", "男");
            Map<String, String> map = compare(stu1, stu2);
    
            for (Map.Entry<String, String> item : map.entrySet()) {
                System.out.println(item.getKey() + ":" + item.getValue());
            }
        }
    
        static Map<String, String> compare(Student stu1, Student stu2) {
            Map<String, String> resultMap = new HashMap<String, String>();
    
            Field[] fieldLis = stu1.getClass().getDeclaredFields(); // 得到stu1所有的字段对象
            try {
                for (Field f : fieldLis) {
                    f.setAccessible(true); // 别忘了,让私有成员可以对外访问
                    Object v1 = f.get(stu1);
                    Object v2 = f.get(stu2);
                    if (!(v1.equals(v2))) {
                        resultMap.put(f.getName(), "stu1的值是" + v1 + "   stu2的值是"
                                + v2);
                    }
                }
    
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return resultMap;
    
        }
    
    }
    
    class Student {
        private String name;
        private String school;
        private String sex;
    
        public Student(int age, String name, String school, String sex) {
    
            this.age = age;
            this.name = name;
            this.school = school;
            this.sex = sex;
        }
    
        private int age;
    
        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 String getSchool() {
            return school;
        }
    
        public void setSchool(String school) {
            this.school = school;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    }

  • 相关阅读:
    LintCode-Search for a Range
    LintCode-Serialization and Deserialization Of Binary Tree
    LeetCode-Reverse Words in a String
    LeetCode-Reorder List
    LeetCode-Word Break
    LeetCode-Word Ladder
    LeetCode-Valid Palindrome
    cf div2 237 D
    POJ 1759
    cf div2 238 D
  • 原文地址:https://www.cnblogs.com/1693977889zz/p/7160639.html
Copyright © 2011-2022 走看看