Inheritance
# Inheritance
- Use
extendsto indicate that class A inherits from class B
# The Object Class
- All classes extends from the
Objectclass- don't need to state the obvious
- i.e.
public class main extends Object
- It provides useful methods
# hashCode() function
- The
hashCode()methods returns a numeric value that is calculated based on the address of the object in memory.
var point1 = new Point(1, 2);
var point2 = new Point(1, 2);
System.out.println(point1.equals(point2)); // false
System.out.println(point1.hashCode() == point2.hashCode()) // false
2
3
4
Even though point1 and point2 have the same coordinates, the default implementation of the
equals()method compares objects for reference equality.These two objects are in two different locations in memory, that’s why the
equals()method returnsfalse.
var point1 = new Point(1, 2);
var point2 = point1;
System.out.println(point1.hashCode() == point2.hashCode()); // true
2
3
# Constructor
A Default Constructor is a constructor without any parameters
- If we don’t create it, the Java compiler will automatically add one to our classes.
i.e.
public Constomer(String name) {}- constructors don’t have a return type, not even void.
To create a constructor
- Click
Code - Click
Generate - Click
Constructor
- Click
# The super keyword
The super keyword is a reference to the base or parent class.
We can use it to access the members (fields and methods) or call the constructors of the base class
In contrast, the
thiskeyword returns a reference to the current object.
// Super class
public abstract class UIControl {
private boolean isEnabled = true;
public UIControl(boolean isEnabled) {
this.isEnabled = isEnabled;
}
}
// Sub class
public class TextBox extends UIControl {
private String text = "";
public TextBox() {
// pass boolean value to the super class
super(true);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Private and protected access modifiers
Members marked with protected or private access modifiers are only accessible inside of a class.
Protected members are inherited and are accessible by child (derived) classes.
- If we omit the access modifier, the member will have the default access modifier which makes that member public in package.
- In other words, that member will be public in the package but private outside of the package.
Private fields cannot be inherited by sub classes and are not accessible outside of the class
- Its implementation detail is hidden
# Method Overriding
Method overriding means changing the implementation of an inherited method in a subclass.
- For example, we can override the
equals()orhashCode()methods of the Object class.
- For example, we can override the
Method overloading means declaring a method with different signatures (different number, type and order of parameters).
public class TextBox extends UIControl {
private String text = "";
// Override the default toString method
@Override
public String toString() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
public static void main(String[] args) {
var textBox = new TextBox();
textBox.setText("Hello world");
// Can ignore the '.toStrong()' part
System.out.println(textBox);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# @Override annotation
The benefit of applying the @Override annotation when overriding a method:
It signals the Java compiler that we are overriding a method in the base class and this helps the compiler check our code for correctness.
It will ensure the signature of the method in the subclass matches the on declared in the base class.
Also, if we remove this method from the base class, the compiler will let us know and we can remove the method in the subclass as well.
# Upcasting and Downcasting
Q: The Customer class inherits from the User class. Can we pass a Customer object to this method? Why?
public void print(User user) {}
- Yes. We can pass an instance of any classes that inherit directly or indirectly from the User class.
- In this case, the customer object will get automatically upcast (meaning it’ll get converted to its base type - User).
- If we need to work with members of the customer object in this method, we need to explicitly downcast it by prefixing the object with (Customer).
public static void main(String[] args) {
var control = new UIControl(true);
var textBox = new TextBox();
}
public static void show(UIControl control) {
// since in textBox, toString is overidden, need to specify its type
if (control instanceof TextBox) {
// downcast it by prefixing the object
var textBox = (TextBox) control;
textBox.setText("Hello World!");
}
System.out.println(control);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
instanceof operator:
- It tells us if an object is an instance of a class.
- We use it before casting an object to a different type to make sure we don’t get a casting exception.
# Comparing Objects
- Click
Command + N - Select
equals() and hashCode()
public static void main(String[] args) {
var point1 = new Point(1, 2);
var point2 = new Point(1, 2);
System.out.println(point1 == point2); // return false, because their address are different
ystem.out.println(point1.equals(point2)); // this is the right way
}
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// use Command + N, and click "Override methods" to override the equals() method
@Override
public boolean equals(Object obj) {
// check address to determine obj is the object itself
if (this == object)
return true;
// safety check
if (!(obj instanceof Point))
return false;
var other = (Point) obj;
return other.x == x && other.y == y;
}
// generated not based on the address of the object in memory, but based on the content of the object
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Four principles of object-oriented programming
- Encapsulation: bundling the data and operations on the data inside a single unit (class).
- Abstraction: reducing complexity by hiding unnecessary details (metaphor: the implementation detail of a remote control is hidden from us. We only work with its public interface.)
- Inheritance: a mechanism for reusing code.
- Polymorphism: a mechanism that allows an object to take many forms and behave differently. This will help us build extensible applications.
# Polymorphism
- Polymorphism: a mechanism that allows an object to take many forms and behave differently. This will help us build extensible applications.
public class Main {
public static void main(String[] args) {
UIControl[] controls = { new TextBox(), new CheckBox() };
// control takes many form
for (var control : controls)
control.render();
}
}
// super class
public abstract class UIControl {
public abstract void render();
}
// sub class
public class TextBox extends UIControl {
@Override
public void render() {
System.out.println("Render TextBox");
}
}
// sub class
public final class CheckBox extends UIControl {
@Override
public void render() {
System.out.println("Render CheckBox");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# abstract classes and methods
public abstract class UIControl {
public abstract void render(); // classes inherited the UIControl class must implement the method
}
2
3
An abstract class is a partially-implemented (half-cooked) class
We cannot instantiate them because it is an abstract concept
But we use them to share some common code across their subclasses
An abstract class does not need abstract methods
- This means we can have an abstract class without any abstract methods
- But if we mark a method as abstract, we should mark the class as abstract as well
Classes inherited a abstract class must implement all methods of that class
# final classes
Final classes cannot be inherited (extended)
We use them when we’ve made certain assumptions about a class and we want to prevent other classes extending our class and break those assumptions.
Normally not used because it breaks object-oriented programming principles
e.g.
Stringclass isfinal, because strings are immutable, and its methods has many assumptions- Once initialized, cannot change its content
Final methods cannot be overridden
- Don't want assumptions been broken
# Deep Inheritance Hierarchies
- Should be one or two levels, no more than three levels
Consequences of Tightly couple classes to each other
- This means if one wants to modify
Entity, they may need to modify all classes that are inherited fromEntity - Any changes will cause all subclasses to be recompiled and redeployed
- Some methods don't make sense to other classes (Polluting hierarchy with irrelevant stuff)
Right way:
- Delete the
Userabstract class- Cost: Duplicate code a little bit
- Delete both
RegularInstructorandPremiumInstrutor- Use a boolean value instead
# Multiple Inheritance
- Java does not support multiple inheritance because it is troublesome:
- It's ambiguous which
sayHello()c should inherit
# The Diamond Problem
- The diamond problem happens in languages that support multiple inheritance.
- If two classes (B, C) derive from A and are also the parents of another class (D), we see a diamond.
- If the top class (A) declares a method (eg toString) and its children (B and C) override this method, it’s not clear which implementation will be inherited by D.