Inheritance

Inheritance allows you to create classes hierarchically.
Subclasses inherit the superclass's implementation.

The key to object-oriented programming is reusability.
You can reuse classes as they are or reuse super ones.
When reusing a superclass, it means creating a subclass appropriately from the superclass.

Let's start with an example of a class that is not inherited.
The following are the Employee and Manager classes.

Employee.java
package net.java_school.oop;

public class Employee {
  private String name;
  private String position;
  private String telephone;
	
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getPosition() {
    return position;
  }

  public void setPosition(String position) {
    this.position = position;
  }

  public String getTelephone() {
    return telephone;
  }

  public void setTelephone(String telephone) {
    this.telephone = telephone;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(name);
    sb.append("|");
    sb.append(position);
    sb.append("|");
    sb.append(telephone);

    return sb.toString();
  }
	
}
Manager.java
package net.java_school.oop;

public class Manager {
  private String name;
  private String position;
  private String telephone;
  private String manageJob;
	
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getPosition() {
    return position;
  }

  public void setPosition(String position) {
    this.position = position;
  }

  public String getTelephone() {
    return telephone;
  }

  public void setTelephone(String telephone) {
    this.telephone = telephone;
  }

  public String getManageJob() {
    return manageJob;
  }

  public void setManageJob(String manageJob) {
    this.manageJob = manageJob;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(name);
    sb.append("|");
    sb.append(position);
    sb.append("|");
    sb.append(telephone);
    sb.append("|");
    sb.append(manageJob);
		
    return sb.toString();
  }
	
}
Test.java
package net.java_school.oop;

public class Test {
  public static void main(String[] args) {
    Employee james = new Employee();
    james.setName("JAMES");
    james.setPosition("CLERK");
    james.setTelephone("19");
    System.out.println(james.toString());	
	
    Manager blake = new Manager();
    blake.setName("BLAKE");
    blake.setPosition("MANAGER");
    blake.setTelephone("9");
    blake.setManageJob("Project Management");
    System.out.println(blake.toString());
  }	
}

The two classes above have nothing to do with each other.
However, since the proposition that a manager is an employee is right, the two classes are an inheritance relationship that establishes an is-a relationship.
Since an employee is a concept wide than a manager, an employee is a superclass, and a manager is a subclass.
Now, to implement inheritance as code, make sure that there is an overlapping code in the employee class and manager class.
You can see that the name, position, and telephone field, and getters and setters methods for these.
The duplicate code will be inherited and will disappear from the manager class source.

Modify the Manager class to inherit the Employee class like below.

Manager.java
package net.java_school.oop;

public class Manager extends Employee {
  private String manageJob;
	
  public String getManageJob() {
    return manageJob;
  }

  public void setManageJob(String manageJob) {
    this.manageJob = manageJob;
  }
	
  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getName());
    sb.append("|");
    sb.append(getPosition());
    sb.append("|");
    sb.append(getTelephone());
    sb.append("|");
    sb.append(manageJob);
		
    return sb.toString();
  }
	
}

To inherit a superclass from a subclass, use the extends keyword in the class declaration of the subclass.
The modified manager class can use the employee class's instance variables and instance methods as if they were their own.
When the subclass accesses the inherited instance variables or methods, the access modifiers of the inherited instance variables and methods are still working.
The reason for using getName(), getPosition(), and getTelephone() in the toString() method of the manager class is that the employee class name, position, and telephone are private.
To access the parent instance variables name, position, and telephone directly, you need to change the access modifiers of these variables.
Since the employee class and the manager class is in the same package, declaring the name, position, and telephone access modifiers in the employee class as package private, protected, or public allows access to these variables of the parent from the child directly. If the employee class and the manager class are not the same packages, you must declare the name, position, and telephone of the employee class as protected or public.
An object of a subclass type can access the protected variables and methods of a superclass even if the package of the subclass and superclass is different.
The protected access modifier protects the inheritance relationship between classes in other packages.

Run the Test class to see the results.

Method Overriding
You can use methods inherited from a parent class, but you can redefine those methods.
It is called method overriding.
When redefining methods of a parent class in a child class, the return type, method name, and parameter list must be the same as those of the parent's method.
The toString() of the manager class overrides the toString() of the employee class, and the toString() of the employee class overrides toString() of the Object class.
Is there an extends keyword in the class declaration of employee class? None.
However, if there is no extends in the class declaration, that class will inherit the Object class.
Java compiler intervenes and changes the class declaration to class Employee extends Object.
As a result, the superclass of the employee class becomes an Object.
An element such as @Override is called an annotation.
An annotation passes information to the compiler or platform that Java code cannot pass to the compiler or platform.
In the above code, @Override tells the compiler that the method overrides the superclass method.

Constructor

In the method main of Test class, Manager blake = new Manager(); is the code to create Manager object.
Now it is time to talk more about this part of the code.
The Manager() that comes after new is the code that calls the Manager() constructor.
Just like the method, you need to declare the Manager() in the class body.
After a new keyword, you can call one of the constructors declared in the class.
In the above example, I did not create a constructor for the employee class and the manager class.
However, I have code that calls the constructor in the method main.
And the example runs without error.
It means that the calling constructor has run.
How did the undeclared constructor run?
The Java compiler compiles after adding a parameterless constructor to the class code when there is no constructor in the class.
The constructor that the compiler automatically generates is called the default constructor.
If you declare any of the constructors, the Java compiler does not add a default constructor.
You can declare multiple constructors with different parameter lists.
The constructor is called just once after an object is created and is not called again.
Don't assume that a constructor creates an object.
The new keyword allocates space for an object in the heap memory and initializes the variables of an object.
Then the constructor after the new keyword is called.
When the constructor finishes without errors, the reference variable is assigned a reference value that can refer to a created object.
If there is an error in the constructor, the reference variable is not assigned a reference value, and as a result, an object is disabled.

Java calls a constructor after creating an object.
So, most constructors consist of code that initializes an object.
A constructor must have no return type, and the constructor name must be the same as the class name.
Many people make a mistake by putting void before the constructor's name when making a constructor.
If you add void, it becomes a method, not a constructor.

Subclasses do not inherit the superclass's constructor.
The first line of the subclass constructor implementation must contain code that invokes the constructor of the superclass.
If not, the compiler adds code to the first line that calls the default constructor of the superclass.
Later, we will add appropriate constructors to the employee class and the manager class.
Before implementing code, let's look at the keywords this and super.

this
At the time this is executed, this will have an instance's reference value.
You can use this to differentiate between a parameter of a constructor and an instance variable within a constructor.
Also, you can use this to call another constructor within a constructor.
Note that when you write your code in Eclipse, you can get code assists for the available resources (variables, methods, and so on) by typing. (Dot) after this.
super
You can use the super keyword in the following cases: 1. When you need to call a method of a superclass hidden by method overriding 2. When you need to call a constructor of superclass within a subclass constructor
Adding constructors to the Employee class
public Employee() {} //if you need to create a constructor, it is a good idea to create a default constructor also.

public Employee(String name, String position, String telephone) {
  this.name = name;
  this.position = position;
  this.telephone = telephone;
}
Adding constructors to the Manager class
public Manager() {} //default constructor

public Manager(String name, String position, String telephone, String manageJob) {
  super(name, position, telephone);
  this.manageJob = manageJob;
}
Modify the main() of the Test class
Employee james = new Employee("JAMES", "CLERK", "19");
System.out.println(james.toString());

Manager blake = new Manager("BLAKE", "MANAGER", "9", "Project Management");
System.out.println(blake);

In System.out.println(blake);, the println() calls the toString() of the instance pointed to by blake.
Therefore, the results of System.out.println(blake.toString()); and System.out.println(blake); are the same.
It is up to you to decide which code you like better.
The compiler changes the above constructor code as below.

Code that the compiler added in Employee's Constructors
public Employee() {
  super();
}

public Employee(String name, String position, String telephone) {
  super();
  this.name = name;
  this.position = position;
  this.telephone = telephone;
}
Code that the compiler added in Manager's Constructors
public Manager() {
  super();
}

public Manager(String name, String position, String telephone, String manageJob) {
  super(name, position, telephone);
  this.manageJob = manageJob;
}

You may assign a reference of subclass type to a variabl of esuperclass type

Codes with polymorphism make you feel like they are in the same shape but executed in various forms.
You can experience polymorphism by assigning a reference of a subclass type to a variable of a superclass type.

Polymorphism

Guitar extends Instrument
Drum extends Instrument

Instrument i = new Guitar();//i is the variable of Intrument type
/*
JVM casts the reference returned by new Guitar() to the Instrument type
and then assigns it to the variable i.
*/
i.play();//Guitar play
i = new Drum();
i.play();//Drum play

i.play();//Guitar play
i.play();//Drum play
i.play() plays a guitar or drum.
i.play() has polymorphism.

Java determines Whether the i.play() code plays the guitar or the drum at runtime, not compile time.

When you assign a reference of a subclass type to a variable of a superclass type, the JVM casts this reference to the superclass type.
Not all variables and methods of an object can be accessed using this reference.
A reference cast to a superclass type can only access instance variables and instance methods inherited from a superclass and methods overridden by a subclass.

Add the following to the main() of the Test class.

Object king = new Manager("KING", "MANAGER", "1", "SALES");
System.out.println(king);
//king.setManageJob("ACCOUNTING");// You can not access the setManagerJob() method with an Object type reference.
//If you want to use the Manager object completely, you need to cast the reference to the Manager class type. 
Manager king1 = (Manager) king;
king1.setManageJob("ACCOUNTING");
System.out.println(king);

In the last line System.out.println(king), the variable king has an Object class type's reference. The println() method internally calls the toString() of Object class. Since the instance created in the heap memory is the manager object, JVM calls the toString() that the manager class overrides. Regardless of the reference's data type, (2) and (3) are covered and can not be seen. Therefore, (1) is called.
Manager Object

Method overloading
In Java, you can create multiple methods with the same name with different argument lists, which is called method overloading.
Method overloading ensures the method to be called with argument lists that match the arguments passed.
Note that the return type has nothing to do with method overloading. You cannot create multiple methods with the same name and the same argument lists but only different return types.
In Java, naming is important.
You should name a method so that the behavior of the one is well understood.
Method overloading reduces this burden of naming.
Method overloading makes you get the impression that the same method looks run variously.
Method overloading is polymorphic.
In System.out.println(); the println() method looks like it prints whatever the argument value is.
Java API developers have defined several println methods with different argument lists.
The appropriate println method reacts according to the arguments passed.

final keyword

The keyword final is related to inheritance.

  1. When used in a class declaration, it is not possible to create a subclass from this class.
  2. When used in a method declaration, a subclass cannot override this method.
  3. When creating constants, prefix the variable name with the final.

Abstract Class

In the class declaration section, a class with an abstract before the class keyword is called an abstract class.
You cannot instantiate an abstract class using the new.
To understand an abstract class, you first need to know the meaning of the abstract method.
An abstract method does not have a method body.
To declare an abstract method, add the abstract keyword after the access modifier in the method declaration.
If a class has one abstract method, you must declare that class as an abstract class.
Conversely, not all abstract classes need to have more than one abstract method.
If necessary, you can declare an abstract class without an abstract method.
A class that inherits an abstract class must override the parent class's abstract method.
Let's create an abstract class by modifying the previous examples.
Create the abstract class AbstractEmployee.java like below.
The ambiguity of abstract classes improves portability.
Of course, there must be a premise that the class design is good.

AbstractEmployee.java
package net.java_school.example;

public abstract class AbstractEmployee {
  private String name;
	
  public AbstractEmployee() {}
	
  public AbstractEmployee(String name) {
    this.name = name;
  }
	
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
	
  //Abstract method
  public abstract void doWork();
  
	
}

Change the employee class to inherit the AbstractEmployee abstract class.
The employee class must implement the abstract method, doWork() of the AbstractEmployee class.

Employee.java
package net.java_school.example;

public class Employee extends AbstractEmployee {
  private String position;
  private String telephone;
	
  public Employee() {}
	
  public Employee(String name,String position, String telephone) {
    super(name);
    this.position = position;
    this.telephone = telephone;
  }
	
  public String getPosition() {
    return position;
  }

  public void setPosition(String position) {
    this.position = position;
  }

  public String getTelephone() {
    return telephone;
  }

  public void setTelephone(String telephone) {
    this.telephone = telephone;
  }

  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append(this.getName());
    sb.append("|");
    sb.append(position);
    sb.append("|");
    sb.append(telephone);
		
    return sb.toString();
  }
	
  
  @Override
  public void doWork() {
    System.out.println("work");
  }
  	
}

The manager class does not change.
Change the first line of the main method of the Test class as below.
AbstractEmployee james = new Employee ("JAMES", "CLERK", "19");

Interface: Defines the function of the component5.

The Java interface has the interface keyword in place of the class keyword in the class declaration, and all methods of the class body are abstract methods.
Since they are all abstract methods, you can omit the abstract keyword. All fields declared in the interface body are static final.
As an abstract class, you cannot use an interface alone.
You will use classes that implement an interface.
A class that implements an interface is a class that implements all of the abstract methods of an interface.
The class declaration that implements the interface defines which interface the class implements using the implements keyword.
A comma-separated list of one or more interfaces can follow the implements keyword, which can look like multiple inheritances.
The Java interface is the same as the user interface of the electronic product.
Most TVs provide interfaces such as - volume + and - channel + at the bottom of the screen.
The fact that electronics have adopted the same interface means that their usage is the same.
If the Java class is an electronic product, then the Java interface corresponds to the user interface of the electronic product.
The implementation of the TV with the PDP, LCD, and LED in the CRT was different, but fortunately, the interface did not change.
As a result, I had no trouble using the TV without having to look at the user manual after buying a new technology TV.

When should I use the interface?

When to use inheritance and when to use the interface is a difficult problem.
To briefly describe this problem, If you find an is-a relationship, you can use inheritance.
If the focus is on what function should be, you can use the interface.
Suppose you have created a driver class that inherits an employee class.
And if you have a delivery man class and the delivery man is not an employee but has many functions like driver class, you can create an interface with that function.
However, you can not create a parent class with duplicate code in the DeliveryMan class and the Driver class.
Because the Driver class cannot has two superclasses.
In the Java source dimension, there must be only one class after extends in the class declaration.
You can not list parent classes with (comma) after extends.
But, you can create an interface with the duplicate functionality of the delivery man and the driver.
Let's practice the contents so far in order.
First, make the driver class as follows.
Because the driver is an employee, he inherited the employee class.

Driver.java
package net.java_school.example;

public class Driver extends Employee {
  private String carNo;
	
  public Driver() {}
	
  public Driver(String name, String position, String telephone, String carNo) {
    super(name, position, telephone);
    this.carNo = carNo;
  }

  public String getCarNo() {
    return carNo;
  }

  public void setCarNo(String carNo) {
    this.carNo = carNo;
  }

  public void drive() {
    System.out.println(this.getName() + " drives");
  }
	
  public void transport() {
    System.out.println(this.getName() + " transports");
  }
	
}
Transporter.java
package net.java_school.example;

public class Transporter {
  private String carNo;
	
  public String getCarNo() {
    return carNo;
  }

  public void setCarNo(String carNo) {
    this.carNo = carNo;
  }

  public void drive() {
    System.out.println("drives");
  }
	
  public void transport() {
    System.out.println("transports");
  }
	
}

The transporter and the driver class have the same features that drive() and transport().
You can create an interface with these same features.
Let's call the interface Drivable.

Drivable.java
package net.java_school.example;

public interface Drivable {
  public void drive();
	
  public void transport();

}

Let's change the transporter and the driver class that implements this interface.

Driver.java
package net.java_school.example;

public class Driver extends Employee implements Drivable {
  private String carNo;
	
  public Driver() {}
	
  public Driver(String name, String position, String telephone, String carNo) {
    super(name, position, telephone);
    this.carNo = carNo;
  }

  public String getCarNo() {
    return carNo;
  }

  public void setCarNo(String carNo) {
    this.carNo = carNo;
  }
	
  @Override
  public void drive() {
    System.out.println(this.getName() + " drives");
  }
	
  @Override
  public void transport() {
    System.out.println(this.getName() + " transports");
  }
	
}
Transporter.java
package net.java_school.example;

public class Transporter implements Drivable {
  private String carNo;
	
  public String getCarNo() {
    return carNo;
  }

  public void setCarNo(String carNo) {
    this.carNo = carNo;
  }

  @Override
  public void drive() {
    System.out.println("drives");
  }
	
  @Override
  public void transport() {
    System.out.println("transports");
  }
	
}

Add the following code snippet to the main method of the Test class.

Test.java
Drivable a = new Driver("Michael","CLERK","ext:8","015000");
System.out.println(a);
a.drive();
Drivable b = new Transporter();
// b.setCarNo("017000"); //error!
b.drive();

As you can see in inheritance, You can assign a subclass type reference to a superclass type variable.
Likewise, you can assign an object reference of a class that implements an interface to interface type variable.