Classes, Superclasses, and Subclasses
Info
Semua file yang ada pada contoh pada catatan ini ada pada package Ch5/J_5_1_Classes_Superclasses_Subclasses
Mari kita kembali pada class Employee
yang telah kita buat pada contoh sebelumnya. Katakan di sebuah perusahaan ada juga Manager. Jadi Manager adalah seorang Employee yang memiliki tunjangan bonus tambahan. Maka kita harus membuat sebuah Class Manager
yang memiliki state dan behavior yang sama persis dengan Employee namun dengan tambahan adanya perhitungan bonus. Disinilah inheritance memainkan perannya. Manager adalah Employee, maka kita dapat menggunakan hubungan is-a
, class Manager is-a
class Employee.
Defining Subclasses
Dibawah ini adalah bagaimana kita mendefinisikan Manager
class yang merupakan turunan dari Employee
Kata kunci extends
meeng indikasi bahwa kita membuat sebuah class baru yang menurunkan sebuah class yang sudah ada. Class yang sudah ada disebut dengan super class, base class atau parent class sedangkan class yang baru bisa disebut subclass, derived class atau child class. Satu class hanya bisa menurunkan (extend) satu buah class.
Class Employee
adalah superclass, namun bukan berarti class tersebut superior atau memiliki fungsi yang lebih banyak sehingga dikatakan superclass. Justru kebalikannya. Subclass memliki fungsi yang lebih banyak dibandingka superclass-nya. Contoh, Manager
memiliki data dan fungsi yang lebih banyak dibandingkan dengan superclass Employee
.
Class Manager
memiliki field baru bonus
dan method baru untuk menyetel nilai pada field tersebut.
Code
Dari hasil diatas, jika kita memiliki objek Manager
kita dapat memasang nilai bonus dengan memanggil method seperti dibawah ini.
Akan tetapi, jika kita memiliki object Employee
, kita tidak dapat menggunakan method setBonus
karena method tersebut tidak dimiliki oleh class Employee
. Namun sebaliknya, pada subclass, yaitu class Manager
kita dapat menggunakan semua method yang memiliki Accsess Modifier public, atau protected seperti method getName
, getHireDay
yang dimiliki oleh class Employee
. Walaupun objek tersebut tidak secera eksplisit di definisikan pada class Manager
, method tersbut akan secara otomatis diturunkan dari Superclass Employee
Semua object Manager
memiliki empat fields, name
, hireDay
, salary
, dan bonus
. Semua field selain bonus
diambil dari Superclass Employee
.
Note
Kita telah mencoba membuat class menggunakan record
. Class yang dibangung menggunakan record
tidak dapat menjadi Superclass atau Subclass dari class lain.
Overriding Methods
Beberapa method dari superclass Manager
tidak cocok dengan subclass Employee
. Salah satunya adalah getSalary()
. Method tersebut seharunsya mengembalikan gaji pokok di tambah dengan bonus. Kita harus membuat method baru yang meng-override superclass method.
Logika sangat mudah, yaitu dengan mengembalikan field salary
ditambah dengan field bonus
.
Kode diatas tidak akan berhasil. Perlu diingat, hanya method dari Employee
yang memiliki akses langsung ke private fields dari class Employee
. Artinya method getSalary()
dari class Manager
tidak memiliki akses langsung untuk mengambil nilai dari field salary
. Jika method dari class Manager
ingin mengakses private field salary
, maka kita harus menggunakan apa yang digunakan oleh method dari class lain, yaitu menggunakan public method, yaitu yang telah kita buat methodnya di class Employee
, yaitu getSalary()
.
Namun masalahnya, fungsi getSalary()
yang kita panggil memiliki nama method yang sama dengan nama method yang sedang kita implementasi. Kode diatas akan menyebabkan perulangan berantai akibat kita memanggil method itu sendiri didalam dirinya yang menyebabkan program akan berhenti.
Karena itu, kita harus mengindikasi atau memberitahu compiler bahwa kita ingin mengambil method getSalary()
dari superclass Employee
, bukan dari class saat ini. Kita dapat menggunakan keyword super
untuk tujuan tersebut.
Code
Anotasi Override
opsional, anotasi tersebut digunakan oleh compiler untuk menunjukan bahwa class tersebut meniban method dari superclass. Compiler akan mengeluarkan error jika setidaknya kondisi dibawah terpenuhi;
- Method meniban atau mengimplementasi deklarasi method
- Method memiliki signature yang sama dengan yang dideklarasi pada superclass
Note
Beberapa orang berpikir bahwa super
dianalogikan dengan this
reference. Namun analogi tersebut kurang tepat. super
bukan merujuk ke sebuah object. Akan tetapi ia adalah special keyword yang mengarahkan compiler untuk meminta superclass method.
Subclass Constructor
Sekarang kita buat constructor pada class Manager
untuk membuat object.
Code
Dibawah ini adalah full kode dari penggalan kode diatas
Code
Kode dibawah ini berada pada Package Ch5/J_5_1_Classes_Superclasses_Subclasses/Example1
package Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1;
import java.math.BigDecimal;
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
var manager1 = new Manager("Farras",new BigDecimal(13000000), LocalDate.of(2023,6,5));
manager1.setBonus(new BigDecimal(2000000));
System.out.println(manager1);System.out.println();
var employee = new Employee("Fulan 2", new BigDecimal(5900000), LocalDate.of(2017,7,3));
System.out.println(employee);
}
}
package Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1;
import java.math.BigDecimal;
import java.time.LocalDate;
public class Manager extends Employee{
private BigDecimal bonus;
public BigDecimal getBonus() {
return bonus;
}
public Manager(String name, BigDecimal salary, LocalDate hireDay){
super(name, salary,hireDay);
this.bonus = new BigDecimal(0);
}
public void setBonus(BigDecimal bonus) {
this.bonus = bonus;
}
@Override
public BigDecimal getSalary() {
return super.getSalary().add(this.getBonus());
}
@Override
public String toString() {
return super.toString().replace("Salary\t\t","Salary & Bonus");
}
}
package Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1;
import java.math.BigDecimal;
import java.time.LocalDate;
public class Employee{
// instance
private String name;
private BigDecimal salary;
private LocalDate hireDay;
public Employee(String name, BigDecimal salary, LocalDate hireDay){
this.name = name;
this.salary = salary;
this.hireDay = hireDay;
}
public String getName() {
return name;
}
public BigDecimal getSalary() {
return salary;
}
public LocalDate getHireDay() {
return hireDay;
}
@Override
public String toString() {
return "Name\t\t\t: %s\nSalary\t\t\t: %,.2f\nHire Day\t\t: %s".
formatted(this.getName(),this.getSalary(),this.getHireDay().toString());
}
}
Preventing Inheritance: Final Classes and Methods
Class yang tidak dapat diturunkan (extend) disebut dengan final class dan kita harus menggunakan final
modifier saat mendefinisikan class untuk mengindikasi bahwa class ini adalah final class. Katakan class Executive
tidak bisa lagi diturunkan karena tidak ada yang lebih tinggi dari eksekutif.
Kita juga dapat membat method tertentu pada sebuah class menjadi final
. Jika kita melakukan itu, maka tidak ada subclass yang dapat meng-override method tersebut.
Note
Semua method didalam final class secara otomatis menjadi final method. Ingat juga bahwa field juga dapat dijadikan final field dimana field tersebut tidak akan pernah berubah lagi semenjak objek class tersebut telah terbuat. Namun class yang di set sebagai final hanya secara otomatis menjadi semua method final, namun fields tidak.
Code
Casting
Konversi dari satu tipe data ke tipe data lain disebut dengan Casting. Java programming langguage memmiliki special notasi untuk casting.
Konversi nilai dari pecahan kedalam integer akan menghilangkan fraksi dari pecahan
.
Mari sekarang kita lihat casting pada object reference. Mari kita gunakan lagi superclass Employee
dan subclass Manager
.
Code
package Ch5.J_5_1_Classes_Superclasses_Subclasses;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Employee;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Manager;
import java.math.BigDecimal;
import java.time.LocalDate;
public class J_1_Casting_Object_Reference {
public static void main(String[] args) {
Employee[] employees = new Employee[3];
employees[0] = new Manager("farras",new BigDecimal(13000000), LocalDate.now());
employees[1] = new Employee("Fulan2",new BigDecimal(5000000), LocalDate.now());
employees[2] = new Employee("Fulan3",new BigDecimal(7500000), LocalDate.now());
for (Employee data : employees){
if (data instanceof Manager){ //(1)!
Manager boss = (Manager) data;
boss.setBonus(new BigDecimal(4500000));
System.out.println(boss);
}
else {
System.out.println(data);
}
System.out.println();
}
}
}
- Semenjak Java 16 kita dapat melakuakn seperti ini
Penjelasan dari kode diatas sbb;
- Kita membuat array yang menampung object variabel yang berisikan object reference ke Class
Employee
- Saat inisiasi data, ada satu yang diisi dengan objects reference
Manager
. Ini sah-sah saja, karena tidak semua Employee adalah karyawan, karena ada juga yang menjabat sebagai Manager. Ini disebut dengan Promosing less. - Kita me-looping vairable
employess
dan melakukan pengecheckan apakah element dari Array yang berisikan object tersebut instance dari classManager
. Jika ia maka kita meng-casting element tersebut kedalam typeManager
. Selanjutnya kita memanggil methodsetBonus()
dan menampilkantoString()
dari objectManager
. - Jika element bukan instace dari maka kita langsung menampilkan
toString()
dari objectEmployee
.
Masih membahas tentang casting objects reference. Compiler melakukan pengujian apakah kita memberikan tipe yang lebih tinggi saat menyimpan nilai pada sebuah variable. Ada dua jenis, promosing less dan promosing more;
-
Jika kita memberikan subclass reference pada superclass variable maka kita melakukan prmissing less, dan compiler akan menganggap itu sah-sah saja (Sebagaimana cotoh diatas kita memberikan object reference subclass
Manager
pada variable superclassEmployee
). -
Jika kita memberikan superclass reference pada sublcass variable maka kita melakukan promosing more. Jika demikian kita harus menggunakan cast sehingga promise daat di check saat runtime oleh compiler.
Code
package Ch5.J_5_1_Classes_Superclasses_Subclasses;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Employee;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Manager;
import java.math.BigDecimal;
import java.time.LocalDate;
public class J_2_Casting_Promosing_More_and_Less {
public static void main(String[] args) {
// Promosing less
Employee realManager = new Manager("farras",new BigDecimal(13000000), LocalDate.now());
// Promosing More
Manager fakeManager = (Manager) new Employee("farras",new BigDecimal(13000000), LocalDate.now());
}
}
Lalu bagaimana jika kita melakukan cast down pada rantai inheritance. Misalkan object reference di cast ke class Manager.
Code
package Ch5.J_5_1_Classes_Superclasses_Subclasses;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Employee;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Manager;
import java.math.BigDecimal;
import java.time.LocalDate;
public class J_3_Casting_to_Subclass {
public static void main(String[] args) {
try {
// will raise ClassCastException
Employee karyawan = new Employee("Fulan2",new BigDecimal(5000000), LocalDate.now());
Manager manager = (Manager) karyawan;
}
catch (ClassCastException ex){
System.out.println(ex.getLocalizedMessage());
}
}
}
jika kita tidak menangkap exception catch
, program kita akan berhenti. Maka dari itu, praktik yang baik kita kita mencari tahu dahulu apakah cast akan berhasil sebelum kita melakukan casting. Kita dapat menggunakan apa yang telah kita gunakan pada conoht diatas, yaitu menggunakan instaceof
Code
package Ch5.J_5_1_Classes_Superclasses_Subclasses;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Employee;
import Ch5.J_5_1_Classes_Superclasses_Subclasses.Example1.Manager;
import java.math.BigDecimal;
import java.time.LocalDate;
public class J_4_Casting_Save_With_Instanceof {
public static void main(String[] args) {
Employee karyawan = new Employee("Fulan2",new BigDecimal(5000000), LocalDate.now());
if(karyawan instanceof Manager) {
Manager manager = (Manager) karyawan;
}else {
System.out.println("Karyawan bukan isntace dari manager");
}
}
}
Access Modifeir
Berbicara tentang akses field dan method dari sebuah class, dibawha ini adalah empat akses kontrol yang disediakan olhe Java
- Accessible in the class only (private).
- Accessible by the world (public).
- Accessible in the package and all subclasses (protected).
- Accessible in the package—the (unfortunate) default. No modifiers are needed.