学习反射笔记

Java反射机制主要提供以下功能:
● 1.在JVM运行时判断任意一个对象所属的类;
● 2.在JVM运行时构造任意一个类的对象;
● 3.在JVM运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
● 4.在JVM运行时调用任意一个对象的方法
● 5.生成动态代理

java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
Class是java反射的起源,对任何想探测的类必须产生一个Class类的对象;Class类的实例表示正在运行的Java应用程序中的类和接口。
Field类提供有关的类和接口的属性,和动态访问权限。(封装反射类的属性)
Constructor类(封装反射类的构造方法);Method类封装反射类的方法;Array类封装静态方法。

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

反射:程序运行时,需要动态的加载一些类,这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。例如我们的项目底层数据库使用mysql或者oracle,需要动态加载驱动类,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc =Class.forName(“com.java.dbtest.TestConnection”);通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!用spring当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载。(–某大佬的解释)

获得Class对象:
1. Object类中的getClass()方法:
2. Class类中的forName()静态方法
3. 直接获取某对象的class:
创建实例:
1. 调用无参的构造方法创建指定名称的类的对象,Class对象的newInstance()方法来创建Class对象对应类的实例。
Class c =Class.forName(“java.util.Date”);
List list=(List)c.newInstance();
2. 使用带参构造方法创建指定类的对象,先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//1.获取String所对应的Class对象
Class c = String.class;
//2.获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//3.根据构造器创建实例
Object obj = constructor.newInstance(“23333”);
System.out.println(obj);
调用方法:
1. getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
2. getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
3. getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
public Method getMethod(String name, Class

// 调用无参的构造方法创建指定名称的类的对象
    public static void main(String[] args) {
        Date currentDate = (Date) newInstance("java.util.Date");
        System.out.println(currentDate);
    }

    public static Object newInstance(String className) {
        Object obj = null;
        // 获取指定名称类的Class对象
            obj = Class.forName(className).newInstance();
        return obj;

    }
// 利用反射使用带参构造方法创建指定类的对象
    public static void main(String[] args) {
        Class claszz;
            claszz = Class.forName("java.util.Date");
            // 获取具有指定参数类型的构造方法
            Constructor constructor = claszz.getConstructor(long.class);
            // 给指定的构造方法传参数,创建对象.
            Date date = (Date) constructor.newInstance(123456789000L);
            System.out.println(date);

    }
package testReflection;
public class ReflectInvokeMethodTest {
    // 动态调用指定类的指定方法
    public static void main(String[] args) {
            Class clazz = Class.forName("testReflection.Product");
            // 创建Product对象
            Product product = (Product) clazz.newInstance();
            // 获取名为setName,带一个string类型参数的成员方法所对应的对象代表
            Method method = clazz.getDeclaredMethod("setName", String.class);
            // 在product对象上调用setName并传值给他,返回值为空
            Object returnValue = method.invoke(product, "java");
            System.out.println("返回值" + returnValue);
            // 获取名为displayInfo,不带参数的成员方法
            Method method2 = clazz.getDeclaredMethod("displayInfo");
            // 取消访问检查
            method2.setAccessible(true);
            // 在Product对象上调用私有的displayInfo方法
            method2.invoke(product);//incoke()真正执行
    }
}
class Product {
    private static long count = 0;
    private long id;
    private String name = "无名氏";
    public Product() {id = ++count;}
    public long getId() {return id;}
    public void setId(long id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {
    System.out.println("调用setName方法");
        this.name = name;
    }
    private void displayInfo() {
    System.out.println(getClass().getName() + "id=" + id + "name=" + name);
    }
}
public class ReflectFiledTest {
    // 动态获取或设置指定对象的指定成员变量的值
    @SuppressWarnings({ "deprecation", "rawtypes" })
    public static void main(String[] args) {

            Class c = Class.forName("testReflection.Product");
            // 使用无参构造方法创建对象
            Product prod = (Product) c.newInstance();
            // 获取私有属性
            Field iField = c.getDeclaredField("id");
            iField.setAccessible(true);// 取消本字段的访问检查
            // 设置prod对象的iField成员变量的值为100
            iField.setLong(prod, 100);
            // 获取prod对象的IFiled成员变量的值
            System.out.println("id:" + iField.getLong(prod));
            Field nameField = c.getDeclaredField("name");
            nameField.setAccessible(true);
            nameField.set(prod, "赵四");
            System.out.println("name" + nameField.get(prod));

    }
}
public class ReflectArrayTest {
    // 反射获取数组信息
    public static void main(String[] args) {
        int[] iArr = new int[5];
        double[] dArr = new double[5];
        String[] sArr = new String[5];
        // iArr.getClass().getName();先用getComponentType()获取对象;
        System.out.println("数组限定名:" + iArr.getClass().getComponentType().getName());
        System.out.println("数组限定名:" + dArr.getClass().getComponentType().getName());
        System.out.println("数组限定名:" + sArr.getClass().getComponentType().getName());
        // 动态创建数组
            Class<?> cla1 = Class.forName("java.lang.String");
            Object array = Array.newInstance(cla1, 25);
            // 加数据
            for (int i = 0; i < 5; i++) {
                Array.set(array, i, "number:" + i);
            }
            // 拿数据
            System.out.println(Array.get(array, 3));
    }

}

由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

posted @ 2018-01-31 22:30  小沐酱  阅读(69)  评论(0编辑  收藏  举报