黑马程序员-------Java高级特性--------反射

黑马程序员—–Java高级特性—–反射

——- android培训java培训、期待与您交流! ———-

一.概述

Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。
这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。
Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection(反射)introspection(内省)是常被并提的两个术语。

二.Java 反射的API

反射中常常用的几个类如下所示:
java.lang 包中:
–Class 类:代表一个类
Java 中,无论生成某个类的多少个对象,这些对象都会对应同一个 Class 对象
Java.lang.reflect 包中:
–Field 类:代表类的成员变量(类的属性)
–Method 类:代表类的方法,一个方法对应一个 Method 对象
–Constructor 类:代表类的构造方法
–Array 类:提供动态创建数组,以及访问数组的元素的静态方法

三.使用JAVA反射综合示例

1. Class对象的获取及实例化

//1.获取该类的 Class 对象
//常用方法有三种:
//a)通过 Class 的 forName 的静态方法获得(参数:包名 + 类名):
    Class<?> classType = Class.forName("java.lang.String");
//b)通过类名 + 点 class 的方法获得:
     Class<?> c = String.class;
//c)通过类的对象的 getClass 的方法获得:
    String str = "test";
    Class<?> typeClass = str.getClass();


//2.实例化一个该类的对象
//两种方法:
//a)通过 Class 对象的 newInstance 的方法创建(该方法只对无参构造方法适用):
    Class<?> classType = Class.forName("java.lang.String");
    Object obj = = classType.newInstance();
//b)通过获取 Constructor 构造方法类的对象,然后通过该对象的 newInstance (Object ... initargs) 方法获得:
    Class<?> classType = cus.getClass();
    Constructor con= classType.getConstructor(new Class[]{String.class,int.class});
    Object object= con.newInstance(new Object[]{cus.getName(),cus.getAge()});
     该方法中的若写成两个参数写成 Class[]{} 和 new Object[ ]{} ,就等同于 a) 的方法

2.访问被private 修饰的方法和属性

public class Private  
{  
    private String name = "张三";  

    private String getName()  
    {  
        return name;  
    }  
}  

把该类中private修饰的 name 值改成“李四”,并且用反射机制调用 getName 方法,返回修改后的值。

package com.wangzhuo.reflect;  

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

public class PrivateTest  
{  
    public static void main(String[] args)throws Exception  
    {  
        //获取Private类的Class对象  
        Class<?> classType = Class.forName("com.wangzhuo.reflect.Private");  

         //获取其构造方法对应的Constructor对象  
        Constructor con = classType.getDeclaredConstructor(new Class[]{});  

         //创建Private的对象  
        Object object =con.newInstance(new Object[]{});  

       //获取Private类中name属性对应的Field对象  
        Field field = classType.getDeclaredField("name");  

        //设置避开java访问控制检测  
        field.setAccessible(true);  

        //获取修改前的值  
        Object str = field.get(object);  

        System.out.println("修改之前name的值:"+(String)str);  

        //给name属性赋值  
        field.set(object, "李四");  

       //获取getName方法对应的Method对象  
        Method getNameMethod = classType.getDeclaredMethod("getName", new Class[]{});  

        //设置避开java访问控制检测  
        getNameMethod.setAccessible(true);  

        //调用方法,返回值  
        Object  o = getNameMethod.invoke(object, new Object[]{});  
        System.out.println("修改之后name的值:"+(String)o);  
    }  
}  

3.运行时复制对象(重要)
ReflectTester 类进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object 同样类型的对象,然后把object对象中的所有属性拷贝到新建的对象中,并将它返回。

public class ReflectTester {
    public Object copy(Object object) throws Exception {
        // 获得对象的类型
        Class<?> classType = object.getClass();
        System.out.println("Class:" + classType.getName());

        // 通过默认构造方法创建一个新的对象
        Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});

        // 获得对象的所有属性
        Field fields[] = classType.getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];

            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            // 获得和属性对应的getXXX()方法的名字
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            // 获得和属性对应的setXXX()方法的名字
            String setMethodName = "set" + firstLetter + fieldName.substring(1);

            // 获得和属性对应的getXXX()方法
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});
            // 获得和属性对应的setXXX()方法
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});

            // 调用原对象的getXXX()方法
            Object value = getMethod.invoke(object, new Object[]{});
            System.out.println(fieldName + ":" + value);
            // 调用拷贝对象的setXXX()方法
            setMethod.invoke(objectCopy, new Object[]{value});
        }
        return objectCopy;
    }

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

        Customer customerCopy = (Customer) new ReflectTester().copy(customer);
        System.out.println("Copy information:" + customerCopy.getId() + " " + customerCopy.getName() + " "
                + customerCopy.getAge());
    }
}

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;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    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;
    }
}

输出结果:

Class:com.langsin.reflection.Customer
id:1
name:Tom
age:21
Copy information:1 Tom 21

示例四.运行时变更field内容

public class RefFiled {
    public double x;
    public Double y;

    public static void main(String args[]) throws NoSuchFieldException, IllegalAccessException {
        Class c = RefFiled.class;
        Field xf = c.getField("x");
        Field yf = c.getField("y");

        RefFiled obj = new RefFiled();

        System.out.println("变更前x=" + xf.get(obj));
        //变更成员x值
        xf.set(obj, 1.1);
        System.out.println("变更后x=" + xf.get(obj));

        System.out.println("变更前y=" + yf.get(obj));
        //变更成员y值
        yf.set(obj, 2.1);
        System.out.println("变更后y=" + yf.get(obj));
    }
}

运行结果:

变更前x=0.0
变更后x=1.1
变更前y=null
变更后y=2.1

示例五.用反射机制调用对象的方法

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

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

    public static void main(String[] args) throws Exception {
        Class<?> classType = InvokeTester.class;
        Object invokeTester = classType.newInstance();

        // Object invokeTester = classType.getConstructor(new
        // Class[]{}).newInstance(new Object[]{});


        //获取InvokeTester类的add()方法
        Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class});
        //调用invokeTester对象上的add()方法
        Object result = addMethod.invoke(invokeTester, new Object[]{new Integer(100), new Integer(200)});
        System.out.println((Integer) result);


        //获取InvokeTester类的echo()方法
        Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
        //调用invokeTester对象的echo()方法
        result = echoMethod.invoke(invokeTester, new Object[]{"Hello"});
        System.out.println((String) result);
    }
}

在例程InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法

add()方法的两个参数为int 类型,获得表示add()方法的Method对象的代码如下:
Method addMethod=classType.getMethod(“add”,new Class[]{int.class,int.class});
Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。

在本例中,尽管InvokeTester 类的add()方法的两个参数以及返回值都是int类型,调用add Method 对象的invoke()方法时,只能传递Integer 类型的参数,并且invoke()方法的返回类型也是Integer 类型,Integer 类是int 基本类型的包装类:
Object result=addMethod.invoke(invokeTester,
new Object[]{new Integer(100),new Integer(200)});
System.out.println((Integer)result); //result 为Integer类型

六.动态创建和访问数组
ArrayTester1 类的main()方法创建了一个长度为10 的字符串数组,接着把索引位置为5 的元素设为“hello”,然后再读取索引位置为5 的元素的值。

public class ArrayTester1 {
    public static void main(String args[]) throws Exception {
        Class<?> classType = Class.forName("java.lang.String");
        // 创建一个长度为10的字符串数组
        Object array = Array.newInstance(classType, 10);
        // 把索引位置为5的元素设为"hello"
        Array.set(array, 5, "hello");
        // 获得索引位置为5的元素的值
        String s = (String) Array.get(array, 5);
        System.out.println(s);
    }
}

ArrayTester2 类的main()方法创建了一个 5 x 10 x 15 的整型数组,并把索引位置为[3][5][10] 的元素的值为设37。

public class ArrayTester2 {
    public static void main(String args[]) {
        int[] dims = new int[]{5, 10, 15};
        //创建一个具有指定的组件类型和维度的新数组。
        Object array = Array.newInstance(Integer.TYPE, dims);

        Object arrayObj = Array.get(array, 3);
        Class<?> cls = arrayObj.getClass().getComponentType();
        System.out.println(cls);

        arrayObj = Array.get(arrayObj, 5);
        Array.setInt(arrayObj, 10, 37);
        int arrayCast[][][] = (int[][][]) array;
        System.out.println(arrayCast[3][5][10]);
    }
}

本文借鉴了
http://lavasoft.blog.51cto.com/62575/43218/
http://847353020-qq-com.iteye.com/blog/1003440

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值