Masukkan Password
51 Constructors in inheritance in Dart | super to call constructor during inheritance
Materi ini membahas constructor dalam inheritance di Dart. Topiknya memang agak membingungkan karena melibatkan extends, super, this, initializer list, factory constructor, dan abstract class sekaligus.
Saya akan jelaskan dari konsep paling dasar → alur pemanggilan constructor → 10 poin penting, sambil meluruskan beberapa bagian transcript yang kurang tepat.
1. Gambaran besar: apa yang terjadi saat membuat object subclass?
Misalnya kita punya:
class A {
A() {
print("Constructor A");
}
}
class B extends A {
B() {
print("Constructor B");
}
}
Kemudian:
void main() {
B();
}
Output:
Constructor A
Constructor B
Kenapa A dipanggil dulu, padahal kita membuat B?
Karena B adalah turunan dari A.
A
↑
B
B mewarisi bagian dari A. Sebelum object B selesai dibuat, bagian superclass (A) harus diinisialisasi terlebih dahulu.
Jadi secara sederhana:
Saat constructor subclass dijalankan, constructor superclass harus dijalankan lebih dulu.
2. Apa itu implicit call ke superclass constructor?
Perhatikan:
class A {
A() {
print("A");
}
}
class B extends A {
B() {
print("B");
}
}
Kita tidak menulis:
super();
Tetapi Dart tetap menjalankan constructor A.
Secara konsep, Dart memperlakukan constructor B seolah-olah ada pemanggilan:
B() : super() {
print("B");
}
Jadi:
B();
alur sederhananya:
B() dipanggil
↓
A() dipanggil
↓
A selesai
↓
B() dijalankan
↓
B selesai
Ini disebut implicit invocation/call of superclass constructor.
3. Tetapi ada syarat penting
Implicit super() hanya bisa dilakukan kalau superclass mempunyai unnamed zero-parameter constructor yang dapat dipanggil.
Contoh:
class A {
A() {
print("A");
}
}
class B extends A {
B() {
print("B");
}
}
Ini valid karena A memiliki:
A()
yaitu:
- unnamed constructor
- tidak memiliki parameter
Bagaimana kalau A punya constructor berparameter?
Misalnya:
class A {
A(int x) {
print("A: $x");
}
}
class B extends A {
B() {
print("B");
}
}
Ini akan error.
Kenapa?
Karena Dart secara default mencoba:
super();
Tetapi A tidak memiliki:
A()
Yang tersedia hanya:
A(int x)
Jadi Dart bingung:
“Saya harus memanggil constructor A, tetapi
A()tidak tersedia.”
4. Solusinya: super(...)
Kita bisa memberitahu Dart constructor mana yang harus dipanggil:
class A {
A(int x) {
print("Constructor A: $x");
}
}
class B extends A {
B() : super(10) {
print("Constructor B");
}
}
Output:
Constructor A: 10
Constructor B
Perhatikan bagian:
B() : super(10)
Artinya:
“Sebelum menjalankan constructor
B, panggil constructor superclassAdengan nilai10.”
Ini disebut explicit superclass constructor invocation.
5. Kenapa menggunakan super?
Bayangkan superclass punya proses initialization yang kompleks.
class Person {
String name;
int age;
Person(this.name, this.age);
}
Kemudian:
class Employee extends Person {
double salary;
String position;
Employee(
String name,
int age,
this.salary,
this.position,
) : super(name, age);
}
Ketika kita melakukan:
Employee employee = Employee(
"Sam",
21,
25000,
"Designer",
);
alur initialization-nya:
Employee constructor
↓
super(name, age)
↓
Person(name, age)
↓
name dan age diinisialisasi
↓
kembali ke Employee
↓
salary dan position diinisialisasi
Sehingga object akhirnya memiliki:
Employee
├── name = "Sam"
├── age = 21
├── salary = 25000
└── position = "Designer"
6. Kenapa tidak initialize name dan age langsung di Employee?
Secara desain, name dan age merupakan bagian yang dimiliki Person.
class Person {
String name;
int age;
Person(this.name, this.age);
}
Sedangkan:
class Employee extends Person {
double salary;
String position;
}
salary dan position adalah bagian khusus Employee.
Jadi lebih baik:
Person
├── name
└── age
Employee
├── salary
└── position
Person bertanggung jawab menginisialisasi:
name
age
Employee bertanggung jawab menginisialisasi:
salary
position
Dan hubungan keduanya dilakukan dengan:
super(name, age)
Ini jauh lebih baik daripada menyalin logic constructor Person ke Employee.
7. Multilevel inheritance
Sekarang kita punya:
class A {
A() {
print("A");
}
}
class B extends A {
B() {
print("B");
}
}
class C extends B {
C() {
print("C");
}
}
Kemudian:
C();
Output:
A
B
C
Kenapa?
Karena hierarchy-nya:
Object
↓
A
↓
B
↓
C
Maka prosesnya dari atas ke bawah:
Object constructor
↓
A constructor
↓
B constructor
↓
C constructor
Khusus Object, constructor-nya tidak melakukan print, jadi kita tidak melihat outputnya.
8. Urutan constructor adalah hal yang sangat penting
Misalnya:
class Person {
Person() {
print("Person");
}
}
class Employee extends Person {
Employee() {
print("Employee");
}
}
void main() {
Employee();
}
Jangan berpikir:
Employee → Person
dalam arti Employee selesai dulu baru Person.
Yang terjadi:
Person constructor mulai
↓
Person constructor selesai
↓
Employee constructor mulai
↓
Employee constructor selesai
Jadi:
Superclass constructor selesai lebih dahulu, baru constructor subclass menjalankan body-nya.
9. Named constructor superclass juga bisa dipanggil
Misalnya:
class A {
A(int x) {
print("A dengan x = $x");
}
A.named(String message) {
print("A.named: $message");
}
}
Subclass:
class B extends A {
B() : super(10) {
print("B");
}
B.demo() : super.named("Hello") {
print("B.demo");
}
}
Kalau:
B.demo();
output:
A.named: Hello
B.demo
Perhatikan:
super.named("Hello")
Artinya:
Panggil named constructor
namedmilik superclass.
10. super() vs super.namaConstructor()
Unnamed constructor
super(10)
memanggil:
A(10)
Named constructor
super.named("Hello")
memanggil:
A.named("Hello")
Jadi:
super(...) → unnamed constructor
super.nama(...) → named constructor
11. super bukan hanya untuk constructor
Dalam Dart, super juga digunakan untuk memanggil member milik superclass.
Misalnya:
class Animal {
void sound() {
print("Animal sound");
}
}
class Cat extends Animal {
@override
void sound() {
super.sound();
print("Meow");
}
}
Output:
Animal sound
Meow
Tetapi dalam materi kali ini, super(...) memiliki fungsi khusus:
B() : super(...);
yaitu memanggil constructor superclass.
12. Kenapa constructor superclass harus dipanggil dulu?
Ini bagian yang paling penting secara konsep.
Misalnya:
class Person {
String name;
int age;
Person(this.name, this.age);
}
Kemudian:
class Employee extends Person {
double salary;
Employee(
String name,
int age,
this.salary,
) : super(name, age);
}
Object Employee secara logis mempunyai bagian:
Employee object
│
├── bagian Person
│ ├── name
│ └── age
│
└── bagian Employee
└── salary
Maka bagian Person harus diinisialisasi dulu.
Baru kemudian bagian Employee.
Itulah salah satu alasan mengapa urutannya:
Superclass → Subclass
bukan:
Subclass → Superclass
13. Poin penting: kalau superclass tidak menulis constructor
Ini sering membingungkan.
Misalnya:
class A {
}
Tidak ada constructor yang ditulis.
Kemudian:
class B extends A {
B() {
print("B");
}
}
Ini valid.
Kenapa?
Karena Dart menyediakan implicit unnamed default constructor pada A dalam kondisi yang sesuai.
Secara konsep:
class A {
A() {}
}
Jadi ketika:
B();
Dart dapat melakukan:
A()
↓
B()
Tetapi A() kosong, sehingga tidak ada output.
14. Kalau kita membuat constructor sendiri, default constructor bisa hilang
Ini sangat penting.
Misalnya:
class A {
A(int x) {
print(x);
}
}
Sekarang A tidak memiliki:
A()
Yang ada:
A(int x)
Jadi:
class B extends A {
B() {}
}
akan bermasalah karena Dart mencoba implicit:
super();
padahal:
A()
tidak tersedia.
Solusinya:
class B extends A {
B() : super(10) {}
}
15. Kapan kita harus menggunakan super?
Ini salah satu poin penting dari video.
Kasus 1 — superclass punya default constructor
Misalnya:
class A {
A() {
print("A");
}
}
class B extends A {
B() {
print("B");
}
}
Tidak wajib menulis:
super();
Karena Dart akan melakukannya secara implicit.
Kasus 2 — superclass tidak punya default constructor
Misalnya:
class A {
A(int x) {}
}
Maka kita harus menentukan constructor yang dipanggil:
class B extends A {
B() : super(10) {}
}
Kasus 3 — superclass punya beberapa constructor dan kita ingin memilih constructor tertentu
Misalnya:
class A {
A() {
print("default");
}
A(int x) {
print("parameter: $x");
}
A.named() {
print("named");
}
}
Kita bisa memilih:
class B extends A {
B() : super.named() {
print("B");
}
}
Jadi meskipun A() tersedia, kita ingin secara sengaja memilih A.named().
Maka gunakan super.
16. Factory constructor subclass tidak bisa menggunakan super(...)
Ini bagian yang cukup penting.
Misalnya:
class A {
A() {
print("A");
}
}
class B extends A {
factory B() {
return B._internal();
}
B._internal() {
print("B");
}
}
Factory constructor:
factory B()
tidak bisa ditulis seperti:
factory B() : super();
Kenapa?
Karena factory constructor bukan constructor generative yang langsung menginisialisasi instance B.
Factory bertugas:
“Saya akan menentukan object mana yang harus dikembalikan.”
Contoh:
factory B() {
return B._internal();
}
Sedangkan generative constructor:
B() : super();
sedang melakukan initialization object secara langsung.
17. Generative constructor vs factory constructor
Ini cara paling mudah mengingatnya.
Generative constructor
class Person {
Person(this.name);
String name;
}
Generative constructor secara langsung melakukan proses pembuatan/inisialisasi instance.
Factory
class Person {
Person._internal(this.name);
String name;
factory Person() {
return Person._internal("Sam");
}
}
Factory berkata:
“Object yang saya return adalah object ini.”
Jadi:
Generative
→ membangun/menginisialisasi instance
Factory
→ menentukan instance mana yang dikembalikan
18. Factory constructor superclass juga tidak bisa dipanggil dengan super
Misalnya:
class A {
A() {
print("A generative");
}
factory A.test() {
return A();
}
}
Kemudian:
class B extends A {
B() : super.test();
}
Ini tidak diperbolehkan.
Kenapa?
Karena super(...) untuk constructor invocation mengharapkan generative constructor superclass, bukan factory constructor.
Jadi:
super(...)
↓
generative constructor
bukan:
super(...)
↓
factory constructor
19. Abstract class tetap bisa punya constructor
Ini sering mengejutkan pemula.
Misalnya:
abstract class Animal {
Animal() {
print("Animal constructor");
}
}
class Cat extends Animal {
Cat() {
print("Cat constructor");
}
}
Kita tidak bisa melakukan:
Animal();
karena Animal adalah abstract class.
Tetapi kita bisa membuat:
Cat();
Dan output:
Animal constructor
Cat constructor
Jadi:
Abstract class tidak dapat dibuat object-nya secara langsung, tetapi constructor abstract class tetap dapat dipanggil sebagai bagian dari proses pembuatan subclass.
20. Abstract class dengan constructor berparameter
Misalnya:
abstract class Animal {
String name;
Animal(this.name);
}
Subclass:
class Cat extends Animal {
Cat(String name) : super(name);
}
Sekarang:
Cat("Milo");
akan memanggil:
Cat("Milo")
↓
Animal("Milo")
21. Abstract class dengan named constructor
Bisa juga:
abstract class Animal {
Animal.named(String name) {
print("Animal: $name");
}
}
Subclass:
class Cat extends Animal {
Cat(String name) : super.named(name) {
print("Cat");
}
}
Kemudian:
Cat("Milo");
Output:
Animal: Milo
Cat
Jadi abstract class tidak menghilangkan kemampuan constructor.
22. extends dan implements sangat berbeda
Ini poin yang sangat penting.
Misalnya:
class A {
A() {
print("A");
}
void test() {
print("test");
}
}
Kalau:
class B extends A {
B() {
print("B");
}
}
maka A adalah superclass.
Constructor A dapat dipanggil:
B() : super();
Tetapi kalau:
class B implements A {
B() {
print("B");
}
@override
void test() {
print("B test");
}
}
A diperlakukan sebagai interface, bukan superclass untuk inheritance implementation.
Constructor A tidak dipanggil.
Output:
B
bukan:
A
B
Jadi:
extends
↓
superclass
↓
constructor superclass dapat dipanggil
sedangkan:
implements
↓
interface contract
↓
constructor A tidak dipanggil
23. this dan super tidak bisa digunakan bersamaan dalam constructor
Ini juga masuk dalam poin video.
Misalnya:
class A {
A() {}
}
class B extends A {
B() {}
B.demo() : super();
}
Di satu constructor kita ingin:
B.demo() : super(), this();
Ini tidak diperbolehkan.
Kenapa?
Karena:
this(...)
dan:
super(...)
memiliki dua tujuan berbeda.
this(...)
Mengarah ke constructor di class yang sama.
B.demo() : this();
artinya:
B.demo()
↓
B()
super(...)
Mengarah ke constructor superclass.
B.demo() : super();
artinya:
B.demo()
↓
A()
Satu constructor tidak bisa sekaligus melakukan dua jalur initialization tersebut.
24. Gambaran this(...) vs super(...)
Misalnya:
class A {
A() {
print("A");
}
}
class B extends A {
B() {
print("B");
}
B.demo() : this();
}
Kalau:
B.demo();
alur sederhananya:
B.demo()
↓
B()
↓
super A()
↓
A
↓
B
Karena B.demo() redirect ke B().
Sedangkan:
B.demo() : super();
berarti:
B.demo()
↓
A()
↓
B.demo() body
Jadi:
this(...) → constructor class sendiri
super(...) → constructor superclass
25. Initializer list dan super tidak bisa digunakan bersamaan?
Nah, di sini transcript perlu diluruskan.
Video mengatakan initializer list dan super tidak bisa digunakan bersamaan. Ini tidak tepat untuk Dart.
Justru Dart memungkinkan kita menggunakan initializer list dan superclass constructor invocation dalam constructor yang sama.
Contoh:
class A {
A(int x) {
print("A: $x");
}
}
class B extends A {
int y;
B(int x, int y)
: y = y * 2,
super(x) {
print("B");
}
}
Ini valid.
Perhatikan:
: y = y * 2,
super(x)
Di sini kita menggunakan:
- initializer list
super(x)
secara bersamaan.
26. Jadi apa sebenarnya yang tidak boleh?
Yang tidak boleh adalah menggunakan redirecting constructor this(...) sekaligus initializer list atau super(...) pada constructor yang sama.
Misalnya konsep seperti:
B.demo() : this(), super();
tidak boleh.
Dan redirecting constructor:
B.demo() : this();
tidak memiliki body sendiri untuk initialization tambahan.
Jadi lebih tepat mengingat:
this(...) → redirect ke constructor class sendiri
super(...) → panggil constructor superclass
initializer list → initialize field
super(...) dan initializer list dapat muncul bersama.
27. Contoh lengkap: initializer list + super
Perhatikan contoh berikut:
class Person {
String name;
int age;
Person(this.name, this.age) {
print("Person constructor");
}
}
class Employee extends Person {
double salary;
String position;
Employee(
String name,
int age,
double salary,
String position,
) : salary = salary,
position = position,
super(name, age) {
print("Employee constructor");
}
}
Saat:
Employee(
"Sam",
21,
25000,
"Designer",
);
alur konseptualnya:
Employee constructor dipanggil
↓
initializer/super diproses
↓
Person(name, age)
↓
name = "Sam"
age = 21
↓
initializer Employee
salary = 25000
position = "Designer"
↓
body Employee dijalankan
28. Urutan yang perlu kamu ingat
Untuk constructor subclass, secara sederhana pikirkan:
Subclass constructor dipanggil
↓
Superclass constructor dipanggil
↓
Field/initializer subclass diproses sesuai aturan initialization
↓
Body constructor subclass
Namun jangan terlalu menghafalkan sebagai urutan mentah; Dart punya aturan initialization yang lebih spesifik. Yang paling penting untuk level ini:
Superclass harus terinisialisasi sebelum body constructor subclass berjalan.
29. 10 poin penting dari materi ini — versi yang lebih rapi
Sekarang kita rangkum seluruh video menjadi 10 poin.
1. Constructor tidak diwariskan
Kalau:
class A {
A() {}
}
class B extends A {
}
constructor A bukan berarti menjadi constructor bernama A di B.
Constructor memang berhubungan dengan class yang membuat object.
2. Kalau superclass tidak menulis constructor, biasanya ada default constructor
class A {}
secara konseptual memiliki constructor default yang memungkinkan subclass memanggilnya.
3. Superclass constructor dijalankan sebelum subclass constructor body
A()
↓
B()
bukan:
B()
↓
A()
4. Gunakan super(...) jika ingin memilih constructor superclass
class A {
A(int x) {}
A.named() {}
}
class B extends A {
B() : super(10);
}
atau:
class B extends A {
B.demo() : super.named();
}
5. Factory constructor subclass tidak bisa memakai super(...)
Karena factory bukan generative constructor yang melakukan initialization instance secara langsung.
6. Factory constructor superclass tidak bisa dipanggil dengan super(...)
super(...) dalam constructor subclass harus mengarah ke generative constructor superclass.
7. Constructor abstract class bisa dipanggil melalui subclass
abstract class A {
A() {}
}
class B extends A {
B() {}
}
B() dapat menyebabkan constructor A dijalankan.
8. Constructor interface tidak dipanggil
Dengan:
class B implements A
constructor A tidak dijalankan.
Dengan:
class B extends A
constructor superclass dapat dijalankan.
9. this(...) dan super(...) tidak bisa digunakan pada constructor yang sama
this(...) → constructor class sendiri
super(...) → constructor superclass
Pilih salah satu jalur.
10. Initializer list dan super(...) sebenarnya bisa digunakan bersama
Ini koreksi penting terhadap transcript.
Contoh valid:
class B extends A {
int y;
B(int x, int y)
: y = y * 2,
super(x);
}
Jadi jangan menghafal:
“initializer list tidak boleh bersama super”
karena itu tidak benar.
30. Diagram besar seluruh konsep
Kalau kamu ingin mengingat materi ini dengan satu diagram, gunakan ini:
Object
│
▼
Person
┌──────┴──────┐
│ │
constructor fields
│
▼
Employee
│
constructor
│
super(name, age)
│
▼
Person constructor
│
▼
Person selesai
│
▼
Employee initialization
│
▼
Employee body
Dan jenis constructor call-nya:
super()
│
└── unnamed superclass constructor
super(10)
│
└── unnamed parameterized constructor
super.named(...)
│
└── named superclass constructor
Sedangkan:
this()
│
└── constructor lain dalam class yang sama
this.named()
│
└── named constructor dalam class yang sama
31. Hubungkan dengan materi Flutter
Konsep ini sangat relevan di Flutter.
Contohnya:
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return const Text("Hello");
}
}
Bagian:
const MyPage({super.key});
menggunakan fitur Dart modern untuk meneruskan named parameter key ke constructor superclass.
Secara konsep mirip:
MyPage({Key? key}) : super(key: key);
Jadi ketika kamu nanti melihat:
super.key
jangan bingung.
Itu masih berhubungan dengan konsep:
parameter constructor subclass diteruskan ke constructor superclass.
32. Cheat sheet super vs this
| Syntax | Arti |
|---|---|
this | object saat ini |
this.name | field/member object saat ini |
this(...) | redirect ke constructor lain di class yang sama |
super(...) | panggil constructor superclass |
super.method() | panggil method superclass |
super.field | akses member superclass |
Contoh:
class Child extends Parent {
Child() : super();
Child.demo() : this();
}
Artinya:
super() → Parent()
this() → Child()
33. Inti paling penting untuk pemula
Kalau seluruh video terasa terlalu banyak, jangan hafalkan 10 poin sekaligus. Pegang dulu 5 konsep ini:
1. extends
class B extends A
berarti:
B adalah subclass dari A.
2. Constructor superclass berjalan lebih dahulu
A → B
3. Kalau A() tersedia, Dart bisa memanggilnya secara implicit
class B extends A {
B() {}
}
4. Kalau ingin memilih constructor tertentu, gunakan super
B() : super(10);
atau:
B() : super.named();
5. Bedakan this dan super
this(...) → constructor di class sendiri
super(...) → constructor di superclass
Satu kalimat untuk mengingat semuanya
Ketika membuat object subclass, Dart harus menyelesaikan initialization superclass terlebih dahulu; jika constructor superclass yang dibutuhkan tidak bisa dipanggil secara otomatis, kita menentukan constructor tersebut dengan
super(...).
Dan satu koreksi terpenting dari transcript: pernyataan bahwa initializer list tidak boleh dipakai bersama super adalah keliru. Di Dart, initializer list dan super(...) dapat digunakan dalam constructor yang sama. Yang tidak boleh dicampur adalah mekanisme redirecting constructor this(...) dengan super(...)/initializer list pada constructor yang sama.