Domanda

Sto cercando di avvolgere la mia mente intorno a qualcosa in Java. Quando passo un oggetto a un metodo di un'altra classe, non posso semplicemente chiamare alcun metodo inerente a quella classe di oggetti?

Qual è il codice motivo come nell'esempio seguente non viene compilato?

Grazie

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);  
  }
}

Modifica: il motivo per cui ho lasciato il parametro in myMethod come tipo Object è perché vorrei poter passare una varietà di tipi di oggetti, ognuno con un metodo testing ().

È stato utile?

Soluzione

Se desideri passare una varietà di oggetti con i metodi testing () , chiedi a ciascun oggetto di implementare un'interfaccia Testable :

public interface Testable
{
   public void testing()
}

Quindi fai in modo che myMethod () prenda un Testable .

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

Modifica: per chiarire, l'implementazione di un'interfaccia significa che la classe ha il metodo, ma il metodo può fare quello che vuole. Quindi potrei avere due classi i cui metodi testing () fanno cose diverse.

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");
   }
}

Altri suggerimenti

Il problema è che myMethod non può sapere che sta ottenendo un oggetto b fino a quando non viene effettivamente eseguito. Potresti passare una String , per quanto ne sa.

Cambialo in

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

e dovrebbe funzionare.


Aggiornamento della domanda:

  

Modifica: il motivo per cui ho lasciato il parametro in myMethod come tipo Object è perché vorrei poter passare una varietà di tipi di oggetti, ognuno con un metodo testing ().

Come hanno detto Amanda S e molti altri, questo è un caso perfetto per un'interfaccia. Il modo per farlo è creare un'interfaccia che definisca il metodo testing () e cambiare myMethod per prendere oggetti che implementano quell'interfaccia.

Una soluzione alternativa (senza interfacce) sarebbe quella di scoprire in modo riflessivo se l'oggetto ha un metodo testing () e chiamarlo, ma questo non è raccomandato e non necessario per un caso così semplice.

Quello di cui stai parlando è la digitazione di anatre. Java non ha la tipizzazione anatra.

Pertanto è necessario definire un'interfaccia che tutte le classi con un metodo testing () implementano.

per esempio:

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();
  }
}

Il tuo problema è un argomento classico a favore di un'interfaccia. Vuoi il più generico possibile, ma vuoi che ogni oggetto che passi abbia un metodo testing (). Suggerisco qualcosa sulla falsariga di quanto segue:

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" 
  }
}

Perché stai passando un oggetto (b eredita dall'oggetto). L'oggetto non ha test, b lo fa.

Puoi passare in b o lanciare l'oggetto su b prima di chiamare il metodo.

EDIT Per passare a una classe generica che implementa quel metodo: ti consigliamo di creare un'interfaccia con la firma del metodo e passare il tipo di interfaccia anziché Oggetto. Tutti gli oggetti che passi devono implementare l'interfaccia.

Puoi accedere solo ai membri visibili per il tipo di riferimento che hai sull'oggetto.

Nel caso di myMethod (Object myObj) ciò significa solo i membri definiti in Object, quindi in class a i membri di class b non sarà visibile.

Se hai modificato la definizione di a.myMethod in nullo statico pubblico myMethod (b myObj) , potresti quindi vedere il testing sull'istanza di b mentre si è in myMethod .

aggiornamento basato su chiarimenti:

In tal caso, definire un'interfaccia che tutti possano implementare è probabilmente ciò che desideri.

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!!!");
    }
}
  

Perché java non riesce a trovare il mio metodo?

A causa del modo in cui è stato progettato Java.

Java è " digitato staticamente " che significa che i tipi di oggetti vengono controllati durante compilazione.

In Java puoi invocare un metodo solo se quel metodo appartiene a quel tipo.

Poiché questa verifica viene effettuata durante la compilazione e il tipo di oggetto non ha il "quoting testing ()" metodo, la compilazione non riesce (anche se in fase di esecuzione gli oggetti dispongono di quel metodo ". Questo è principalmente per la sicurezza.

La soluzione alternativa descritta da altri richiederà la creazione di un nuovo tipo, in cui è possibile indicare al compilatore

" Ehi, le istanze di questo tipo risponderanno al metodo di test "

Se vuoi passare una varietà di oggetti e mantenerli molto generici, un modo è avere quegli oggetti da implementare e interfacciare.

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() { 
        //.... 
    }
}

Più tardi altrove

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

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

Il " ALTRO " modo per farlo, in java è invocare i metodi riflettentemente , ma non sono sicuro che sia quello che ti serve, perché il codice è molto più astratto quando lo fai in quel modo, ma è così che funzionano i framework di test automatizzati (e molti altri framework come Hibernate).

Spero che questo ti aiuti a chiarire il motivo.

Se vuoi VERAMENTE, REALMENTE mantenere il parametro il più astratto possibile, dovresti considerare l'API di riflessione. In questo modo, puoi passare qualsiasi oggetto tu voglia ed eseguire dinamicamente il metodo che desideri. Puoi dare un'occhiata a alcuni esempi .

Non è l'unico modo, ma potrebbe essere una valida alternativa a seconda del problema.

Tieni presente che la riflessione è molto più lenta della chiamata diretta dei tuoi metodi. Potresti considerare di utilizzare anche un'interfaccia, come quella sul post di Amanda.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top