Chapter:Inheritance - Some rules and syntax

From Juneday education
Jump to: navigation, search

Meta information about this chapter

Expand using link to the right to see the full content.

Purpose

The purpose of this lecture, is to cover the rules and syntax of Java inheritance. It also aims to explain what happens in runtime when an object is created, in terms of the object's parts from super classes and how they are initialized (e.g. the implicit call to super()).

Goals

After this lecture, the student shall know and understand

  • That the compiler adds an implicit call to super() - the parameterless super class constructor, if you don't provide an explicit call to a specific constructor
    • That the solution shouldn't be to add a parameterless constructor to every class - just in case, and to shut up the compiler
  • That you can only extend one class at the time in Java
    • Interfaces are a different story, but there's time for that in a later lecture
    • There are other languages that allow multiple inheritance - but we don't care about that in this course material - we focus on Java
  • That you can prevent a class from being extended by using final at the class declaration
    • That java.lang.String is final
      • FYI: because the designers of Java thought it could introduce security problems otherwise
      • FYI: also because String is immutable and to keep it that way, normally immutable classes are declared final
    • You can also make all constructors private - this prevents extension because the implicit call to super() will fail to compile

Instructions to the teacher

Common problems related to this chapter

Spend some time on explaining the implicit call to super() which is inserted by the compiler if no explicit call is found in the source code. You can convince the students of this fact in a few ways:

Using javap

$ cat A.java
public class A { }
$ javac A.java
$ javap A
Compiled from "A.java"
public class A {
  public A();
}

Trying to extend a class where all constructors are private:

jshell> class A {
   ...>   private A() {}
   ...> }
|  created class A

jshell> class B extends A {}
|  Error:
|  A() has private access in A
|  class B extends A {}
|  ^

Ask the students why they think the implicit call to super is important. Ask them what would happen if it were not inserted automatically. Give an example where the constructor in the super class does some initialization of some fields that are inherited. Show them (convince them) that these fields would not be initiated properly without the call to super().

This may be a good time to bring up a rule-of-thumb - don't let constructors call methods that are non-final.

Ask them what will happen in this scenario:

import java.util.Random;

public class A {
  
  protected String tag;

  public A() {
    initializeTag();
  }

  /* Generate a String of three random chars */
  protected void initializeTag() {
    Random rand = new Random();
    String s = "";
    char c = (char)(rand.nextInt('Z' - 'A' + 1) + 'A');
    s += c;
    c = (char)(rand.nextInt('Z' - 'A' + 1) + 'A');
    s += c;
    c = (char)(rand.nextInt('Z' - 'A' + 1) + 'A');
    s += c;
    tag = s;
  }}

class B extends A {
  @Override
  protected void initializeTag() {
    tag = tag.toLowerCase();
  }
}

class TestB {
  public static void main(String[] args) {
    B b = new B();
  }
}

What happends when we run TestB?

Answer:

$ java TestB
Exception in thread "main" java.lang.NullPointerException
	at B.initializeTag(A.java:22)
	at A.<init>(A.java:8)
	at B.<init>(A.java:19)
	at TestB.main(A.java:28)

Explanation:

In class A, the variable tag first gets the default value null, then the constructor calls the method initializeTag(). Until initializeTag is completed, tag will be null. Now, class B extends A and overrides the method initializeTag(). The overridden version returns whatever string tag has, as lower case letters by calling toLowerCase() on tag.

The problem is, that when main creates a new B, then the explicit call to super() is first executed. The execution continues in the constructor of A. The constructor calls initializeTag(), but this method is overridden by A! So execution continues in the overridden version of initializeTag() in B. When tag.toLowerCase() is evaluated, we get a null pointer exception, because tag still has its default value null.

To avoid hard-to-predict errors like this, the recommendation is "Never call a method from a constructor, unless that method is final".

Note: The method initializeTag() works by generating a random number between 'A' and 'Z' inclusive. The nextInt() method takes an argument for producing a value between 0 and the argument exclusive. So we take the number calculated as the difference between 'Z' and 'A' plus one, then we add 'A'. This way we'll get a number between 'A' and 'Z' inclusive.

Full frontal - Code up-front

Here's some teaser code - just to spark your imagination.

public class DefaultConstructor {

}

When compiled, the compiler adds a parameter-less constructor to the class file, and in that constructor, it also adds a call to super() (in this case to Object() ):

$ javap -c DefaultConstructor.class
Compiled from "DefaultConstructor.java"
public class DefaultConstructor {
  public DefaultConstructor();  <---------------------------------------Default constructor added!
    Code:
       0: aload_0
       1: invokespecial #1 // Method java/lang/Object."<init>":()V <----Call to Object() added!
       4: return
}

Introduction

This section shows you the rules (most of them) when using extends and inheritance.

The purpose of this lecture, is to cover the rules and syntax of Java inheritance. It also aims to explain what happens in runtime when an object is created, in terms of the object's parts from super classes and how they are initialized (e.g. the implicit call to super()).

Chapters on the topic of Inheritance

Videos

English videos

Swedish videos

Links

Further reading

Where to go next

Next page has exercises for this chapter (if any): Inheritance_-_Some_rules_and_syntax_-_Exercises

« PreviousBook TOCNext »