Inheritance
Inheritance is the process by which a subclass automatically includes any public or protected members of the class, including primitives, objects, or methods, defined in the parent class.
When one class inherits from a parent class, all public and protected members are automatically available as part of the child class.
Package-private members are available if the child class is in the same package as the parent class.
private members are restricted to the class they are defined in and are never available via inheritance. This doesn’t mean the parent class doesn’t have private members that can hold data or modify an object; it just means the child class has no direct reference to them.
public or protected members defined in the parent classPackage-private members are available if the child class is in the same package as the parent class.private members are restricted to the class they are defined in and are never available via inheritance.inheritance is transitive
If child class X inherits from parent class Y, which in turn inherits from a parent class Z, then class X would be considered a subclass, or descendant, of class Z. By comparison, X is a direct descendant only of class Y, and Y is a direct descendant only of class Z.
SINGLE VS. MULTIPLE INHERITANCE
Java supports single inheritance, by which a class may inherit from only one direct parent class. Java also supports multiple levels of inheritance, by which one class may extend another class, which in turn extends another class. You can have any number of levels of inheritance, allowing each descendant to gain access to its ancestor’s members.
Java does allow one exception to the single inheritance rule that you’ll see in Chapter 9—a class may implement multiple interfaces.
How to prevent a class from being extended?
It is possible in Java to prevent a class from being extended by marking the class with the final modifier.
If you try to define a class that inherits from a final class, then the class will fail to compile.
INHERITING OBJECT
java.lang.Object, or Object for short.extends java.lang.Object to the class definition.Defining and extending a class
public abstract class ElephantSeal extends Seal {
// Methods and Variables defined here
}public or default (package-private) access modifierabstract or final keyword (optional)class keyword (required)extends parent class (optional)EXTENDING A CLASS
public class Animal {
private int age;
protected String name;
public int getAge() {
return age;
}
public void setAge(int newAge) {
age = newAge;
}
}
public class Lion extends Animal {
public void setProperties(int age, String n) {
setAge(age);
name = n;
}
public void roar() {
System.out.print(name + ", age " + getAge() + ", says: Roar!");
}
public static void main(String[] args) {
var lion = new Lion();
lion.setProperties(3, "kion");
lion.roar();
}
}the Lion program prints the following: kion, age 3, says: Roar!
Cannot access private variable
public class Lion extends Animal {
...
public void roar() {
System.out.print("Lions age: "+age); // DOES NOT COMPILE
}
...
}APPLYING CLASS ACCESS MODIFIERS
Top-level class can only have public or default (package-private) access modifier
> [!NOTE:]
An inner class is a class defined inside of another class and is the opposite of a top-level class. In addition to public and package-private access, inner classes can also have protected and private access. We will discuss inner classes in Chapter 9.
As you might recall, a Java file can have many top-level classes but at most one public top-level class. In fact, it may have no public class at all. There’s also no requirement that the single public class be the first class in the file. One benefit of using the package-private access is that you can define many classes within the same Java file.
Inner class can have public, protected, default (package-private) and private access modifier.top-level classes but at most one public top-level class.package-private access is that you can define many classes within the same java file.> [!NOTE:]
For simplicity, any time you see multiple public classes or interfaces defined in the same code sample in this book, assume each class is defined in its own Java file.
test
ACCESSING THE THIS REFERENCE
this reference refers to the current instance of the class and can be used to access any member of the class, including inherited members.instance method, constructor, and instance initializer block.static method or static initializer block.What do you think the following program prints?
public class Flamingo {
private String color;
public void setColor(String color) {
color = color;
}
public static void main(String... unused) {
Flamingo f = new Flamingo();
f.setColor("PINK");
System.out.println(f.color);
}
}Output:
null
The assignment completes successfully within the method, but the value of the instance variable color is never modified and is null when printed in the main() method.
public void setColor(String color) {
this.color = color;
}The this reference refers to the current instance of the class and can be used to access any member of the class, including inherited members. It can be used in any instance method, constructor, and instance initializer block. It cannot be used when there is no implicit instance of the class, such as in a static method or static initializer block.
1: public class Duck {
2: private String color;
3: private int height;
4: private int length;
5:
6: public void setData(int length, int theHeight) {
7: length = this.length; // Backwards – no good!
8: height = theHeight; // Fine because a different name
9: this.color = "white"; // Fine, but this. not necessary
10: }
11:
12: public static void main(String[] args) {
13: Duck b = new Duck();
14: b.setData(1,2);
15: System.out.print(b.length + " " + b.height + " " + b.color);
16: } }This code compiles and prints the following:0 2 white
How do we reference the version in the parent class instead of the current class?
To achieve this, you can use the super reference or keyword.
ex:
class Mammal {
String type = "mammal";
}
public class Bat extends Mammal {
String type = "bat";
public String getType() {
return super.type + ":" + this.type;
}
public static void main(String... zoo) {
System.out.print(new Bat().getType());
}
}The program prints mammal:bat
What does the following program output?
1: class Insect {
2: protected int numberOfLegs = 4;
3: String label = "buggy";
4: }
5:
6: public class Beetle extends Insect {
7: protected int numberOfLegs = 6;
8: short age = 3;
9: public void printData() {
10: System.out.print(this.label);
11: System.out.print(super.label);
12: System.out.print(this.age);
13: System.out.print(super.age);
14: System.out.print(numberOfLegs);
15: }
16: public static void main(String []n) {
17: new Beetle().printData();
18: }
19: }That was a trick question—this program code would not compile!
line 13 does not complie.
while this includes current and inherited members, super only includes inherited members.
Constructors Rules
matches the name of the class and has no return type.parameters can be any valid class, array, or primitive type, including generics, but may not include var.constructor has a unique signature. (constructor parameters must be distinct.)Can you tell why these two are not valid constructors for the Bunny class?
public class Bunny {
public bunny() { } // DOES NOT COMPILE
public void Bunny() { }
}The first one doesn’t match the class name because Java is case sensitive.
The second method is a perfectly good method but is not a constructor because it has a return type.
The following does not compile:
class Bonobo {
public Bonobo(var food) { // DOES NOT COMPILE
}
}Like method parameters, constructor parameters can be any valid class, array, or primitive type, including generics, but may not include var.
Constructor Overloading
A class can have multiple constructors, so long as each constructor has a unique signature. In this case, that means the constructor parameters must be distinct. Like methods with the same name but different signatures,
declaring multiple constructors with different signatures is referred to as constructor overloading.
ex:
public class Turtle {
private String name;
public Turtle() {
name = "John Doe";
}
public Turtle(int age) {}
public Turtle(long age) {}
public Turtle(String newName, String... favoriteFoods) {
name = newName;
}
}DEFAULT CONSTRUCTOR
Every class in Java has a constructor whether you code one or not. If you don’t include any constructors in the class, Java will create one for you without any parameters. This Java-created constructor is called the default constructor and is added anytime a class is declared without any constructors. We often refer to it as the default no-argument constructor for clarity.
It is only in the compiled file with the .class extension that it makes an appearance.
> [!NOTE:]
Having only private constructors in a class tells the compiler not to provide a default no-argument constructor.
It also prevents other classes from instantiating the class.
This is useful when a class has only static methods or the developer wants to have full control of all calls to create new instances of the class.
Remember, static methods in the class, including a main() method, may access private members, including private constructors.
test
CALLING OVERLOADED CONSTRUCTORS WITH THIS()
public class Hamster {
private String color;
private int weight;
public Hamster(int weight) { // First constructor
this.weight = weight;
color = "brown";
}
public Hamster(int weight, String color) { // Second constructor
this.weight = weight;
this.color = color;
}
}Constructors can be called only by writing new before the name of the constructor.
Cannot call constructor like normal method.
public Hamster(int weight) {
Hamster(weight, "brown"); // DOES NOT COMPILE
}When this() is used with parentheses, Java calls another constructor on the same instance of the class.
public Hamster(int weight) {
this(weight, "brown");
}this() rule
Calling this() has one special rule you need to know. If you choose to call it, the this() call must be the first statement in the constructor. The side effect of this is that there can be only one call to this() in any constructor.
ex:
3: public Hamster(int weight) {
4: System.out.println("in constructor");
5: // Set weight and default color
6: this(weight, "brown"); // DOES NOT COMPILE
7: }Consider the following definition of the Gopher class:
public class Gopher {
public Gopher(int dugHoles) {
this(5); // DOES NOT COMPILE
}
}The compiler is capable of detecting that this constructor is calling itself infinitely.
Since this code can never terminate, the compiler stops and reports this as an error.