2012-03-25 3 views
7

Ich versuche Scala zu lernen, also habe ich beschlossen, Datenstrukturen damit zu implementieren. Ich habe mit dem Stack begonnen. Ich habe die folgende Stapelklasse erstellt.Versuch, eine Scala erstellte Klasse in Java zu initialisieren

class Stack[A : Manifest]() { 

    var length:Int = -1 
    var data = new Array[A](100) 

    /** 
    * Returns the size of the Stack. 
    * @return the size of the stack 
    */ 
def size = {length} 

    /** 
    * Returns the top element of the Stack without 
    * removing it. 
    * @return Stacks top element (not removed) 
    */ 
    def peek[A] = {data(length)} 

    /** 
    * Informs the developer if the Stack is empty. 
    * @return returns true if it is empty else false. 
    */ 
    def isEmpty = {if(length==0)true else false} 

    /** 
    * Pushes the specified element onto the Stack. 
    * @param The element to be pushed onto the Stack 
    */ 
    def push(i: A){ 
    if(length+1 == data.size) reSize 
    length+=1 
    data(length) = i; 
    } 

    /** 
    * Pops the top element off of the Stack. 
    * @return the pop'd element. 
    */ 
    def pop[A] = { 
    length-=1 
    data(length) 
    } 

    /** 
    * Increases the size of the Stack by 100 indexes. 
    */ 
    private def reSize{ 
    val oldData = data; 
    data = new Array[A](length+101) 
    for(i<-0 until length)data(i)=oldData(i) 
    } 
} 

Ich versuche dann, diese Klasse in meiner Java-Klasse zu initialisieren, mit den folgenden

Stack<Integer> stack = new Stack<Integer>(); 

Aber ich habe gehört, dass der Konstruktor nicht existiert und dass ich ein Argument hinzufügen Übereinstimmen Manifest. Warum passiert das und wie kann ich das beheben?

Antwort

18

Alexey gab Ihnen die richtige Erklärung, aber es ist definitiv möglich, Manifest in Ihrem Code zu erstellen (Sie brauchen nur ein java.lang.Class Objekt, das Sie einfach in Java erstellen können).

Zuerst sollten Sie eine Java-freundliche Factory-Methode zu dem Begleitobjekt der Stapel hinzufügen:

object Stack { 
    def ofType[T](klass: java.lang.Class[T]) = { 
    val manifest = new Manifest[T] { 
     def erasure = klass 
    } 
    new Stack()(manifest) 
    } 
} 

Diese Methode das entsprechende Manifest erzeugt wird (von einer Java-Klasse) und übergeben es ausdrücklich auf die Stack Konstruktor. Sie können es dann ohne Schmerzen von Java verwenden:

Stack<String> stack = Stack.ofType(String.class); 
stack.push("Hello"); 
stack.push("World"); 

System.out.println(stack.size()); 
System.out.println(stack.peek()); 
9

Dies passiert, weil ein Kontext wie [A : Manifest] nur eine Abkürzung für ein implizites Konstruktorargument ist. Ihre Klasse ist also "wirklich" als class Stack[A]()(implicit m: Manifest[A]) { deklariert. Da die einzige Möglichkeit, ein Manifest zu erstellen, Compiler-Magie ist (soweit ich weiß), können Sie es nicht von Java aus tun und können dort kein Stack konstruieren.

Sie können entweder den Entwurf ändern, um Manifeste zu vermeiden, oder Instanzen von Stack in Scala-Code erstellen und diese nur aus Java verwenden.

+1

+1 für die Erklärung, aber es ist möglich, 'Manifest' ohne Compiler Magie zu erstellen. Siehe meine Antwort. – paradigmatic

2

auf paradigmatische Antwort Follow-up, können Sie auch einen Konstruktor für die Klasse erstellen:

class Stack[A](implicit m: Manifest[A]) { 

def this(clazz : Class[A]) { 
    this()(new Manifest[A] { 
    def erasure = clazz 
    }) 
} 

, die dann von Java aufgerufen werden kann:

Dennoch wird das Problem mit generischen Typen wie Stacks von Strings Stacks haben. Dafür sollten Sie in diesen Thread schauen: http://www.scala-lang.org/node/7267

Verwandte Themen