jdk的反射机制

反射的作用

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

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

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

4)在运行时调用任意一个对象的方法。

5)反射API可以获取程序在运行时刻的内部结构。

6)使用反射的一个最大的弊端是性能比较差。相同的操作,用反射API所需的时间大概比直接的使用要慢一两个数量级。

Class类

可以通过以下三种方式获得Class对象:

1)使用Class类的静态方法forName:Class.forName(“java.lang.String”);

2)使用类的.class语法:String.class;

3)使用对象的getClass()方法:String s = "aa";  Class<?> clazz = s.getClass();

4)对于包装类(8个)可以通过.TYPE语法方式

public class ReflectDemo01 {
    public static void main(String[] args) throws Exception {
        // Class<?> clazz = Class.forName(args[0]);
        Class<?> clazz = Class.forName("java.lang.Object");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-------------");
        methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

注意:

getDeclaredMethods()和getMethods()方法的区别

Integer.TYPE返回的是int;

Integer.class返回的是Integer类所对应的Class对象;

Integer.TYPE返回的是基本类型 int的Class实例;

Integer age = 10;
System.out.println(age.TYPE);

结果是:int

getSuperclass()方法的使用

public class ReflectDemo08 {
    public static void main(String[] args) {
        Class<?> classType = Child.class;
        System.out.println(classType); //class Child

        classType = classType.getSuperclass();
        System.out.println(classType); //class Parent

        classType = classType.getSuperclass();
        System.out.println(classType); //class java.lang.Object

        classType = classType.getSuperclass();
        System.out.println(classType);//null
    }
}

class Parent {
}

class Child extends Parent {
}

通过Class的方法来获取到该类中的构造方法、属性和方法。对应的方法分别是getConstructor、getField和getMethod。

Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等。

Constructor类

Constructor类代表某个类中的一个构造方法。

得到某个类所有的构造方法:

Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一个构造方法:

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

创建实例对象:

方法一:通常方式

String str = new String(new StringBuffer("abc"));

方法二:反射方式

String str = (String)constructor.newInstance(new StringBuffer("abc"));

方法三:Class.newInstance()方法

String obj = (String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。

Field类

Field类代表某个类中的一个成员变量;

问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?

类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。(注意访问权限的问题)

示例代码:

ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));

Method类

Method类代表某个类中的一个成员方法;

得到类中的某一个方法:

Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

调用方法:

方式一:通常方式

System.out.println(str.charAt(1));

方式二:反射方式

System.out.println(charAt.invoke(str, 1)); 

如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法

jdk1.4和jdk1.5的invoke方法的区别:

Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke("str", new Object[]{1})形式。

通过Class类实例化对象

方法一:实例化无参构造的类并调用方法

先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

Class<?> classType = String.class;
Object obj = classType.newInstance();

先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:

Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
public class ReflectDemo02 {

    public int add(int param1, int param2) {
        return param1 + param2;
    }

    public String echo(String message) {
        return "hello: " + message;
    }

    public static void main(String[] args) throws Exception {

        Class<?> clazz = ReflectDemo02.class;
        Object obj = clazz.newInstance();

        Method addMethod = clazz.getMethod("add", int.class, int.class);
        Object result = addMethod.invoke(obj, 1, 2);
        System.out.println(result);

        System.out.println("----------------华丽的分割线------------------");

        Method echoMethod = clazz.getMethod("echo", String.class);
        result = echoMethod.invoke(obj, "luogankun");
        System.out.println(result);
    }
}

getMethod()的定义:

public Method getMethod(String name,  Class<?>... parameterTypes)  

第二个参数是可变参数。

方法二:实例化有参构造的类并调用方法

若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:

Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
Object obj = cons.newInstance(new Object[]{"hello", 3});
Class<?> clazz = Dog.class;
Constructor<?> constructor = clazz.getConstructor(Integer.class,String.class);
Dog dog = (Dog) constructor.newInstance(2, "aaad");

利用反射完成对象的拷贝

public class ReflectDemo03 {
    public static void main(String[] args) throws Exception {
        Customer customer = new Customer("Tom", 20);
        customer.setId(1L);

        ReflectDemo03 demo = new ReflectDemo03();

        Customer customer2 = (Customer) demo.copy(customer);
        System.out.println(customer2.getId() + "," + customer2.getName() + ","
                + customer2.getAge());
    }

    // 该方法实现对Customer对象的拷贝操作
    @SuppressWarnings("rawtypes")
    public Object copy(Object object) throws Exception {
        Class<?> clazz = object.getClass();
        System.out.println("clazz " + clazz);

        Constructor constructor = clazz.getConstructor();
        Object objectCopy = constructor.newInstance();

        // 以上两行代码等价于clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields(); //获得属性
        for (Field field : fields) {
            // System.out.println(field.getName());
            String name = field.getName();
            String firstLetter = name.substring(0, 1).toUpperCase();
            String getMethodName = "get" + firstLetter + name.substring(1);
            String setMethodName = "set" + firstLetter + name.substring(1);

            //获得方法
            Method getMethod = clazz.getDeclaredMethod(getMethodName);
            Method setMethod = clazz.getDeclaredMethod(setMethodName,sfield.getType());

            Object value = getMethod.invoke(object);
            setMethod.invoke(objectCopy, value);
        }
        return objectCopy;
    }
}

public class Customer {
    private Long id;
    private String name;
    private int age;

    public Customer() {
    }

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
    setter/getter
}

如果要通过反射调用类的静态方法时,只需要将要反射的对象设置成null即可。 setMethod.invoke(null, value);

使用Java反射API的时候可以绕过Java默认的访问控制检查

1)利用反射调用对象的私有方法

public class ReflectDemo06 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Private.class;
        Object object = clazz.newInstance();

        Method method = clazz.getDeclaredMethod("sayHello", String.class);
        method.setAccessible(true);

        Object result = method.invoke(object, "luogankun");
        System.out.println(result);
    }
}

public class Private {
    private String name = "zhangsan";
    private String sayHello(String name) {
        return "hello: " + name;
    }

    public String getName() {
        return name;
    }
}

2)利用反射完成对私有成员变量的重新赋值

面试题:私有变量能被外界访问吗? 正常情况下不行,但是可以通过反射来调用

public class ReflectDemo07 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Private.class;
        Private object = (Private) clazz.newInstance();

        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        field.set(object, "luogankun");
        System.err.println(object.getName());
    }
}

总结:使用Java反射API的时候可以绕过Java默认的访问控制检查,比如可以直接获取到对象的私有域的值或是调用私有方法

只需要在获取到Constructor、Field和Method类的对象之后,调用setAccessible方法并设为true即可。有了这种机制,就可以很方便的在运行时刻获取到程序的内部状态。

Array类提供了一系列的静态方法用来创建数组和对数组中的元素进行访问和操作

public class ReflectDemo04 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("java.lang.String");
        Object array = Array.newInstance(clazz, 10); //等价于 new String[10]
        Array.set(array, 5, "hello"); //等价于array[5] = "Hello"
        String string = (String) Array.get(array, 5); //等价于array[5]
        System.out.println(string);
    }
}
时间: 2024-08-30 04:50:46

jdk的反射机制的相关文章

利用JAVA反射机制将JSON数据转换成JAVA对象

net.sf.json.JSONObject为我们提供了toBean方法用来转换为JAVA对象, 功能更为强大,  这里借鉴采用JDK的反射机制, 作为简单的辅助工具使用,   有些数据类型需要进行转换, 根据需要进行扩展,  这里可以处理Long和Date类型. 只支持单个JSONObject对象的处理,   对于复杂的JSON对象, 如JSONArray数组, 可考虑先遍历, 获取JSONObject后再进行处理. package common; import java.lang.refle

Java系列笔记(2) - Java RTTI和反射机制

目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这就是RTTI(Runtime Type Information,运行时类型信息). 在java中,有两种RTTI的方式,一种是传统的,即假设在编译时已经知道了所有的类型:还有一种,是利用反射机制,在运行时再尝试确定类型信息. 本文主要讲反射方式实现的RTTI,建议在阅读本文之前,先了解类的加载机制(

Java语言的反射机制 笔记 摘自 http://blog.csdn.net/kaoa000/article/details/8453371

在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的.这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制. 1.Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类.在运行时构造任意一个类的对象.在运行时判断任意一个类所具有的成员变量和方法.在运行时调用任意一个对象的方法 2.Reflection 是Java被视为动态(或准动态)语言的一个关键性质.

Java反射机制(Reflection)

Java反射机制(Reflection) 一.反射机制是什么 Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种动态获取类信息以及动态调用对象方法的功能就是JAVA语言的反射机制. 二.反射机制能干什么 (1)在运行时判断任意一个对象所属的类 (2)在运行时构造任意一个类的对象 (3)在运行时判断任意一个类所具有的成员变量和方法 (4)在运行时调用任意一个对象的方法 (PS:注意反射机制都是在程序运行时,而不

深度剖析JDK动态代理机制

摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 代理模式 使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能. 使用动态代理的五大步骤 1.通过实现InvocationHandler接口来自定义自己的Invocati

Java反射机制专题

·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法 ·Java反射机制提供的功能 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任何一个对象的成员变量和方法 生成动态代理 ·反射相关的主要API: java.lang.Class:代表一个类 java.lang.refle

Java 反射机制(一)

Java 反射机制 基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制. Java反射机制主要提供了以下功能: 1.在运行时判断任意一个对象所属的类. 2.在运行时构造任意一个类的对象. 3.在运行时判断任意一个类所具有的成员变量和方法. 4.在运行时调用任意一个对象的方法. Reflection是Jav

Java 反射机制及Annotation

转自:http://justjavac.iteye.com/blog/714654 Java 反射是 Java 语言的一个很重要的特征. 它允许运行中的 Java 程序对自身进行检查,并能直接操作程序的内部属性.例如,使用 它能获得 Java 类中各成员的名称并显示出来. Java 反射机制主要提供了以下功能: a .在运行时判断任意一个对象所属的类. b .在运行时构造任意一个类的对象. c .在运行时判断任意一个类所具有的成员变量和方法. d .在运行时调用任意一个对象的方法. 在 JDK 

深入理解Java类型信息(Class对象)与反射机制

深入理解Class对象 RRTI的概念以及Class对象作用 认识Class对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RRTI的说法则是源于<Thinking in Java>一书,其作用是在运行时识别一个对象的类型和类的信息,这里分两种:传统的"RRTI",它假定我们在编译期已知道了所有类型(在没有反射机制创建和使用类对象时,一般都是编译期已确定其类