Chinaunix首页 | 论坛 | 博客
  • 博客访问: 69929
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 15:04
个人简介

记录,分享

文章分类

全部博文(43)

文章存档

2017年(24)

2015年(1)

2014年(18)

我的朋友

分类: Java

2014-06-27 16:32:19

一、Class类
    反射机制为程序提供了分析类的能力。在程序运行期间,java运行时系统始终未所有的对象维护一个被称为运行时的类型标识。这个信息保存着每个对象所属的类足迹,保存在Class类的对象实例中,虚拟机根据运行时信息选择相应的方法执行。
    
    获得Class对象的三种形式:
1.Class clazz = obj.getClass();
2.Class clazz = Class.forName(className);
3.Class clazz = T.class (T是类型名,不仅可以是类也可以使基本数据类型.如 Date.class,int.class,double[].class)

二、利用反射分析类的结构

    java.lang.reflect包中提供了Field、Method和Constructor三个类分别描述类的域、方法和构造器。Class类中提供了不同的方法用来获取public或者全部声明的域、方法、构造器。

  • Field类用于描述类的域,它有一个 getType 方法,用来返回域所属类型的Class对象。
  • Method类和Constructor类都有能够报告参数类型的方法,Method类还有一个可以报告返回类型的方法。
  • 这三个类都提供了一个叫 getModifiers 的方法,它将返回一个整型数值,其不同的位分别描述public,static等修饰符的使用状况。 可以用反射包中 Modifier 类提供的方法来分析这个整型数值,例如,isPublic,isPrivate等等。
  • 这三个类都提供了 setAccessible 方法,可以在运行时改变域、方法和构造器的访问控制级别。一个常见场景是利用这个方法在单元测试时测试非公有方法。记得使用后要再次调用这个方法将访问控制恢复。
三、在运行时利用反射分析对象、修改对象

    将对象转成json格式字符串是典型的反射应用。看下面的例子

public class JsonMapper {

    private static final Set> basics_num = new HashSet>();
    private static final Set> basics_not_num = new HashSet>();
    static {
        basics_num.add(Integer.TYPE);
        basics_num.add(Integer.class);
        basics_num.add(Long.TYPE);
        basics_num.add(Long.class);
        basics_num.add(Byte.TYPE);
        basics_num.add(Byte.class);
        basics_num.add(Short.TYPE);
        basics_num.add(Short.class);
        basics_num.add(Float.TYPE);
        basics_num.add(Float.class);
        basics_num.add(Double.TYPE);
        basics_num.add(Double.class);
        basics_not_num.add(Boolean.TYPE);
        basics_not_num.add(Boolean.class);
        basics_not_num.add(Character.TYPE);
        basics_not_num.add(Character.class);
    }

    public static String toJson(Object o) throws IllegalArgumentException, IllegalAccessException {
        StringBuilder sb = new StringBuilder();
        toJson(o, false, sb);
        return sb.toString();
    }

    public static void toJson(Object o, boolean isField, StringBuilder sb)
            throws IllegalArgumentException, IllegalAccessException {
        if (o == null)
            return;
        Class clazz = o.getClass();

        if (o instanceof CharSequence || basics_not_num.contains(clazz)) {
            if (isField) {
                sb.append("\"").append(String.valueOf(o)).append("\"");
            } else {
                sb.append("[\"").append(String.valueOf(o)).append("\"]");
            }
        } 
        else if (basics_num.contains(clazz)){
            if (isField) {
                sb.append(String.valueOf(o));
            } else {
                sb.append("[").append(String.valueOf(o)).append("]");
            }
        }
        else if (isArray(o)) {
            arrayToJson(o, sb);
        } else if (isIterable(o)) {
            iterableToJson(o, sb);
        } else if (isMap(o)) {
            mapToJson(o, sb);
        }

        else {
            sb.append("{");
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                field.setAccessible(true);
                sb.append("\"");
                sb.append(field.getName());
                sb.append("\":");
                Object fo = field.get(o);
                toJson(fo, true, sb);
                field.setAccessible(false);
                if (i != (fields.length - 1))
                    sb.append(",");
            }
            sb.append("}");
        }
    }

    private static boolean isArray(Object object) {
        return object.getClass().isArray();
    }

    private static boolean isIterable(Object object) {
        return object instanceof Iterable;
    }

    private static boolean isMap(Object object) {
        return object instanceof Map;
    }

    private static void arrayToJson(Object o, StringBuilder sb)
            throws IllegalArgumentException, IllegalAccessException {
        sb.append("[");
//        Object[] _object = (Object[]) object;
        int len = Array.getLength(o);
        for (int i = 0; i < len; i++) {
            Object elem = Array.get(o, i);
            toJson(elem, true, sb);
            if (i != len - 1)
                sb.append(",");
        }
        sb.append("]");
    }

    private static void iterableToJson(Object object, StringBuilder sb)
            throws IllegalArgumentException, IllegalAccessException {
        if (object == null)
            return;
        sb.append("[");
        Iterable _object = (Iterable) object;
        Iterator it = _object.iterator();
        while (it.hasNext()) {
            Object elem = it.next();
            toJson(elem, true, sb);
            if (it.hasNext())
                sb.append(",");
        }
        sb.append("]");
    }

    private static void mapToJson(Object object, StringBuilder sb)
            throws IllegalArgumentException, IllegalAccessException {
        sb.append("{");
        Map _object = (Map) object;
        Set entrySet = _object.entrySet();
        Iterator it = entrySet.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            Object key = entry.getKey();
            Object value = entry.getValue();
            sb.append("\"").append(key).append("\":");
            toJson(value, true, sb);
            if (it.hasNext())
                sb.append(",");
        }
        sb.append("}");
    }

    static class ModelObject {
        private int intField;
        private Integer integerField;
        private long longField;
        private Long _longField;
        private double doubleField;
        private Double _doubleField;
        private float floatField;
        private Float _floatField;
        private char charField;
        private Character characterField;
        private byte byteField;
        private Byte _byteField;
        private boolean booleanField;
        private Boolean _booleanField;
        private String stringField;
        private String[] stringArrayField = {"s1", "s2", "s3"};
        private int[] intArrayField = {1,2,3};
        private Map mapField;
        {
            this.intField = 4;
            this.integerField = new Integer(intField);
            this.longField = 1000l;
            this._longField = new Long(longField);
            this.doubleField = 1.0;
            this._doubleField = new Double(doubleField);
            this.floatField = 2.0f;
            this._floatField = new Float(floatField);
            this.charField = 'c';
            this.characterField = new Character(charField);
            this.byteField = 0x01;
            this._byteField = new Byte(byteField);
            this.booleanField = true;
            this._booleanField = new Boolean(booleanField);
            this.stringField = "json";
            this.mapField = new HashMap();
            SubObject[] subs = { new SubObject("001"), new SubObject("002"), new SubObject("003") };
            for (SubObject sub : subs)
                this.mapField.put(sub.getNo(), sub);
        }
    }

    static class SubObject {
        private String no;
        private List stringList;

        public SubObject(String no) {
            this.no = no;
            List list = new ArrayList();
            list.add("haha");
            list.add("wowo");
            list.add("hehe");
            this.stringList = list;
        }

        public String getNo() {
            return no;
        }

        public void setNo(String no) {
            this.no = no;
        }

        public List getStringList() {
            return stringList;
        }

        public void setStringList(List stringList) {
            this.stringList = stringList;
        }
    }

    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        ModelObject o = new ModelObject();
        System.out.println(toJson(o));
        System.out.println(toJson("abc"));
        int[] a = {1,2,3,4};
        System.out.println(toJson(a));
    }
}

四、利用反射编写泛型数组代码

    假设一种场景,我们创建了一个数组并将它填满,我们希望能够扩展这个数组而又不希望每次手工地编写扩展代码。可以利用反射的特性来编写一个通用的方法动态扩展数组。

    看下面的代码:

static Object[] arrayGrow(Object[] obj,int growth){
    int newLength = obj.length+growth;
    Object[] newArray = new Object[newLength];
    System.arrayCopy(obj,0,newArray,0,obj.length);
    return newArray;
}

Book[] books = new Book[100];
...
//array is full
books = arrayGrow(books,50);

    这段代码运行会抛出 ClassCastException ,因为java数组会记住每个元素被创建时的类型,newArray被创建时用的是是Object[]类型(不是指声明类型,虽然声明类型也是Object[]),无法强制转换成Book[]类型。解决方法是利用java.lang.reflect.Array的newInstance方法,可以在创建数组时指定元素类型。

  看下面代码

   static Object goodArrayGrow(Object a,int growth)
   {
      Class cl = a.getClass();
      if (!cl.isArray()) return null;
      Class componentType = cl.getComponentType();    //
      int length = Array.getLength(a);
      int newLength = length + growth;
      Object newArray = Array.newInstance(componentType, newLength);
      System.arraycopy(a, 0, newArray, 0, length);
      return newArray;
   }

五、动态调用方法(方法指针)

    java并没有提供方法指针机制,但作为反射的副产品,类似方法指针的东西是存在的。看下面的代码

Method method = XXX.class.getDeclaredMethod("fun",null);
int result = (int)method.invoke(x,null);// x is an object of XXX class


阅读(611) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~