Tampilan
Kenapa penting
Di M01 semua kodemu berupa method static yang menerima data lewat parameter. Itu cukup untuk perhitungan kecil, tetapi aplikasi backend memodelkan hal-hal yang punya data dan perilaku sendiri: produk dengan harga dan stok, pesanan dengan status, pengguna dengan email. Java adalah bahasa berorientasi object (OOP), dan seluruh ekosistemnya — Spring Boot, JPA, library JSON — dibangun di atas class dan object. Bab ini fondasi untuk seluruh modul M02.
Konsep inti
Class sebagai blueprint, object sebagai wujudnya
Class adalah cetak biru: ia mendeskripsikan data apa yang dimiliki (field) dan apa yang bisa dilakukan (method). Object adalah wujud nyata yang dibuat dari class itu dengan kata kunci new. Satu class bisa melahirkan banyak object, dan setiap object menyimpan nilai field-nya sendiri.
java
class Product {
String name;
long price;
int stock;
long stockValue() {
return price * stock;
}
boolean isAvailable() {
return stock > 0;
}
}
public class ProductDemo {
public static void main(String[] args) {
Product coffee = new Product();
coffee.name = "Kopi Gayo";
coffee.price = 85_000;
coffee.stock = 12;
Product tea = new Product();
tea.name = "Teh Melati";
tea.price = 40_000;
System.out.println(coffee.name + " — nilai stok: " + coffee.stockValue());
System.out.println(tea.name + " tersedia? " + tea.isAvailable());
System.out.println(tea.stock);
}
}Output:
text
Kopi Gayo — nilai stok: 1020000
Teh Melati tersedia? false
0Beberapa hal yang perlu diperhatikan:
- Satu file boleh berisi beberapa class, tetapi hanya satu yang
publicdan namanya harus sama dengan nama file. Itulah sebabnya contoh ini bisa langsung dijalankan denganjava ProductDemo.java. Di project nyata, setiap class biasanya punya file sendiri. - Field dan method diakses dengan titik:
coffee.price,coffee.stockValue(). tea.stocktidak pernah diisi, tetapi hasilnya0, bukan error. Field mendapat nilai default:0untuk angka,falseuntukboolean, dannulluntuk tipe referensi sepertiString. Variabel lokal di dalam method tidak punya nilai default — wajib diisi sebelum dibaca.
Method instance vs method static
Method tanpa static disebut method instance: ia dipanggil lewat sebuah object dan bisa membaca serta mengubah field object itu. Method static milik class — dipanggil lewat nama class dan tidak terikat object mana pun.
java
class Cart {
int itemCount;
long total;
void add(long unitPrice, int quantity) { // method instance: memakai data object ini
itemCount += quantity;
total += unitPrice * quantity;
}
static long withTax(long amount) { // method static: tidak butuh data object mana pun
return amount + amount * 11 / 100;
}
}
public class CartDemo {
public static void main(String[] args) {
Cart budiCart = new Cart();
Cart sariCart = new Cart();
budiCart.add(50_000, 2);
sariCart.add(10_000, 1);
System.out.println("Budi: " + budiCart.itemCount + " item, Rp" + budiCart.total);
System.out.println("Sari: " + sariCart.itemCount + " item, Rp" + sariCart.total);
System.out.println("Budi + PPN: Rp" + Cart.withTax(budiCart.total));
}
}Output:
text
Budi: 2 item, Rp100000
Sari: 1 item, Rp10000
Budi + PPN: Rp111000Keranjang Budi dan Sari tidak saling mengganggu karena masing-masing object punya itemCount dan total sendiri. Sebaliknya, withTax hanya menghitung dari parameternya, jadi cocok dibuat static.
Aturan praktis: kalau method membutuhkan state (data) milik object, jadikan method instance. Kalau method hanya mengolah parameter — seperti semua method di M01 — boleh static. Method static tidak bisa langsung membaca field instance; compiler akan menolak dengan pesan non-static variable price cannot be referenced from a static context.
Variabel object menyimpan referensi
Ingat dari bab Tipe Data: tipe selain primitif adalah tipe referensi. Variabel Product coffee tidak berisi object-nya, melainkan referensi (alamat) ke object yang tersimpan di memori. Akibatnya, menyalin variabel berarti menyalin referensi — bukan menyalin object.
java
class Counter {
int value;
}
public class ReferenceDemo {
static void increment(Counter counter) {
counter.value++; // mengubah object yang ditunjuk
}
static void replace(Counter counter) {
counter = new Counter(); // hanya mengganti salinan referensi
counter.value = 100;
}
public static void main(String[] args) {
Counter a = new Counter();
Counter b = a; // b menunjuk object yang SAMA dengan a
b.value = 5;
System.out.println(a.value);
increment(a);
System.out.println(a.value);
replace(a);
System.out.println(a.value);
Counter c = new Counter();
c.value = 6;
System.out.println(a == b);
System.out.println(a == c);
}
}Output: 5, 6, 6, true, false. Ini persis aturan pass-by-value dari bab Method dan bab String & Array: method menerima salinan referensi, sehingga bisa mengubah isi object (increment), tetapi tidak bisa membuat variabel a menunjuk object lain (replace). Operator == pada object membandingkan apakah dua referensi menunjuk object yang sama — a dan c punya value yang sama, tetapi object-nya berbeda.
Variabel object juga bisa bernilai null: tidak menunjuk object apa pun. Memanggil method atau membaca field lewat referensi null menghentikan program dengan NullPointerException. Object yang sudah tidak ditunjuk referensi mana pun akan dibersihkan otomatis oleh garbage collector.
toString: agar object bisa dibaca
Saat object dicetak dengan println atau digabung dengan String, Java memanggil method toString() milik object itu. Bawaannya hanya mencetak nama class dan kode hash — tidak berguna untuk log. Kamu bisa menulis versimu sendiri:
java
class Money {
long amount;
}
class Product {
String name;
long price;
@Override
public String toString() {
return "Product[name=" + name + ", price=" + price + "]";
}
}
public class ToStringDemo {
public static void main(String[] args) {
Money money = new Money();
money.amount = 5_000;
Product product = new Product();
product.name = "Kopi Gayo";
product.price = 85_000;
System.out.println(money);
System.out.println(product);
System.out.println("Dipesan: " + product);
}
}Output:
text
Money@221af3c0
Product[name=Kopi Gayo, price=85000]
Dipesan: Product[name=Kopi Gayo, price=85000]Angka setelah @ pada Money bisa berbeda di mesinmu. Anotasi @Override menandai bahwa method ini menggantikan versi bawaan; dari mana versi bawaan itu berasal dibahas di bab Inheritance. Untuk sekarang, cukup ingat: toString harus public dan mengembalikan String.
Contoh di dunia backend
Sebuah pesanan (order) di toko online punya data — ID, email pelanggan, total, status — dan perilaku: menambah item, menerima pembayaran, membuat ringkasan. Dengan class, data dan aturan itu dikumpulkan di satu tempat:
java
class Order {
String id;
String customerEmail;
long total;
int itemCount;
String status = "NEW";
void addItem(long unitPrice, int quantity) {
total += unitPrice * quantity;
itemCount += quantity;
}
boolean pay(long amount) {
if (!status.equals("NEW") || amount != total) {
return false;
}
status = "PAID";
return true;
}
String summary() {
return id + " (" + customerEmail + "): " + itemCount + " item, Rp" + total + ", " + status;
}
}
public class OrderDemo {
public static void main(String[] args) {
Order order = new Order();
order.id = "INV-001";
order.customerEmail = "budi@contoh.com";
order.addItem(85_000, 2);
order.addItem(40_000, 1);
System.out.println(order.summary());
System.out.println(order.pay(200_000));
System.out.println(order.pay(210_000));
System.out.println(order.pay(210_000));
System.out.println(order.summary());
Order another = new Order();
another.id = "INV-002";
System.out.println(another.summary());
}
}Output:
text
INV-001 (budi@contoh.com): 3 item, Rp210000, NEW
false
true
false
INV-001 (budi@contoh.com): 3 item, Rp210000, PAID
INV-002 (null): 0 item, Rp0, NEWField boleh punya nilai awal (status = "NEW"), sehingga setiap order baru langsung berstatus NEW. Method pay menolak pembayaran yang jumlahnya tidak cocok atau order yang sudah dibayar — aturan bisnis tinggal di dalam object, bukan tersebar di banyak tempat.
Namun desain ini masih bocor: kode lain bisa menulis order.total = 0; atau order.status = "PAID"; tanpa lewat pay, dan INV-002 bisa dibuat tanpa email. Bab berikutnya, Encapsulation, menutup celah itu.
Pertanyaan interview
1. Apa beda class dan object?
Class adalah definisi atau cetak biru yang mendeskripsikan field dan method. Object adalah instance konkret dari class itu, dibuat dengan new, dan menyimpan nilai field-nya sendiri di memori. Satu class bisa punya banyak object.
2. Apa beda method instance dan method static? Kapan memakai static?
Method instance dipanggil lewat object dan bisa memakai field object tersebut. Method static milik class dan tidak punya akses ke field instance. Pakai static untuk fungsi utilitas yang hanya bergantung pada parameternya (mis. perhitungan pajak); pakai method instance bila perilakunya bergantung pada state object.
3. Apa yang terjadi saat kamu menulis Product b = a;?
Tidak ada object baru. Referensi di a disalin ke b, sehingga keduanya menunjuk object yang sama; perubahan lewat b terlihat lewat a. Object hidup di heap, sedangkan variabel hanya menyimpan referensinya. Object yang tidak lagi direferensikan akan dibersihkan garbage collector.
Jebakan umum
- Mengira
b = amenyalin object. Yang tersalin hanya referensi; ubah satu, keduanya ikut berubah. - Memanggil method lewat referensi
null→NullPointerException. Pastikan object ada sebelum dipakai. - Membuat semua method
statickarena kebiasaan dari M01, lalu mengoper data lewat parameter berulang-ulang. Kalau data dan perilaku selalu berjalan bersama, satukan dalam object. - Membandingkan object dengan
==padahal maksudnya isi yang sama.==hanya memeriksa apakah object-nya sama; perbandingan isi dibahas di M03 (equals&hashCode). - Lupa menulis
toStringsehingga log hanya berisiProduct@1b6d3586.
Ringkasan
- Class mendefinisikan field (data) dan method (perilaku); object dibuat dengan
newdan punya state sendiri. - Field mendapat nilai default (
0,false,null); variabel lokal wajib diisi sebelum dipakai. - Method instance memakai state object; method
staticmilik class dan tidak bisa membaca field instance. - Variabel object menyimpan referensi:
b = aberbagi object yang sama,nullberarti tidak ada object. - Override
toStringagar object mudah dibaca di log dan saat debugging.