Почему ява не может найти мой метод? - PullRequest
2 голосов
/ 07 марта 2009

Я пытаюсь сосредоточиться на чем-то в Java. Когда я передаю объект в метод другого класса, могу ли я просто вызвать какие-либо методы, присущие этому классу объекта?

Какой код причины, например, приведенный ниже, не компилируется?

Спасибо,

class a {
  public static void myMethod(Object myObj) {
    myObj.testing();
  }
}


class b {
  public void testing() {
    System.out.println ("TESTING!!!");
  }
}


class c {  
  public static void main (String[] args) {
    b myB = new b();    
    a.myMethod(myB);  
  }
}

Edit: причина, по которой я оставил параметр в myMethod как тип Object, заключается в том, что я хотел бы иметь возможность передавать различные типы объектов, каждый из которых имеет метод test (). 1010 *

Ответы [ 8 ]

19 голосов
/ 07 марта 2009

Если вы хотите передать различные объекты с помощью методов testing(), пусть каждый объект реализует интерфейс Testable:

public interface Testable
{
   public void testing()
}

Тогда пусть myMethod() возьмет Testable.

public static void myMethod(Testable testable)
{
  testable.testing();
}

Редактировать: Чтобы уточнить, реализация интерфейса означает, что класс гарантированно имеет метод, но метод может делать все, что он хочет. Таким образом, у меня может быть два класса, чьи testing() методы делают разные вещи.

public class AClass implements Testable
{
   public void testing()
   {
      System.out.println("Hello world");
   }
}

public class BClass implements Testable
{
   public void testing()
   {
      System.out.println("Hello underworld");
   }
}
8 голосов
/ 07 марта 2009

Проблема в том, что myMethod не может знать, что получает объект b, пока он на самом деле не запустится. Вы могли бы передать String, потому что все это знает.

Измените его на

public static void myMethod(b myObj) {
  myObj.testing();
}

и должно работать.


Обновление вопроса:

Редактировать: причина, по которой я оставил параметр в myMethod как тип Object, заключается в том, что я хотел бы иметь возможность передавать различные типы объектов, каждый из которых имеет метод test ().

Как сказали Аманда С и несколько других, это идеальный случай для интерфейса. Способ сделать это - создать интерфейс, который определяет метод testing(), и изменить myMethod для получения объектов, реализующих этот интерфейс.

Альтернативным решением (без интерфейсов) было бы рефлексивно обнаружить, есть ли у объекта метод testing() и вызвать его, но это не рекомендуется и не требуется для такого простого случая.

6 голосов
/ 07 марта 2009

То, о чем вы говорите, - это утка. В Java нет утки.

Поэтому вам необходимо определить интерфейс, который реализуют все классы с помощью метода testing().

например:

public interface Testable
{
   public void testing()
}

class B implements Testable 
{
  public void testing() {
    System.out.println ("TESTING!!!");
  }
}

class A {
  public static void myMethod(Testable myObj) {
    myObj.testing();
  }
}
4 голосов
/ 07 марта 2009

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

public interface Testable
{
  public void testing();
}

public class A
{
  public static void myMethod(Testable myObj)
  {    
    myObj.testing();
  }
}

public class B implements Testable
{
  public void testing()
  {
    System.out.println("This is class B");
  }
}

public class C implements Testable
{
  public void testing()
  {
    System.out.println("This is class C");
  }
}

public class Test
{  
  public static void main (String[] args) 
  {
    B myB = new B();
    C myC = new C();
    A.myMethod(myB); // "This is class B"
    A.myMethod(myC); // "This is class C" 
  }
}
2 голосов
/ 07 марта 2009

Потому что вы передаете объект (b наследовать от объекта). У объекта нет тестирования, у b -.

Вы можете передать b или привести объект к b перед вызовом метода.

EDIT Чтобы передать общий класс, который реализует этот метод: вам нужно создать интерфейс с сигнатурой метода и передать тип интерфейса вместо Object. Все объекты, которые вы передаете, должны реализовывать интерфейс.

1 голос
/ 07 марта 2009

Почему я не могу найти мой метод?

Из-за способа, которым была разработана Java.

Java "статически типизирован" , что означает, что типы объектов проверяются во время компиляции.

В Java вы можете вызывать метод, только если этот метод принадлежит этому типу.

Так как эта проверка выполняется во время компиляции и тип объекта не имеет метода «testing ()», компиляция завершается неудачно (даже если во время выполнения объекты имеют этот метод ». Это в первую очередь для безопасности.

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

«Эй, экземпляры этого типа будут отвечать на метод тестирования»

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

public interface Testable { 
    public void testing();
}

class A implements Testable { // here this class commits to respond to "testing" message 
    public void testing() {
    }
}

class B implements Testable { // B "is" testable 
    public void testing() { 
        System.out.println("Testing from b");
    } 
}


class C implements Testable { // C is... etc. 
    public void testing() { 
        //.... 
    }
}

Позже где-то еще

public void doTest( Testable object ) { 
    object.testing();
}

doTest( new A() );
doTest( new B() );
doTest( new C() );

"ДРУГОЙ" способ сделать это, в Java вызывает методы рефлексивно , но я не уверен, что это то, что вам нужно, потому что код гораздо более абстрактный, когда вы делаете это, что Да, но именно так на самом деле работают фреймворки автоматизированного тестирования (и многие другие фреймворки, такие как Hibernate).

Надеюсь, это поможет вам выяснить причину.

1 голос
/ 07 марта 2009

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

В случае myMethod(Object myObj) это означает только элементы, определенные в Object, поэтому в class a элементы class b не будут видны.

Если вы изменили определение a.myMethod на public static void myMethod(b myObj), вы сможете увидеть метод testing в экземпляре b в myMethod.

обновление на основе уточнения:

В этом случае определение интерфейса для реализации всеми из них, скорее всего, то, что вам нужно.

public interface Testable {
    public void testing();
}

public class a {
    public static void myMethod(Testable myObj) {
        myObj.testing();
    }
}

public class b implements Testable {
    public void testing () {
        System.out.println("TESTING!!!");
    }
}
0 голосов
/ 07 марта 2009

Если вы ДЕЙСТВИТЕЛЬНО, ДЕЙСТВИТЕЛЬНО хотите сохранить параметр как можно более абстрактным, вам следует подумать об API отражения. Таким образом, вы можете передать любой объект и динамически выполнить нужный метод. Вы можете взглянуть на некоторые примеры .

Это не единственный способ, но это может быть верной альтернативой в зависимости от вашей проблемы.

Имейте в виду, что рефлексия намного медленнее, чем прямой вызов ваших методов. Вы также можете подумать об использовании интерфейса, такого как на посту Аманды.

...