Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
class A{}
class B extends A{}
def b= new B()
assert b in B && b in A

class A1{}
class A2{}
//class C extends A1, A2{}
    //compile error when uncommented: a class can extend at most one class

...

Code Block
class A{
  public int prev //field
  int signature //property
  String sayPies(int n){ "There are ${prev= signature= n} pies!" } //method
}
class B extends A{
  String sayBirds(int n){ "There are $n birds!" }
}
def b= new B()
assert b.sayBirds(17) == 'There are 17 birds!'
assert b.sayPies(11) == 'There are 11 pies!'
    //method sayPies(int) from A acts as part of B
assert b.prev == 11 //field 'prev' from A acts as part of B
b.signature= 19
assert b.signature == 19 //property 'signature' from A acts as part of B
assert b.getSignature() == 19

...

Code Block
class A{
  //private methods, properties, and fields are not visible outside the class,
  //even in inheriting classes...
  private int prevPies
  private String sayPies(int n){ "There are ${prevPies= n} pies!" }

  //protected methods, properties, and fields are visible in inheriting
classes...   //...classes (and within the same package (see later tutorial on packages)...
  protected int prevBeans
  protected String sayBeans(int n){ "There are ${prevBeans= n} beans!" }
}
class B extends A{
  def testAccesses(){
    assert sayPies(23) == 'There are 23 pies!'
               //Groovy bug: this private method shouldn't be visible here
    try{ prevPies; assert 0 }catch(e){ assert e in MissingPropertyException }
               //A's private field 'prevPies' not visible here

    assert sayBeans(29) == 'There are 29 beans!'
               //A's protected method visible here in an inheriting class
    assert prevBeans == 29
               //A's protected field visible here in an inheriting class
  }
}
def b= new B()
assert b.sayPies(11) == 'There are 11 pies!'
               //Groovy bug: this private method shouldn't be visible here
try{ b.prevPies; assert 0 }catch(e){ assert e in MissingPropertyException }
               //A's private field 'prevPies' not visible here

assert b.sayBeans(14) == 'There are 14 beans!'
    //this protected method is visible here in the same package it's defined in
assert b.prevBeans == 14
    //this protected field is visible here in the same package it's defined in

b.testAccesses()

...

Code Block
class A{
  static public int numBananas //field
  static signature //property
  static String sayBananas(int n){ //method
    "There are ${numBananas= signature= n} bananas!"
} //method }
}
class B extends A{}

assert A.sayBananas(23) == 'There are 23 bananas!' //method call
assert A.numBananas == 23 //field access
assert A.signature == 23 //property accesses
assert A.getSignature() == 23

assert B.sayBananas(23) == 'There are 23 bananas!' //method call

assert B.numBananas == 23 //field access
assert B.signature == 23 //property access
B.getSignature() == 23 //property access using method syntax

...

Code Block
class A{
  static private int numBananas= 0
  static private String sayBananas(int n){
    "There are ${numBananas= n} bananas!"
  }
   static protected int numApples= 0
  static protected String sayApples(int n){
    "There are ${numApples= n} apples!"
  }
}
class B extends A{
  static testAccesses(){
    assert sayBananas(37) == 'There are 37 bananas!'
    //numBananas //compile error when uncommented:
                 //A's private field not visible here

    assert sayApples(29) == 'There are 29 apples!'
    //numApples //compile error when uncommented:
                //A's protected field not visible here in an inheriting class
  }
}
assert B.sayBananas(31) == 'There are 31 bananas!'
try{ B.numBananas; assert 0 }catch(e){ assert e in MissingPropertyException }
assert B.sayApples(23) == 'There are 23 apples!'
assert B.numApples == 23

B.testAccesses()

...

Code Block
interface X{
  def x()
  //static x1() //error when uncommented: interface methods can not be static
}
interface Y{
  def y()
}
abstract class A{
  static a(){ println 1 }
  abstract b()
  abstract c()
  //abstract static c1()
    //error when uncommented: abstract methods can not be static
}
class B extends A implements X, Y{
  static x(){ println 2 }
  def y(){ println 3 }
  static b(){ println 4 }
  def c(){ println 5 }
}

...

Code Block
class A{
  final a(){ 11 }
  def b(){ 12 }
}
final class B extends A{
  //def a(){ 15 } //compile error when uncommented: can not override final A.a()
  def b(){ 16 }
}
//class C extends B{} //compile error when uncommented: can not extend final C

Constructors

Just as a class's constructor can call another constructor at the beginning of its code, so also it can call a constructor on the superclass at the beginning of its code:

Code Block
class A{
  def list= []
  A(){
    list<< "A constructed"
  }
  A(int i){
    this()
    list<< "A constructed with $i"
  }
}
class B extends A{
  B(){
    list<< "B constructed"
  }
  B(String s){
    super(5) //a constructor can call its superclass's constructor if it's
             //the first statement
    list<< "B constructed with '$s'"
  }
}

def b1= new B('kea')
assert b1.list.collect{it as String} == [
  "A constructed",
  "A constructed with 5",
  "B constructed with 'kea'",
]
def b2= new B()
assert b2.list == [
  "A constructed",
        //default parameterless constructor called if super() not called
  "B constructed",
]

Using Classes by Extending Them

Some classes supplied with Groovy are intended to be extended to be used. For example, FilterInputStream, FilterOutputStream, FilterReader, and FilterWriter:

Code Block
try{ //When not extended, FilterOutputStream simply passes its method calls to the
//wrapped stream...
try{
  def fos= new FilterOutputStream(new FileOutputStream('abc.txt'))
  fos.write(33i)
  fos.write([34,35,36] as byte[])
  fos.write([34,35,36,37,38,39,40] as byte[], 3, 2)
  fos.close()
  def fis= new FilterInputStream(new FileInputStream('abc.txt'))
  def ba= new byte[6]
  fis.read(ba)
  assert ba.toList() == [33,34,35,36,37,38]
}

//We can extend FilterOutputStream to provide the logic for the filter...
class EvenNumberOutputStream extends FilterOutputStream{
  EvenNumberOutputStream(OutputStream out){
    super(out)
  }
  def write(int i){
    if(i%2 == 0) super.write(i) //call method of same name in the super-class
  }
  def write(byte[] ba){
    super.write( ba.toList().findAll{ it%2 == 0 } as byte[] )
  }
  def write(byte[] ba, int start, int size){
    this.write( ba[start..<(start+size)] as byte[] )
        //another way to call method of same name in same class definition
  }
}
try{ //...then call the methods...
  def fos= new EvenNumberOutputStream(new FileOutputStream('abc.txt'))
  fos.write(33i)
  fos.write([34,35,36] as byte[])
  fos.write([34,35,36,37,38,39,40] as byte[], 3, 2)
  fos.close()
  def fis= new FilterInputStream(new FileInputStream('abc.txt'))
  def ba= new byte[6]
  fis.read(ba)
  assert ba.toList() == [34,36,38,0,0,0]
}

We can similarly extend FilterInputStream, FilterReader, and FilterWriter.

The Object Hierarchy

All classes are arranged in a hierarchy with java.lang.Object as the root. Here are those we've met so far; those labelled as such are abstract and final classes:

...