Groovy implements a comprehensive type system that allows developers to define items as specific types and convert these items into other types as necessary. The Groovy type system implements inclusion polymorphism, overloading and type conversions. Groovy also supports an equivalent to parameterized types via its generics structure.
The subclass inherits access to all the protected and public methods and variables provided by the parent class. It can also be used anywhere the parent class can be used.
The above example defines two classes: Shape and Circle. Shape is an abstract class, meaning it forms a prototype or base class for any subclasses, but cannot be directly instantiated. This can be considered a partially implemented class. Like an interface, it defines methods that need to be implemented by any class extending this abstract class. Unlike an interface, an abstract class may include methods and variables.
In addition to the Java class and interface mechanism, Groovy adds an additional set of capabilities through its traits mechanism. This mechanism allows a class to extend one or more traits, which adds methods and fields. This is similar to how JavaScript allows for extending a prototype or existing object with additional fields and methods. In actuality, traits are defined in code somewhere between an interface and a class.
Groovy allows for implementing multiple traits in a given class, resulting in an equivalent of multiple inheritance in C++. In an instance where a class implements multiple traits with the same method, the last declared trait will be executed.
Unlike Java, Groovy also offers the ability to overload operators as well as providing method level overloading.
Groovy adds an additional set of explicit conversions though the as <type> instruction.
This instruction tells the interpreter how to perform the conversion, eliminating any ambiguity that can arise from the Groovy automatic conversion system.
Groovy can also inherits Java’s implicit object to string conversion. When any Object is assigned to a String variable, Java automatically calls the toString() method that is defined in the base Object class that all Java classes subclass. This allows Java to get a string representation of any object, even if it’s just the class name and hashcode.
Inclusion Polymorphism
Groovy implements inclusion polymorphism through classes and subclasses instead of types and subtypes. When defining a class, as in Java, the developer defines the variables in the class and the methods available in the class. A developer can then create a second class that extends that class, creating a subclass.The subclass inherits access to all the protected and public methods and variables provided by the parent class. It can also be used anywhere the parent class can be used.
abstract class Shape
{
private int x, y
public int getX() { return x }
public int getY() { return y }
public void setX(int x) { this.x = x }
public void setY(int y) { this.y = y }
abstract void draw()
}
class Circle extends Shape
{
private long radius
void draw()
{
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
}
class Test
{
static void main(String[] args)
{
// Create instance of Circle
Circle c = new Circle()
c.radius = 1.4
// Access the methods from Shape
c.x = 1
c.y = 5
// Assign c to a variable of type
// Shape which works because Circle
// is a sub class of Shape
Shape s = c
s.draw()
}
}
In addition to the Java class and interface mechanism, Groovy adds an additional set of capabilities through its traits mechanism. This mechanism allows a class to extend one or more traits, which adds methods and fields. This is similar to how JavaScript allows for extending a prototype or existing object with additional fields and methods. In actuality, traits are defined in code somewhere between an interface and a class.
trait FlyingAbility
{
String fly() { "I'm flying!" }
}
class Bird implements FlyingAbility {}
def b = new Bird()
assert b.fly() == "I'm flying!"
trait A
{
String exec() { 'A' }
}
trait B
{
String exec() { 'B' }
}
// When called, the exec command will return the value of
// B.exec() because it is listed last
class C implements A, B {}
Parameterized Types
Groovy supports Java’s generics structure which can be likened to a parameterized type. For a further description of Java generics, see Generic Abstraction.Overloading
Groovy supports method overloading, allowing multiple definitions for a method of a given name. Overloaded methods are differentiated by the parameters passed into the method. The following example shows the draw method is overloaded with two implementations: one that takes no parameters and one that takes a single int parameter. Depending on which method is invoked, the class will present two different outcomes.class Circle
{
private int x, y
private float radius
void draw()
{
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
void draw(int scale)
{
int x = this.x * scale
int y = this.y * scale
float radius = this.radius * scale
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
}
Type Conversions
Groovy supports converting one type into another. The underlying Java language is strongly typed, meaning that it can define a variable as a specific primitive or class. Once a variable has been defined, Java allows for converting that variable from one type to another, where applicable, via both casting and coercion.Casting
Casting instructs the JRE to treat or convert a given variable as a different type of object. This is accomplished by prefixing a variable or method with the class type to cast to. At compile time, the compiler will attempt to determine if the cast is valid for the combination of variable/return and target variable. For example, if the target variable is a parent class for the source variable or method, then the compiler will allow it because any subclass of the target variable will be compatible. If the target variable is a subclass of the return, then the compiler will allow it and defer to runtime checks. If the cast is not possible (such as Integer to String), the Java compiler will return an error.class CastExample
{
static void main(String[] args)
{
// Compile time-check
Parent p = getChild();
// Runtime check
Child c = (Child)getParent();
// Invalid cast
Child c = new Object()
}
static Parent getParent()
{
// Child is cast to Parent on return
return new Child();
}
static Child getChild()
{
return new Child();
}
}
class Parent
{
// No implementation for this example
}
class Child extends Parent
{
// No implementation for this example
}
String s = “42”
int i = s as Integer
Coercion
In addition to explicit conversions via casts, Groovy also supports implicit casts via coercion. Within primitive types, Java allows coercing values of storage to be converted into variables of higher storage. For example, Java can automatically convert a short to an int to a long. In each case, the second type stores more bits than the source type, allowing the JRE to represent the same value.short s = 10
int i = s
long i = s
No comments:
Post a Comment