Java Reflection,java.lang.IllegalAccessException错误

时间:2010-04-04 15:36:18

标签: java reflection

我的目标是:

第三类将从控制台读取类的名称作为String。读取类的名称后,它将自动动态地(!)生成该类并调用其writeout方法。如果未从输入中读取该类,则不会对其进行初始化。

我正在犯java.lang.IllegalAccessException: Class deneme.class3 can not access a member of class java.lang.Object with modifiers "protected"错误。而且我不知道怎么能解决它.. 任何人都可以帮助我吗?

import java.io.*;

import java.lang.reflect.*;


 class class3
{

    public void run()
      {
        try
        {    
            BufferedReader reader= new BufferedReader(new InputStreamReader(System.in)); 

              String line=reader.readLine();

              Class c1 = Class.forName("java.lang.String");
              Object obj = new Object();
              Class c2 = obj.getClass();

              Method writeout = null; 
              for( Method mth : c2.getDeclaredMethods() ) {                  
                     writeout = mth; 
                     break;                  
              } 
              Object o = c2.newInstance(); 
              writeout.invoke( o );              

        }
        catch(Exception ee)
        {
       System.out.println("ERROR! "+ee);
        }

        }

  public void writeout3()
  {
      System.out.println("class3");
  }
      }

class class4
{
  public void writeout4()
  {
    System.out.println("class4");
  }
}

class ornek {


    public static void main(String[] args) {
       System.out.println("Please Enter Name of Class : ");
       class3 example = new class3();
       example.run();               
    }
}

5 个答案:

答案 0 :(得分:3)

你准备执行什么功能? 在我看来,你只是选择了第一种方法而没有实际检查它是什么。 尝试选择一种公开的特定方法。

答案 1 :(得分:1)

目前还不清楚你在代码中做了什么。

看起来,首先你声明c1 java.lang.String而不使用它..然后你加载一个新的java.lang.Object,通过它声明的方法然后你选择第一个找到的方法作为writeout,你试图在不知道你在呼唤什么的情况下调用它。

要做你试图解释的事情我建议你:

使用您想要动态调用的方法定义Invokable之类的接口,例如

interface Invokable {
  public void invokeMe();
}

然后,无论何时通过加载名称生成新类,您都可以将其强制转换为接口并调用该方法而不会发疯:

Class<?> class = Class.forName("your.YourClass");
Object target = class.newInstance();

if (target instanceof Invokable)
 ((Invokable)target).invokeMe();

(当然YourClass必须实现Invokable接口)

这种方法清楚地定义了程序能够动态实例化的内容以及允许对这些对象执行的操作,而不必担心搜索方法或允许发生奇怪的事情。

答案 2 :(得分:1)

这是您的代码中最明显的问题:

Method writeout = null; 
for( Method mth : c2.getDeclaredMethods() ) {                  
   writeout = mth; 
   break;                  
} 

您只是抓住c2的第一个声明方法,即Object.class。谁知道方法是什么? (顺便说一下,在我的情况下,它是protected void java.lang.Object.finalize() throws java.lang.Throwable

另一个问题是:

String line=reader.readLine();
// presumably you're reading the name of the class to find here...

Class c1 = Class.forName("java.lang.String");
// why do you need String.class? what is c1 used for?

Object obj = new Object();
Class c2 = obj.getClass();
// so now c2 is Object.class? what are you trying to accomplish?

大概你可能想要这样做:

  1. 阅读要查找的课程名称
  2. 使用Class.forName
  3. 查找该课程
  4. 反映该课程以查找writeout*方法
  5. 这意味着:

    String line = reader.readLine();
    
    Class<?> writeoutClass = Class.forName(line);
    
    Method writeout = null;
    for (Method mth : writeoutClass.getDeclaredMethods()) {
        if (mth.getName().startsWith("writeout")) {
            writeout = mth;
            break;
        }
    }
    
    Object o = writeoutClass.newInstance();
    writeout.invoke(o);
    

    这将打印"class3""class4",具体取决于您输入的类名。您需要使其更加健壮,但它说明了这一想法。


    应该提到的是,如果可能的话,你应该创建这些动态创建的类型implements SomeInterface(参见杰克的回答)。另请阅读 Effective Java 2nd Edition ,第53项:首选接口到反射。

答案 3 :(得分:0)

看起来它会尝试调用Object的第一个方法。似乎已经选择了clone。这将需要setAccessible(true)。您的代码可能还有其他问题。

答案 4 :(得分:0)

以上似乎对我很困惑。没有顺序:

  1. 您没有使用在标准输入
  2. 上输入的班级名称
  3. 您正在通过forName()加载课程,但这不是您在上面指定的课程
  4. 您应该使用writeout()或类似方法找到该类的getDeclaredMethods()方法。
  5. 简而言之,我认为您需要加载某人在命令行中指定的类,实例化实例,然后调用方法所需的所有方法/ API。只是在您的类加载/方法位置没有执行上述操作时。