java反射

------------ android培训java培训、java博客、java学习型技术博客、期待与您交流! --------------

Java中的反射:

内存里面的每一份字节码就是一个Class类的的实例对象。
java虚拟机里面每一个类只保存一份字节码。

得到字节码(Class类)的方式有三种:
类名.class;
对象名.getClass();
Class.forName("类名"):如果要加载的类字节码已经被加载过,那么就直接返回那一份字节码;
如果要加载的类字节码没有被加载过,那么就用类加载器去加载,把加载进来的字节码缓存到虚拟机里面;

java里面有9个预定义的Class实例对象(8个基本数据类型和void)。

int.class = Integer.TYPE;
int.class.isPrimitive();-----true    //判断class类是否为基本数据类型。
int[].class.isArray();-----true   //判断Class类是否为数组类。

总之,只要是在源程序中出现的类型,都有各自的Class实例对象,如:int[], void 等。

字节码之间的比较应该用“==”来比较,当然,用equals()来比较也是可以的,只是从意义上来说,应该用“==”来比较比较合理。
因为一种类型的字节码在虚拟机里面是只有一份的,所以,用“==”来比较比较合理。如:field1.getType() == String.class;

Class类中有个方法isAssignableFrom(Class<?> cls)判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,
或是否是其超类或超接口。如果是则返回 true;否则返回 false。
如果该 Class 表示一个基本类型,且指定的 Class 参数正是该 Class 对象,则该方法返回 true;否则返回 false。
如:Number.class.isAssignableFrom(Integer.class);返回true。


反射:把java类中的各种成分映射成相应的java类。
      其实就是通过一个类的Class对象(字节码)把类中的各种成分映射成相应的java类的对象来使用。

Constructor类,Field类,Method类。

Class类中的方法newInstance()方法是在方法内部先得到默认的构造方法,然后用该构造方法来创建实例对象。其内部用到了缓存机制来保存默认构造方法的实例对象。

Constructor类的简单使用见如下例子:
package com.heima.exam;

import java.lang.reflect.Constructor;

public class RefConstructorTest {

 public static void main(String[] args) throws Exception {
  // TODO Auto-generated method stub

  Constructor con = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
         String str = (String) con.newInstance(new StringBuffer("haha"));
         System.out.println(str);
            }

}


Field实例对象只代表类字节码里面的一个变量,并不代表某一对象里面的变量本身具体的值。我们需要调用Field类中的方法get(Object obj)
(注意:此方法返回类型是Object类型,很多时候我们需要做类型强制转换。)或其他对应的方法才能获得具体实例对象所对应的此字段的值。
在对象里面声明为非public的的成员变量需要用getDeclaredField(String name)才能得到Class对象中的此变量名所对应的Field实例对象。
然后如果需要访问此Field实例对象所对应的具体的值,那么需要调用Field父类的方法setAccessible(true)来指示反射的对象在使用时应该取消Java语言访问检查,
然后才能访问具体对象所对应的此字段的值。

Field对象的使用见如下例子:

package com.heima.exam;

import java.lang.reflect.Field;

public class RefChangeStringValue {
 
 public static void changeStringValue(Object obj) {
  
      Field[] fields = obj.getClass().getDeclaredFields();
          for(Field field : fields) {
                     if(field.getType() == String.class) {
             try {
                       field.setAccessible(true);
                       field.set(obj, ((String)field.get(obj)).replace('b', 'a'));
             } catch (IllegalArgumentException e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
             } catch (IllegalAccessException e) {
                       // TODO Auto-generated catch block
              e.printStackTrace();


                               }
                     }
           }
 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub

  TestClass tv = new TestClass();
           changeStringValue(tv);
           System.out.println(tv);
 }

}

class TestClass {
                   public String str1 = "ball";
                   protected String str2 = "basketball";
                   String str3 = "hello";
                   private String str4 = "bell";
                   int i = 10;
 
 public String toString() {
                    return str1 + ":" + str2 + ":" + str3 + ":" + str4 + ":" + i;
          }
}


         静态方法的反射调用时,invoke()方法中的对象参数可以是null,如:methodTest.invoke(null, "hello"))。

  java1.5以后的虚拟机为了兼容1.4以前的版本,对方法的反射调用时所传输的数组参数进行解包操作,如:method1.invoke(null, new String[] {"aa", "bb"});
         java虚拟机会自动的解开数组里面的元素来作为调用方法的参数,此时并不是我们所想象的那样了,而实际是method1.invoke(null, "aa", "bb");这样了。
         我们只能用如下方式进行调用:Test.method1((Object)new String[] {"aa", "bb"});或如下所说的另一种方案。
         对接收数组参数的成员方法进行反射的2种解决方案:new Object(arrays[]),(object)arrays[]。

Method类的简单使用见如下例子:

package com.heima.exam;

import java.lang.reflect.Method;

public class RefMethodTest {

public static void main(String[] args) throws Exception {
                    // TODO Auto-generated method stub

             String str = "hello";
                    Method methodCharAt = String.class.getMethod("charAt", int.class);
                    System.out.println(methodCharAt.invoke(str, 0));
  
                    Method methodMin = Math.class.getMethod("min", int.class, int.class);
                    System.out.println(methodMin.invoke(null, 3, 20));
  
                    ClassTest1.main(new String[] {"aa", "bb"});
  
                    Method methodMain = Class.forName("com.heima.exam.ClassTest1").getMethod("main", String[].class);
                    methodMain.invoke(null, (Object)new String[] {"hello", "world"});
                    methodMain.invoke(null, new Object[] {new String[] {"hello", "world"}});
          }

}

class ClassTest1 {
                    public static void main(String[] args) {
                    for(String arg : args) {
                     System.out.println(arg);
                    }
          }
}


数组类型:具有相同类型和相同维数的数组共享同一份字节码,即同一个Class类。

Arrays是一个对数组操作的工具类,里面有很多的方法能对数组进行各种操作,如:Arrays.asList(T... a),能将一个数组转换成List返回。
Arrays中的asList(T... a)方法为了兼容JDK1.4版本,如果传进去的参数是一个Object数组的话,那么就把数组里面的元素装进一个集合里面,并返回这个List集合,
但是如果传进去的参数是一个基本类型的数组的话,那么就把这个基本类型的数组作为一个元素装进集合里面并返回。
如:Arrays.asList(new String[] {"aa", "ss", "dd"});那么转换后的List集合里面有3个元素,分别是"aa", "ss", "dd";
但是:Arrays.asList(new int[] {1, 5, 9});这样的话,转换后的List集合里面就只有一个元素,这个元素就是new int[] {1, 5, 9}这个数组本身。

Array工具类用于完成对数组的反射操作,Array类里面的所有方法都是静态方法。如:Array.getLength(obj); Array.get(obj, index);
数组反射的简单应用程序片段如下:
public void printObject(Object obj) {
          if(obj.getClass().isArray()) {
          for(int i = 0; i < Array.getLength(obj); i++) {
                     System.out.println(Array.get(obj, i));
                }
           } else {
                      System.out.println(obj);
           }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值