Dentro de las clases los atributos y las variables locales deben ser declaradas antes de su uso. Groovy utiliza los mismos modificadores que Java para modificar la visibilidad:
private
: sólo los miembros de la clase tienen acceso
protected
: pueden ser accedidos por las subclases
public
(valor por defecto): accesible desde otras clases
El modificador final
se usa para desactivar nuevas asignaciones y static
para denotar
variables de clase. Otro nombre para los atributos no estáticos es variables de instancia.
Dentro de las clases, no es obligatorio definir el tipo de una variable pero si que es obligatorio declararlo.
La palabra reservada def
es usada para declarar una variable para especificar que es del
tipo genérico Object. Veamos un ejemplo:
generaciondecodigos@nereida:~/Lgroovy/learning$ cat -n dec.groovy 1 class T { 2 def static int x = 4 3 def static String[] s = [ 1 .. 4 ]; 4 static Collection<?> c = [1, 2, "a"]; 5 def static y = x 6 7 public static void main(String[] args) { 8 println x 9 println y 10 println s 11 println c 12 } 13 }Obsérvese como Groovy ha realizado las conversiones adecuadas en todos los casos en los que ha sido necesario:
generaciondecodigos@nereida:~/Lgroovy/learning$ groovy dec.groovy 4 4 [1..4] [1, 2, a]
The unbounded wildcard aboveCollection<?>
indicates aCollection
which has an unknown object type.
Generic type parameters in Java are not limited to specific classes. Java
allows the use of wildcards to specify bounds on the type of parameters a
given generic object may have. Wildcards are type parameters of the form
?
.
La conversión ocurre de la forma que cabría esperar, en el siguiente ejemplo el entero es promocionado a un array de una String:
~/Lgroovy/learning$ cat dec2.groovy class T { def static int x = 4 def static String[] s = ( 1 .. 4 ).toList() public static void main(String[] args) { println s println s[0] println s[0].class println s.size() s = x println s println s[0] println s.class } }Sigue una ejecución:
~/Lgroovy/learning$ groovy dec2.groovy [1, 2, 3, 4] 1 class java.lang.String 4 [4] 4 class [Ljava.lang.String;
Sin embargo, esta otra asignación produce una excepción:
~/Lgroovy/learning$ cat -n dec3.groovy 1 class T { 2 def static int x = 4 3 def static String[] s = ['a', 'b'] 4 5 public static void main(String[] args) { 6 x = s 7 println x 8 } 9 }Ejecución:
~/Lgroovy/learning$ groovy dec3.groovy Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[Ljava.lang.String;@3a4c5b4' with class '[Ljava.lang.String;' to class 'java.lang.Number' at T.main(dec3.groovy:6)
Las asignaciones de expresiones a objetos de tipo numérico deben ser de tipo numérico:
generaciondecodigos@nereida:~/src/groovy/objects$ cat -n Conform.groovy 1 int a 2 try { 3 a = 'hello' 4 } 5 catch(e){ 6 println "Assignments to typed references must conform to the type" 7 }La ejecución muestra como se produce la ejecución del código que captura la excepción:
generaciondecodigos@nereida:~/src/groovy/objects$ groovy Conform.groovy Assignments to typed references must conform to the type
Si el objeto no esta tipado presenta una conducta polimorfa, aceptandose la asignación:
generaciondecodigos@nereida:~/src/groovy/objects$ cat -n Nontyped.groovy 1 def a 2 int b = 4 3 String c = 'hello' 4 Float d = 4.5 5 6 a = b 7 println a 8 9 a = c 10 println a 11 12 a = d 13 println aNinguna de las asignaciones a
a
produce un error:
generaciondecodigos@nereida:~/src/groovy/objects$ groovy Nontyped.groovy 4 hello 4.5
El siguiente ejemplo ilustra una variedad de declaraciones, incluyendo diversos modificadores:
generaciondecodigos@nereida:~/src/groovy/objects$ cat -n Declarations.groovy 1 class SomeClass { 2 public fieldWithModifier 3 String typedField 4 def unTypedField 5 protected field1, field2, field3 6 private assignedField = new Date() 7 8 static classField 9 10 public static final String CONSTA = 'a', CONSTB = 'b' 11 12 def someMethod() { 13 def localUntypedMethodVar = 1 14 int localtypedMethodVar = 1 15 def localVarWithoutAssignment, andAnotherOne 16 } 17 } 18 19 def localvar = 1 20 boundVar1 = 1 21 22 def someMethod() { 23 localMethodVar = 1 24 boundVar2 = 1 25 }La siguiente sesión con
groovysh
muestra las formas de acceso a algunos
de los entes definidos en la clase SomeClass
:
generaciondecodigos@nereida:~/Lgroovy/objects$ groovysh Groovy Shell (1.6.5, JVM: 1.6.0_0) Type 'help' or '\h' for help. ----------------------------- groovy:000> import Declarations ===> [import Declarations] groovy:000> a = new SomeClass() groovy:000> a.fieldWithModifier = 4 ===> 4 groovy:000> SomeClass.fieldWithModifier ERROR groovy.lang.MissingPropertyException: No such property: fieldWithModifier for class: SomeClass at groovysh_evaluate.run (groovysh_evaluate:3) ... groovy:000> SomeClass.classField = 'hola' ===> hola groovy:000> SomeClass.CONSTA ===> a groovy:000> SomeClass.CONSTA = 'c' ERROR groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: CONSTA for class: SomeClass at groovysh_evaluate.run (groovysh_evaluate:3) ... groovy:000> a.assignedField ===> Thu Feb 18 10:21:28 WET 2010 groovy:000> a.typedField = 'hola' ===> hola groovy:000> a.typedField = [1,2] ===> [1, 2] groovy:000> a.typedField.class ===> class java.lang.String groovy:000> (0..<a.typedField.size()).each { print "<${a.typedField[it]}> " }; println '' <[> <1> <,> < > <2> <]> ===> null
Obsérvese en el siguiente ejemplo
que el valor asignado a la variable de tipo cadena PI
no está entre comillas.
generaciondecodigos@nereida:~/src/groovy/objects$ cat -n Shouldfail.groovy 1 final String PI = 3.14 2 3 println "PI.class.name = ${PI.class.name}" 4 println "PI.length() = ${PI.length()}" 5 6 new GroovyTestCase().shouldFail(org.codehaus.groovy.runtime.typehandling.GroovyCastException) { 7 Float area = PI 8 } 9 10 try { 11 Float area = PI 12 } 13 catch(e){ 14 println "Assignments to typed references must conform to the type. ${e.class}" 15 } 16
La asignación deja en PI
la cadena "3.14"
.
La asignación de PI
a area
produce una excepción:
generaciondecodigos@nereida:~/src/groovy/objects$ groovy Shouldfail.groovy PI.class.name = java.lang.String PI.length() = 4 Assignments to typed references must conform to the type. class org.codehaus.groovy.runtime.typehandling.GroovyCastException
Un objeto GroovyTestCase
es construido en las líneas:
6 new GroovyTestCase().shouldFail(org.codehaus.groovy.runtime.typehandling.GroovyCastException) { 7 Float area = PI 8 }La clase GroovyTestCase provee una serie de métodos como
protected String shouldFail(Class clazz, Closure code) Asserts that the given code closure fails when it is evaluated and that a particular exception is thrown. protected String shouldFail(Closure code) Asserts that the given code closure fails when it is evaluated
que simplifican el proceso de pruebas JUnit.
JUnit is a unit testing framework for the Java programming language.
JUnit has been important in the development of test-driven development, and is one of a family of unit testing frameworks collectively known as xUnit based on the design by Kent Beck (the creator of Extreme Programming), originally implemented for Smalltalk as SUnit.
JUnit has been ported to many other languages.
Como JUnit
forma parte del entorno de ejecución Groovy, es posible
escribir pruebas JUnit
dentro de las clases
Groovy y Java utilizando la sintáxis de Groovy.
Casiano Rodríguez León