反射调用私有实现类的方法出异常的分析

原始内容如下:

http://www.java2000.net/viewthread.jsp?tid=6982

http://topic.youkuaiyun.com/u/20080707/10/a718ad57-a28d-4492-b1e9-f3048671260a.html

我们先看测试代码:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class T {
  public static synchronized void main(String[] a) throws Exception {
    T t = new T();
    Method m = t.getClass().getMethod("hasNext");
    System.out.print(m.invoke(t));
    List<T> list = new ArrayList<T>();
    list.add(t);
    Iterator it = list.iterator();
    m = it.getClass().getMethod("hasNext");
    System.out.print(m.invoke(it));
  }

  public boolean hasNext() {
    return true;
  }
}

运行结果为

trueException in thread "main" java.lang.IllegalAccessException: Class T can not access a member of class java.util.AbstractList$Itr with modifiers "public"

第一个true我们就不分析了,关键是第二个为何为异常??我们来看几个楼层的回复

Java2000_net:

T的getClass返回T,他的hasNext是一个public 方法,所以可以正常调用,输出true; 

而 Iterator的 getClass 返回的是一个 java.util.AbstractList$Itr 

我们可以输出看看 

System.out.println(it.getClass()); 

那个Itr是一个inner Class, 其 hasNext 不是一个public方法,所以无法调用。 

关键就是Iterator是一个接口而已。

Any_Yan:

呵呵,很有意思的一个问题! 

ArrayList继承自AbstractList,其iterator()方法返回内部类Itr的一个实例,而AbstractList的内部类Itr签名是private  关键问题在最后一行"System.out.print(m.invoke(it));"上 

Method的invoke方法参数是一个对象,内部到底决定是谁去调用这个Method呢?这里显然最后JVM决定用T来调用这个"hasNext"的Method对象,T肯定没有访问它的权利,至于底层原理,我会整明白再来回答,呵呵,上班暂时没空

import java.lang.reflect.Method;

public class T {
  public static void main(String[] args)throws Exception{
      T t = new T();
      Sam sam = t.getIt();
      Method m = sam.getClass().getMethod("f");
      System.out.println(sam.getClass());
      m.invoke(sam);
  }

  private class It implements Sam{
    public void f(){
      System.out.println("F method");
    }
  }

  public Sam getIt(){
     return new It();
  }
}



public interface Sam{
    public void f();
}

无语了,自己也模仿这个例子写了个程序,却无法重新楼主程序里出现的问题,一下子推理也不知道从哪里开始了。楼主那个程序中的异常是从Method类的invoke方法中有下面这行抛出来的: 

其中caller是sun.reflect.Reflection.getCallerClass(1)返回的,由于不提供源码,所以无法深入跟踪 

而clazz是Method对象的getDeclaringClass()方法返回的,这里就是AbstractList$Itr没有问题 

obj是传入的iterator()方法返回的Iterator实现类对象也没有问题 

modifiers是1,也就代表是Public方法,并不是7楼老紫竹说的,hasNext确实是一个Public方法 

那么唯一可能出问题的就是第一个参数getCallerClass()返回的估计是Class T,而不是Class AbstractList$Itr类对象 

Java2000_net

原因我找到了,是package的问题,请看如下代码: 下面是3个模仿的类,用于测试,请注意其package为 a

package a;
public interface MyCollection {
  public MyIterator myIterator();
}
package a;
public interface MyIterator {
  public void myHasNext();
}
package a;
public class MyArrayList implements MyCollection {
  private class It implements MyIterator {
    public void myHasNext() {
      System.out.println("myHasNext method");
    }
  }

  public MyIterator myIterator() {
    return new It();
  }
}

下面是我的测试类

package b;
import java.lang.reflect.Method;
import a.MyArrayList;
import a.MyCollection;
import a.MyIterator;

public class TestInvoke {
  public static void main(String[] args) throws Exception {
    MyCollection t = new MyArrayList();
    MyIterator sam = t.myIterator();
    Method m = sam.getClass().getMethod("myHasNext");
    m.invoke(sam);
  }
}

请注意其package为b 运行结果为

Exception in thread "main" java.lang.IllegalAccessException: Class b.TestInvoke can not access a member of class a.MyArrayList$It with modifiers "public"
        at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at b.TestInvoke.main(TestInvoke.java:12)

 

如果你把测试类的放在和前面的3个类相同的package a 里面,则不会抱异常。

结论:

同包的可以调用。 不同包的比可以调用private的东西,虽然接口是public的







<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值