Inheritance

Inheritance allows you to create classes hierarchically.
A superclass passes its implementation to a subclass, and a subclass inherits its implementation from a superclass.

The most important thing in object-oriented programming is reuse.
Reuse can reuse classes as they are and reuse super classes.
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.example;

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.example;

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.example;

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 "manager is an employee" is correct, the two classes are an inheritance relationship that establishes a "is-a" relationship.
Since the employee is a concept wider than the manager, the employee is a superclass and the manager is a subclass.
Now, in order to implement inheritance as code, make sure that there is overlapping code in employee class and manager class.
You can see that the name, position, and telephone instance variables are overlapped with the getters and setters methods for this variable.
The duplicate code will be inherited and will be deleted from the manager class source.
Modify the manager class to inherit the employee class as shown below.

Manager.java
package net.java_school.example;

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.
Now the manager class will be able to write the member of the employee class as if it were a member.
However, from now on, the inherited member and the original member of the class should be considered separately, because the inherited member still applies the access modifiers.
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 member variables name, position, and telephone directly, you need to change the access modifiers of these member variables.
Since the employee class and the manager class are in the same package, applying the name, position, and telephone access modifiers in the employee class as package private, protected, or public allows access to the members of the parent directly.
If the employee class and the manager class are not the same package, you must apply the name, position, and telephone accessors in the employee class as protected or public.
An object of a subclass type can access the protected member of a superclass even if the package of the subclass and superclass is different.
The access modifier protected protects the inheritance relationship between classes in other packages.
Run the Test class to see the results.

Method Overriding
You can use the method inherited from the parent, but if you want to "redefine" 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.
The toString() of the employee class overrides toString() of the Object class, and the toString () of the manager class overrides the toString () of the employee class.
Wait, does the toString() in the employee class override the toString() in the Obejct class? Check the employee class code again.
Is there an extends keyword in the class declaration? None.
However, if there is no extends keyword in the class declaration, the class inherits the Object class.
This is because the compiler intervenes and changes the class declaration to public class Employee extends Object.
As a result, the superclass of the employee class becomes Object.
An element such as @Override is called an annotation.
An annotation passes information that the Java code can not pass to the compiler or platform.
In the above code, @Override tells the compiler that the method overrides the superclass method.

Constructor

In the main method 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.
Manager() must be declared in the class body just like methods.
After new, 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, the constructor is called in the main method of the Test class.
And seeing the result without errors means that the calling constructor was executed.
How could a constructor that could not be created be called? The compiler creates a parameterless constructor if you did not create any constructors as you were writing the class.
The constructor that the compiler automatically generates is called the "default constructor".
If you have created any of the constructors, the compiler does not create a "default constructor".
You can create multiple constructors with different parameter lists.
The constructor is called just once after "the object is created" and is not called again.
Note that "after object is created".
It is misleading to think that an object is created when a constructor is called.
The new keyword allocates space for the object in the heap memory1 and initializes the value of the instance variable2.
Then the constructor after new is called.
When the constructor finishes without errors, the reference variable is assigned a reference value that can refer to the created object.
If there is an error in the constructor, no reference value is assigned to the reference variable, and as a result, the object is disabled.

It is called after the object is created, so it is good to write the constructor only for initialization.
So initialization of instance variables is done by the constructor.
If you have code that calls a method in the constructor implementation, it is often not good code.

The 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 name when making a constructor.
If you add void, it becomes a method, not a constructor.

The following describes the constructor syntax associated with inheritance.
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 for the parent class.
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 the object's own reference value.
The this keyword is used to call another constructor within the constructor or to distinguish instance variables from parameters in the constructor.
Note that when you write your code in Eclipse, you can get code assists for the available resources (member variables, methods, and so on) by typing. (Dot) after this.
super
The super keyword is used in the following cases: 1. When you need to call a method of a superclass hidden by method overriding 2. When calling a superclass constructor from a subclass constructor
Adding a constructor to 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 a constructor to 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 method 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 method calls the toString() method of the object 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 above constructor code is changed by the compiler as shown below.

Code that the compiler added in Employee's Constructor
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 Constructor
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 value of the subclass type to the reference variable of the superclass type.

It is polymorphism to make them feel like they are in the same shape, but executed in various forms.
You can see this polymorphism by taking advantage of the fact that you can assign a reference value of a subclass type to a reference of a superclass type.

Polymorphism

Guitar extends Instrument Drum extends Instrument Instrument i = new Guitar(); //i is the variable of Intrument type i.play(); //Guitar play i = new Drum(); i.play(); //Drum play

I.play() plays a guitar or drum.
I.play() has polymorphism.
Whether the guitar is played or the drum is played is determined at the time i.play() is executed (Runtime).
It is not determined at compile time.
When a reference type variable of a superclass type refers to an object of a subclass type, it can not be used to access all members of the object.
The original member of the subclass is not accessible.
There is an exception, but the methods overridden in a subclass are accessible.
In fact, this is the hardest part to understand.
In conclusion, a superclass type reference can access inherited members from a superclass and overridden methods by subclasses.
Let's look at an example.
Add the following to the main method of the Test class:

Add the following code to the main method of Test.java
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 Employee object completely, you need to cast the reference type variable.
Manager king1 = (Manager)king;
king1.setManageJob("ACCOUNTING");
System.out.println(king);

In the last line System.out.println(king); king is an Object type variable.
The println() method internally calls the toString() method of the object pointed to by king.
Then, since the object actually created in the heap memory is the manager object, the toString() method that the manager class overrides is called.
The picture below is drawn for your understanding.
Regardless of the reference type, (2) and (3) are covered and can not be seen.
Therefore, (1) is called.
Manager Object

Method overloading
In Java, you can create any number of methods of the same name, if different from the argument list.
This is called method overloading.
Method overloading can create multiple methods of the same name with different argument lists, This means that the appropriate method will be called according to the arguments passed in while calling the method.
Note that the return type has nothing to do with method overloading.
You cannot create a method with the same name with the same parameter list, but with a different return type.
In Java, naming is important.
You should name the method so that the behavior of the method is well understood.
Method overloading reduces this burden of naming.
With overloaded methods, you get the impression that the method looks the same but runs differently.
Method overloading is polymorphic.
In System.out.println(); the println() method3 looks like it prints whatever the argument value is.
In fact, there are a number of methods with different parameter types defined, and the right method is called depending on the type of argument value passed when the method is called.

final keyword

  1. When used in a class declaration4, it is not possible to inherit the class and create a subclass.
  2. When used in a method declaration, the method cannot be overridden in a subclass.
  3. When creating constants in Java, prefix the variable name with "final".

Abstract Class

In the class declaration section, a class with an abstract before the class keyword is called an abstract class.
An abstract class can not be instantiated using the keyword new, unlike a normal class.
To understand an abstract class, you first need to know the meaning of the abstract method.
An abstract method is a method declaration, but not a method body.
To distinguish abstract methods from normal methods, add the abstract keyword after the access modifier in the method declaration.
If a class has one abstract method, it must be declared 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.
To use an abstract class, you need to create a normal class that inherits from the abstract class, and override the abstract methods of the abstract class in the normal class you created.
Let's create an abstract class example by modifying the previous examples.
Create the abstract class AbstractEmployee.java class as shown below.
If you make it ambiguous like this, the portability is better.
Of course, there must be a premise that the 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() method 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");
	}
		
}

Manager classes do not change.
Change the first line of the main method of the Test class you created so far as shown 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.
Because they are all abstract methods, the abstract keyword to distinguish them from normal methods is omitted.
All fields declared in the interface body are static6 final.
Like an abstract class, an interface can not be used alone, and it is used to objectize a class that implements an interface.
If a class implements an interface, it means a class that implements all of the abstract methods of the interface.
The class declaration that implements the interface defines which interface the class implements using the keyword implements.
The implements keyword can be followed by one or more interfaces separated by commas, which may look like multiple inheritance.
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, we apply inheritance if we find the "to" relationship.
If the focus is on "what function should be", then the interface should be applied.
Keep in mind that interfaces are not constrained by hierarchical relationships like inheritance, and that Java supports only a single inheritance, while an interface can look like multiple inheritance.
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 is two parent classes.
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.
This is one of the constraints of the hierarchical relationship mentioned above.
You can create an interface with the common 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");
	}
	
}
Transportor.java
package net.java_school.example;

public class Transportor {
	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 has common features that drive() and transport().
This common function can be created as an interface.
The interface name is called 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");
	}
	
}
Transportor.java
package net.java_school.example;

public class Transportor 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 Transportor();
// b.setCarNo("017000"); //error!
b.drive();

As you can see in inheritance, "Subclass type object reference values can be assigned to superclass type references" An object reference value of a class that implements an interface can be assigned to a variable of an interface type.

Comments
  1. In Java, heap memory is the space in which objects are created.
  2. When an object is created before the constructor is called, the value of the instance variable is initialized to 0 for numeric types, false for Boolean values, and null for reference type variables.
    Char is strictly a numeric type and is initialized to 0 in Unicode tables.
  3. The print() and println() methods are methods of the java.io.PrintStream class. Check out the Java documentation.
  4. The String class is the final class. In other words, you can not create your own string class by inheriting from the String class. Check out the Java documentation.
  5. It is an independent unit that consists of several elements to provide various functions for one purpose.
    The condition should be good portability.
    What if you can buy the necessary components and build a system like a LEGO block? What components do companies like Amazon need? Payment component, warehouse management component, order management component, accounting component ..
    The interface is responsible for defining the functionality of the component for inter-component communication.
  6. When static is attached, it means that it does not belong to the object.
    In the next chapter, we will learn about static.
    Note that the static variable is not an instance variable.