2012-03-25 25 views
7

Estoy intentando aprender Scala, así que he decidido implementar las estructuras de datos con él. Empecé con la Pila. Creé la siguiente clase de Pila.Intento de inicializar una clase creada por Scala en Java

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

que luego intentar inicializar esta clase en mi clase de Java utilizando la siguiente

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

Sin embargo, me han dicho que el constructor no existe y que yo debería añadir un argumento para que coincida Manifiesto. ¿Por qué sucede esto y cómo puedo solucionarlo?

Respuesta

18

Alexey te dio la explicación correcta, pero definitivamente es posible crear un manifiesto en tu código (solo necesitas un objeto java.lang.Class, que puedes crear fácilmente en Java).

En primer lugar se debe añadir un método de fábrica java-amigable con el objeto acompañante de Pila:

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

Este método genera el manifiesto apropiada (de una clase Java) y lo pasará explícitamente a la Stack constructor. A continuación, puede utilizarlo desde Java sin dolor:

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

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

Esto sucede porque un contexto enlazado como [A : Manifest] es solo una abreviatura de un argumento de constructor implícito. Entonces su clase es "realmente" declarada como class Stack[A]()(implicit m: Manifest[A]) {. Entonces, dado que la única forma de crear un Manifest es la magia del compilador (hasta donde yo sé), no se puede hacer desde Java y no se puede construir un Stack allí.

Puede cambiar el diseño para evitar manifiestos, o crear instancias de Stack en código Scala y solo usarlas desde Java.

+1

+1 para la explicación, pero es posible crear el 'Manifiesto' sin la magia del compilador. Ver mi respuesta – paradigmatic

2

Dar seguimiento a la respuesta paradigmático, también puede crear un constructor para la clase:

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

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

que se puede llamar entonces a partir de Java:

Stack<Integer> s = new Stack<Integer>(Integer.class); 
s.push(1); 
System.out.println(s.peek()); 

Sin embargo, el problema será con tipos genéricos como tener pilas de pilas de cadenas. Para esto deberías mirar este hilo: http://www.scala-lang.org/node/7267

Cuestiones relacionadas