2010-05-12 40 views
6

en Scala que iba a escribir una clase abstracta con un atributo abstracto path:atributos abstractos en Java

abstract class Base { 

    val path: String 

} 

class Sub extends Base { 

    override val path = "/demo/" 

} 

Java no sabe atributos abstractos y me pregunto cuál sería la mejor manera de solucionar este limitación.

Mis ideas:

a) de parámetros constructor

abstract class Base { 

    protected String path; 

    protected Base(String path) { 
    this.path = path; 
    } 

} 

class Sub extends Base { 

    public Sub() { 
     super("/demo/"); 
    } 

} 

b) método abstracto

abstract class Base { // could be an interface too 

    abstract String getPath(); 

} 

class Sub extends Base { 

    public String getPath() { 
     return "/demo/"; 
    } 

} 

¿Cuál te gusta más? ¿Otras ideas?

Tiendo a utilizar el constructor ya que el valor de la ruta no se debe calcular en tiempo de ejecución.

+0

Advertencia: b) no se compila. Necesita agregar el modificador 'abstracto' al método abstracto. – BalusC

+0

Pregunta relacionada: http://stackoverflow.com/questions/2371025/abstract-variables-in-java – BalusC

+1

FYI: Scala se ejecuta en la JVM, que no admite campos abstractos, por lo que Scala básicamente utiliza métodos abstractos internamente. – RoToRa

Respuesta

5

Lo Scala hace internamente es lo que usted está describiendo como el método B.

Tomemos el siguiente ejemplo de clase:

abstract class Test{ 
    val path: String 
} 

Al compilar esto con scalac, generará una clase Java abstracto con una método abstracto llamado attr que devuelve una cadena. La razón por la que esto puede suceder es porque un valor constante es constante y, como tal, solo puede ser emulado por un getter y un setter. Entonces, si desea acceder a esta clase desde Java, puede simplemente anular el método get get abstracto.

Este es el equivalente de la clase Java que será producido (salida de javap):

public abstract class Test extends java.lang.Object implements scala.ScalaObject{ 
    public abstract java.lang.String path(); 
    public Test(); 
} 
1

Si el path nunca cambia, iría por la opción a, de lo contrario iría por la opción b.

Otro aspecto es que el valor de path puede no estar disponible en el momento de la construcción. En ese caso, la opción a es descartada. Sin embargo, en comparación con su código Scala, parece que path está disponible en el momento de la construcción.

+0

Sí, 'ruta' está disponible en tiempo de compilación. ¿Por qué preferirías la opción b) si la ruta fuera inmutable? – deamon

+0

Dejar que la subclase invalide 'getPath' parece algo razonable que hacer si la ruta se puede calcular de manera diferente a veces. Una subclase futura podría, por ejemplo, querer leer la ruta desde un archivo de configuración que cambia durante el tiempo de ejecución o algo así, y entonces no tiene sentido tener una variable protegida para él. – aioobe

0

Puede intentar crear un método protected para establecer el valor de la variable. Solo se puede llamar desde clases en el mismo paquete.

+1

Pero el compilador no haría cumplir para llamar a este método en una subclase, por lo que el valor podría dejarse sin inicializar. – deamon

0

Elegiría la opción b porque, si por alguna razón, una ruta depende de otros atributos, entonces no es realmente agradable establecer el atributo en la superclase cada vez que cambia otro atributo. Si tiene que implementar el captador, entonces no hay problema. No puedo pensar en ningún caso específico donde la opción a sea más útil.

1

El equivalente es B ya que los valores es fijo.

Opción A recibe la ruta en el constructor, y que el valor puede ser calculada en tiempo de ejecución que no es lo que se goind la clase Sub en el ejemplo Scala.

0

Cualquiera de las dos cosas está bien, el parámetro de constructor es probablemente más simple si nunca va a haber ningún cálculo involucrado (en cuyo caso puede querer hacer el campo final, que tendrá la ventaja adicional de asegurarse de que sea otro constructores que pueden agregarse más tarde); mientras que el método abstracto te da más libertad para cambiar las cosas en el futuro.

También podría combinar los dos, y tener un campo privado configurado en el constructor y proporcionar una implementación concreta (pero no definitiva) del getter que accede a él.

Cuestiones relacionadas