Отражение Java, ошибка java.lang.IllegalAccessException - PullRequest
2 голосов
/ 04 апреля 2010

Моя цель:

Третий класс будет читать имя класса как String из консоли. При чтении имени класса он автоматически и динамически (!) Генерирует этот класс и вызывает его метод записи. Если этот класс не читается из ввода, он не будет инициализирован.

И я принимаю 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 ]

3 голосов
/ 04 апреля 2010

какую функцию вы пытаетесь выполнить точно? мне кажется, что вы просто выбираете первый метод, фактически не проверяя, что это такое. попробуйте выбрать определенный метод, который является общедоступным.

1 голос
/ 04 апреля 2010

Это самая вопиющая проблема с вашим кодом:

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. Подумайте над этим классом , чтобы найти writeout* метод

Это означает что-то вроде этого:

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: Предпочитайте интерфейсы отражению.

1 голос
/ 04 апреля 2010

Непонятно, что вы делаете в своем коде.

Похоже, сначала вы объявляете 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)

Этот подход четко определяет, что программа сможет создавать экземпляры динамически и что вам разрешено делать с этими объектами, не беспокоясь о поиске методов или допуская странные вещи ..

0 голосов
/ 04 апреля 2010

Вышесказанное кажется мне очень запутанным. Без заказа:

  1. вы не используете имя класса, введенного в стандартный ввод
  2. вы загружаете класс через forName(), но это не тот, который вы указали в 1. выше
  3. вы должны найти метод writeout() этого класса, используя getDeclaredMethods() или аналогичный.

Короче говоря, я думаю, что у вас есть все необходимые методы / API, необходимые для загрузки класса, который кто-то указывает в командной строке, создания экземпляра и вызова метода. Просто в данный момент загрузка вашего класса / местоположение метода не выполняет вышеуказанное.

0 голосов
/ 04 апреля 2010

Похоже, он попытается вызвать первый метод Object. Кажется, поднял clone. Это потребует setAccessible(true). Возможно, есть другие проблемы с вашим кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...