devway

https://github.com/devway9

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

目录

  • 1 什么是反射?主要提供了哪些功能?
  • 2 如何通过反射获取类的信息?
  • 3 数组的特殊处理。
  • 4 反射的应用场景。
  • 5 其他。

正文

1 什么是反射?主要提供了哪些功能?
  1) Java的反射机制是指在程序运行期间,对于任意一个类,都可以知道这个类的属性和方法,并进行调用。
  2) 提供以下功能:
    ① 在运行时可以判断任意一个对象所属的类。
    ② 在运行时可以构造任意一个类的对象。
    ③ 在运行时可以获取任意一个类的所有成员变量和方法。
    ④ 在运行时调用任意一个对象的方法。
    ⑤ 生成动态代理。
  3) 优缺点
    ① 优点:增加灵活性。
    ② 缺点:使用不当会导致效率低、会破坏封装,且可以访问类的私有方法,不安全。

2 如何通过反射获取类的信息?
  1) 首先获取类的Class对象:
    ① 每一个类、接口、数组、基本类型都有唯一的一个对应的Class类对象。通过Class类对象可以获取类的全部信息(包括成员变量、方法、父类、接口等)。
    ② 获得Class对象的三种方式。【参考TestLoadClass.java】
    ③ Class的常用方法:【参考TestClass.java】 

package com.devway.j2se.reflect;

public class TestLoadClass {
    public static void main(String[] args) {
        try {
            // 获取Class对象的三种方法
            // 方法一,通过对象实例获取,
            A a = new A();
            Class<?> class1 = a.getClass();
            System.out.println("1:getClass " + class1);

            // 方法二,根据类名获取
            Class<?> class2 = B.class;
            System.out.println("2:.class " + class2);
            // 方法三,根据类的全名获取
            Class<?> class3 = Class.forName("com.devway.j2se.reflect.C");
            System.out.println("3:Class.forName " + class3);

        } catch (ClassNotFoundException e) {
            System.err.println(e);
        }

    }
}

class A {
    static {
        System.out.println("init A static");
    }
}

class B {
    static {
        System.out.println("init B static");
    }
}

class C {
    static {
        System.out.println("init C static");
    }
}
TestLoadClass.java
package com.devway.j2se.reflect;

public class TestClass {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");
            System.out.println("1:" + class1);// true

            // Class类的常用方法
            // 判断是否是接口
            boolean isInterface = class1.isInterface();// false
            // 判断是否是数组
            boolean isArray = class1.isArray();// false
            // 判断是否是8种基本类型
            boolean isPrimitive = class1.isPrimitive();// false;
            System.out.println("2:" + isInterface + "," + isArray + "," + isPrimitive);

            // 获取父类的Class类对象
            Class<?> superClass = class1.getSuperclass();
            // 获取所有接口
            Class<?>[] interfaces = class1.getInterfaces();
            // 获取类型修饰符
            int modifiers = class1.getModifiers();
            System.out.println("3:" + superClass + "," + interfaces + "," + modifiers);

            // 获取数组的组件类型
            int[] ints = { 1, 2, 3 };
            Class<?> class4 = ints.getClass();
            Class<?> class5 = class4.getComponentType();// int
            System.out.println("4:" + class4);
            System.out.println("4:" + class5);

            // 返回声明这个的Class对象,如果不是嵌套类型,返回null
            Class<?> class6 = class1.getDeclaringClass();// null
            System.out.println("5:" + class6);

            // 获取包
            Package package1 = class1.getPackage();
            System.out.println("6:" + package1);

        } catch (ClassNotFoundException e) {
            System.err.println(e);
        }
    }
}

package com.devway.j2se.reflect;

public interface Interface1 {
    String iv1 = "a";
    String iv2 = "b";

    void f1();
}

package com.devway.j2se.reflect;

public class Parent {
    public String pv1;
    protected String pv2;

    public Parent() {

    }

    public String pf1(String s) {
        return s;
    }

    protected void pf2() {

    }

    void pf3() {

    }

    private void pf4() {

    }

}

package com.devway.j2se.reflect;

public class Child extends Parent implements Interface1 {
    public String cv1;
    protected String cv2;
    private String cv3;
    public static String scv1;

    public Child() {

    }

    public Child(String s, int i) {

    }

    protected Child(int i) {

    }

    private Child(String s) {

    }

    public String cf1(String s, int i) throws NullPointerException {
        return s + i;
    }

    protected void cf2() {
        System.out.println("protected method cf4()");
    }

    void cf3() {
        System.out.println("default method cf4()");
    }

    private void cf4() {
        System.out.println("private method cf4()");
    }

    @Override
    public void f1() {
        System.out.println("public method f1()");
    }

}
TestClass.java

  2) 对类的构造函数、方法、属性的访问和调用:
    ① Constructor类:用于构造函数。【参考TestConstrcutor.java】
    ② Method类:用于类的方法。【参考TestMethod.java】
    ③ Field类:用于类的属性。【参考TestField.java】
    ④ Modifer类:用于判断修饰符类型。【参考TestModifier.java】
    ⑤ Field、Method、Constructor类都继承了AccessibleObject类(该类用于获取和修该访问权限)【参考TestAccessible.java】,同时也实现了Member接口。

package com.devway.j2se.reflect;

import java.lang.reflect.Constructor;

public class TestConstrcutor {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");

            // 获取所有的public构造函数,包括父类和接口的
            Constructor<?>[] publicConstructors = class1.getConstructors();
            for (Constructor<?> constructor : publicConstructors) {
                System.out.println("1:" + constructor);
            }

            // 获取当前类的所有构造函数,不包括父类和接口的
            Constructor<?>[] declaredConstructors = class1.getDeclaredConstructors();
            for (Constructor<?> constructor : declaredConstructors) {
                System.out.println("2:" + constructor);
            }

            // 根据名称和参数获取方法
            Constructor<?> constructor1 = class1.getConstructor(String.class, int.class);
            System.out.println("3:" + constructor1);

            // 获取方法参数对应的Class对象
            Class<?>[] paramTypesClass = constructor1.getParameterTypes();
            for (Class<?> paramType : paramTypesClass) {
                System.out.println("4:" + paramType);
            }

            // 获取方法抛出的异常对应的Class对象
            Class<?>[] exceptionTypesClass = constructor1.getExceptionTypes();
            for (Class<?> exceptionType : exceptionTypesClass) {
                System.out.println("6:" + exceptionType);
            }

            // 创建实例并调用方法
            Interface1 inf = (Interface1) class1.newInstance();
            inf.f1();

        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException e) {
            System.err.println(e);
        }
    }
}
TestConstrcutor.java
package com.devway.j2se.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestMethod {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");

            // 获取所有的public方法,包括父类和接口的
            Method[] publicMethods = class1.getMethods();
            for (Method method : publicMethods) {
                System.out.println("1:" + method);
            }

            // 获取当前类的所有方法,不包括父类和接口的
            Method[] declaredMethods = class1.getDeclaredMethods();
            for (Method method : declaredMethods) {
                System.out.println("2:" + method);
            }

            // 根据名称和参数获取方法
            Method method1 = class1.getMethod("cf1", String.class, int.class);
            System.out.println("3:" + method1);

            // 获取方法返回值类型对应的Class对象
            Class<?> returnTypeClass = method1.getReturnType();
            System.out.println("4:" + returnTypeClass);

            // 获取方法参数对应的Class对象
            Class<?>[] paramTypesClass = method1.getParameterTypes();
            for (Class<?> paramType : paramTypesClass) {
                System.out.println("5:" + paramType);
            }

            // 获取方法抛出的异常对应的Class对象
            Class<?>[] exceptionTypesClass = method1.getExceptionTypes();
            for (Class<?> exceptionType : exceptionTypesClass) {
                System.out.println("6:" + exceptionType);
            }

            // 方法调用
            Child child = (Child) class1.newInstance();
            String value = (String) method1.invoke(child, "abc", 123);
            System.out.println("7:" + value);
        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            System.err.println(e);
        }
    }
}
TestMethod.java
package com.devway.j2se.reflect;

import java.lang.reflect.Field;

public class TestField {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");

            // 获取所有的public域,包括父类和接口的
            Field[] publicFields = class1.getFields();
            for (Field field : publicFields) {
                System.out.println("1:" + field);
            }

            // 获取当前类的所有域,不包括父类和接口的
            Field[] declaredFields = class1.getDeclaredFields();
            for (Field field : declaredFields) {
                System.out.println("2:" + field);
            }

            // 根据名称获取域
            Field field1 = class1.getField("cv1");
            System.out.println("3:" + field1);

            // 获取域类型的Class对象
            Class<?> field1Class = field1.getType();
            System.out.println("4:" + field1Class);

            // 读取域的值
            Child child = (Child) class1.newInstance();
            child.cv1 = "abc";
            String field1Value = (String) field1.get(child);// abc
            System.out.println("5:" + field1Value);

            // 修改域的值
            field1.set(child, "def");
            System.out.println("6:" + child.cv1);

        } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | InstantiationException | IllegalAccessException e) {
            System.err.println(e);
        }
    }
}
TestField.java
package com.devway.j2se.reflect;

import java.lang.reflect.Modifier;

public class TestModifier {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");
            boolean isPrivate = Modifier.isPrivate(class1.getModifiers());// false;
            System.out.println("1:" + isPrivate);

            boolean isAbastract = Modifier.isAbstract(class1.getModifiers());// false
            System.out.println("2:" + isAbastract);
        } catch (ClassNotFoundException e) {
            System.err.println(e);
        }
    }
}
TestModifier.java
package com.devway.j2se.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestAccessible {
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("com.devway.j2se.reflect.Child");
            Method method1 = class1.getDeclaredMethod("cf4");

            Interface1 inf = (Interface1) class1.newInstance();
            // ! method1.invoke(inf,null);//cf4是private方法,不能访问
            System.out.println("1:" + method1.isAccessible());//false
            
            //取消访问限制
            method1.setAccessible(true);
            method1.invoke(inf,null);
            System.out.println("2:" + method1.isAccessible());//true
        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            System.err.println(e);
        }

    }
}
TestAccessible.java

 

 3 数组的特殊处理。

  1) 数组是没有方法和属性的对象,所以不能通过反射常用的的方法来获取或设置成员。
  2) 可以通过反射创建数组,使用两种new Instance的方法来创建。使用Array.set和Array.get来设置或获取数组元素的值。【参考TestArray.java】  

package com.devway.j2se.reflect;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class TestArray {
    public static void main(String[] args) {
        Integer[] arrays1 = { 1, 2, 3, 4 };
        Class<?> class1 = arrays1.getClass();

        // 数组是没有方法和域的对象,所以都返回null
        Method[] delcaredMethods = class1.getDeclaredMethods();
        for (Method method : delcaredMethods) {
            System.out.println("1:" + method);// null
        }

        Field[] delcaredFields = class1.getDeclaredFields();
        for (Field field : delcaredFields) {
            System.out.println("2:" + field);// null
        }

        // 创建数组方式1
        Integer[] arrays2 = (Integer[]) Array.newInstance(Integer.class, 5);

        // 创建数组方式2,返回多为数组
        int[] intval = { 2, 2 };
        Integer[][] arrays3 = (Integer[][]) Array.newInstance(Integer.class, intval);

        // 设置数组元素的值
        for (int i = 0; i < arrays2.length; i++) {
            Array.set(arrays2, i, i + 1);
        }

        // 获取数组元素的值
        for (int i = 0; i < arrays2.length; i++) {
            System.out.println("3:" + Array.get(arrays2, i));
        }

    }
}
TestArray.java

 

4 反射的应用场景。

  1) 用于基础框架中,如Spring。
  2) JDBC,数据库可能使用Oracle,也可能使用Mysql,不同的数据库有不同的驱动,在运行时,再通过Class.forName()运用反射动态加载。
  3) 应用开发中,尽量避免使用反射。

5 其他。

  1) class.getName方法返回结果
    ① 数组类型以[为前缀,后面跟着成员的类型编码,基础类型则简写如下。
    (B:byte、C:char、D:double、F:float、I:int、J:long、S:short、Z:boolean)
    ② 嵌套类型使用$符号将类型名隔开:Outer$Inner
  2) 注意这种写法是错误的:Class<Parent> c = Child.class; 因为Child.class不是Parent的子类,正确写法是:Class<? extends Parent> c= Child.class。
  3) 向上转型和向下转型:
    ① 向上转型:子类转为父类,自动转换。
    ② 向下转型:父类转为子类,需要强制转换。

posted on 2017-12-01 15:31  devway  阅读(165)  评论(0编辑  收藏  举报