Невозможно получить доступ к методу анонимного класса в Java

Я получаю сообщение об ошибке компилятора всякий раз, когда пытаюсь вызвать метод, принадлежащий анонимному классу, из внешнего класса. Пример:

public class Test {

    public static void main(String[] args) {
        Test testObj = new Test(){
            public void doStuff(){
                System.out.println("Test");
            }
        };
        testObj.doStuff();
    }
}

Компилятор выдает ошибку: «Не удается найти символ — doStuff()». Должно быть, я что-то упускаю из виду... есть идеи?

Заранее спасибо.


person Polymorph    schedule 12.06.2015    source источник


Ответы (5)


Вы можете вызывать существующий метод только из класса Reference of Test. Итак, если вы объявили метод doStuff(), то только вы можете вызвать его со ссылкой Test testObj.

См. этот вопрос SO Можно ли вызывать подклассы ' методы объекта суперкласса?

Но вы, безусловно, можете вызвать новый метод внутри другого объявления метода анонимного класса. См. пример ниже.

Пример:

public class Test {
    public void doStuff() {
        System.out.println("Test");
    }

    public static void main(String[] args) {
        Test testObj = new Test() {
            public void doStuff() {
                System.out.println("Inside anonymous class doStuff");
                doOtherStuff(); // calling new method doOtherStuff() and it works
            }

            public void doOtherStuff() {
                System.out.println("Inside anonymous class doOtherStuff");
            }
        };
        testObj.doStuff();

        /*Below code give compilation error: The method doOtherStuff() is undefined for the type Test*/
        // testObj.doOtherStuff();
    }
}

Вывод:

Inside anonymous class doStuff
Inside anonymous class doOtherStuff
person Naman Gala    schedule 12.06.2015
comment
Я так не думаю... вы всегда можете создавать новые методы в анонимном классе. Только то, что вы не сможете вызвать его со ссылкой на суперкласс. - person Codebender; 12.06.2015
comment
@AbishekManoharan Итак, с анонимными классами вы в значительной степени ограничены назначением им типа их суперкласса. Другими словами, у них не может быть собственного типа, верно? - person Polymorph; 12.06.2015
comment
Нет, они не могут... Но это не значит, что новые методы бесполезны. См. обновленный ответ, где он используется. - person Codebender; 12.06.2015
comment
Анонимные классы @Polymorph имеют свой собственный тип, но этот тип недоступен для вас по имени (следовательно, он анонимный). Но он доступен напрямую. Смотрите мой ответ на этот вопрос. - person Erwin Bolwidt; 13.06.2015

Java — это типизированный язык. Когда у вас есть объект класса Test (которым вы объявили testObj), компилятор позволит вам вызывать только методы, определенные в классе Test. Даже если у вас есть экземпляр подкласса, компилятор не выведет его автоматически, поэтому он не позволит вам вызывать методы подкласса. Это происходит только по типу переменной.

Вам нужно определить метод doStuff в вашем классе Test.

Конечно, это делает глупым создание подкласса анонимно, если только вы не хотите переопределить метод, чтобы сделать что-то еще.

person Thilo    schedule 12.06.2015

Проблема в том, что анонимный класс не имеет имени типа (поэтому он и называется анонимным).

Вы присвоили экземпляр анонимного класса переменной типа Test, а тип Test не имеет метода с именем doStuff.

Таким образом, вы не можете присвоить экземпляр анонимного класса любой переменной, а затем вызвать для него метод, который не определен в суперклассе.

Однако можно вызвать метод, если вы не присвоите его:

public class Test {

    public static void main(String[] args) {
        new Test(){
            public void doStuff(){
                System.out.println("Test");
            }
        }.doStuff();
    }
}

Обратите внимание, что существует несколько ситуаций, в которых это полезно в реальной программе Java.

Я просто показываю это, чтобы подчеркнуть источник проблемы: анонимным классам, безусловно, разрешено иметь методы, которые не определены в суперклассе, и единственная причина, по которой вы не можете легко вызвать их, заключается в том, что тип класса анонимный ( не имеет имени). Но они по-прежнему существуют и могут быть вызваны непосредственно в экземпляре.

person Erwin Bolwidt    schedule 12.06.2015

Проблема сводится к тому, в чем разница между ссылочной переменной и объектом. Переменная testObj имеет тип Test, и у Test нет метода doStuff, он есть только у вашего анонимного класса, но хотя компилятор может создать объект анонимного типа, он не может создать переменную анонимного типа. Суть в том, что вы не должны использовать анонимные типы для этого типа кода, кода, в котором дочерний класс имеет методы, которых нет в родительском классе. Вместо этого либо дайте родительскому классу метод (здесь дайте Test метод doStuff), либо рассмотрите возможность использования частного внутреннего класса вместо вашего анонимного класса.

person Hovercraft Full Of Eels    schedule 12.06.2015

В классе Test нет метода doStuff(). Когда вы создали свой анонимный класс, вы добавили новый метод с именем doStuff(). Затем вы сохраняете эту ссылку как тип Test, который не может получить доступ к дополнительному методу.

Почему вы используете такой анонимный класс?

Самый простой способ — просто добавить метод doStuff() для проверки

public class Test {

     public void doStuff(){
          System.out.println("Test");
     }

    public static void main(String[] args) {
        Test testObj = new Test();
        testObj.doStuff();
    }
}
person dkatzel    schedule 12.06.2015
comment
Спасибо за ваш ответ. Мой пример не должен был быть практичным, я знал, что мог бы легко добавить метод doStuff() непосредственно в класс Test. Цель состояла в том, чтобы лучше понять анонимные классы. Итак, если я правильно понимаю сейчас: я могу запускать методы только для объекта анонимного класса, если я переопределяю их из родительского класса? - person Polymorph; 12.06.2015
comment
@Polymorph - нет, вы можете запускать методы в анонимном классе, если этот метод является видимым методом для объекта, на который вы можете ссылаться или на который можно привести. Это не должно быть переопределено. Конечно, другие методы в анонимном классе могут быть выполнены, если они также вызываются этими другими методами. - person dkatzel; 12.06.2015