2015-11-20 18 views
6


Ich möchte eine Klasse erstellen, die ein Objekt aus anonymer Klassendefinition zum Speichern erhält. Ich habe eine generische typisierte Klasse verwendet, um das zu erreichen. Dann möchte ich einige Operationen definieren, die funktionale Schnittstellen verwenden, die dieses Objekt als einen Parameter erhalten, mit dem ich arbeiten kann.
Code sagt mehr als Worte. So haben Sie einen Blick auf diese:anonyme Klasse als generischer Parameter

public class Test<T> { 
    @FunctionalInterface 
    public interface operation<T> { 
     void execute(T object); 
    } 
    private T obj; 
    public Test(T _obj){ 
     obj = _obj; 
    } 
    public void runOperation(operation<T> op){ 
     op.execute(obj); 
    } 

    public static void main(String[] args){ 
     Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }); 
     t.runOperation((o) -> { 
      System.out.println(o.text); // text cannot be resolved 
     }); 
    } 
} 

Mein Problem ist, dass o.text bei der Umsetzung der funktionalen Schnittstelle kann nicht aufgelöst werden. Ist das eine Art von Löschungsfolge?
Die interessante Sache ist, dass ich diesen Code arbeiten kann, wenn ich die funktionale Schnittstelle im Konstruktor implementiere.
Werfen Sie einen Blick auf diesen Code:

public class Test<T> { 
    @FunctionalInterface 
    public interface operation<T> { 
     void execute(T object); 
    } 
    private T obj; 
    private operation<T> op; 

    public Test(T _obj, operation<T> _op){ 
     obj = _obj; 
     op = _op; 
    } 
    public void runOperation(){ 
     op.execute(obj); 
    } 
    public static void main(String[] args){ 
     Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }, (o) -> { 
      System.out.println(o.text); 
     }); 
     t.runOperation(); 
    } 
} 

Diese perfekte und druckt "Something" funktioniert. Aber was ist los mit meiner ersten Annäherung? Ich verstehe das Problem hier wirklich nicht.

+0

neues Objekt() { public String text = "Etwas"; }) – GKislin

Antwort

1

In dem zweiten Teil des Codes,

new Test<>(new Object(){ 
     public String text = "Something"; 
    }, (o) -> { 
     System.out.println(o.text); 
    }); 

kompiliert, da der Typ Argument Test für den Konstruktoraufruf (da der Diamant-Operator verwendet wird) abgeleitet wird, und es wird die anonymen gefolgert Geben Sie ein, dass das erste Argument ausgewertet wird (der anonyme Klassentyp), und daher der Typ des zweiten Arguments operation<that anonymous class type>, was funktioniert.

Im ersten Teil des Codes, der Ausdruck

t.runOperation((o) -> { 
     System.out.println(o.text); // text cannot be resolved 
    }) 

nicht kompiliert. Hier wird der Typ des Lambda basierend auf dem Typ der Variablen t, die Test<?> ist, abgeleitet. Daher muss das Argument runOperationoperation<some unknown type> sein. Das einzige Argument zu runOperation, das hier funktioniert, ist null.

1
Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }, (o) -> { 
      System.out.println(o.text); 
     }); 

Der Compiler ist hier T in Test mit Ihrer anonymen Klasse zu ersetzen, und da diese Klasse enthält eine Variable text Deshalb ist der zweite Fall funktioniert.

+0

Ok, aber warum ersetzt der Compiler T im ersten Fall nicht durch meine anonyme Klasse? – ArcticLord

+0

Es tut, aber der Typ Ihrer anonymen Klasse ist "Objekt", die keine Eigenschaft namens "Text" hat, so erhalten Sie den Kompilierungsfehler. –

2

Das Problem besteht darin, dass Ihre anonyme Klasse noch einem Typ entsprechen muss (erweitern oder implementieren) und der von Ihnen gewählte Typ ist Object, der Ihre text-Eigenschaft nicht enthält. Um auf bestimmte Eigenschaften zu verweisen, benötigen Sie eine tatsächliche Klasse oder Schnittstelle, mit der Sie arbeiten können. Der Compiler kann also garantieren, welche Eigenschaften und Methoden für das Objekt verfügbar sind.

Das funktioniert.

public class Test<T> { 

    public static class Data { 
     public String text; 
    } 

    @FunctionalInterface 
    public interface Operation<K> { 
     void execute(K object); 
    } 

    private T obj; 
    private Operation<T> op; 

    public Test(T obj) { 
     this.obj = obj; 
    } 

    public void runOperation(Operation<T> op) { 
     op.execute(obj); 
    } 

    public static void main(String[] args) { 
     Test<Data> t = new Test<>(new Data() {{ 
      this.text = "Something"; 
     }}); 

     t.runOperation((o) -> { 
      System.out.println(o.text); 
     }); 
    } 
}