Showing posts with label java pemula. Show all posts
Showing posts with label java pemula. Show all posts

Thursday

ARRAY

Array adalah struktur data yang terdiri dari item berurutan, di mana semua itemnya bertipe sama. Dalam Java, item dalam array selalu dinomori dari nol hingga nilai maksimum tertentu, yang nilainya ditentukan pada saat array tersebut dibuat. Misalnya, suatu array berisi 100 bilangan bulat, yang dinomori dari nol hingga 99. Item dalam array bisa bertipe salah satu tipe Java primitif. Item-item ini bisa juga berupa referensi ke objek, sehingga, misalnya kita bisa membuat array yang berisi semua komponen dalam applet.
Bagian ini akan membahas bagaimana array dibuat dan digunakan pada Java. Juga mencakup kelas standar java.util.ArrayList. Suatu objek bertipe ArrayList sangat mirip dengan array dari Object, akan tetapi ia bisa bertambah ukuran secara dinamis.

PENGENALAN STRUKTUR DATA DAN ALGORITMA

Dalam membuat suatu program kita pasti akan merancang program tersebut dengan konsep dan struktur yang tepat dan dinamis, maksudnya bahwa konsep dan struktur tersebut dimulai dengan perhitungan yang tepat dan proses yang benar dan berurutan. Demikian juga dalam pemrograman Java, struktur data sangat penting untuk memudahkan dalam penegcekan dan edit coding ketika muncul eror. Struktur data dalam Java masih cenderung menggunakan metode diagram trees (pohon), diagram ini sering dibahas dalam mata kuliah Sistem Basis Data.
Sedangkan pengertian Algoritma Sorting adalah kumpulan langkah sistematis atau secara berutan untuk memperoleh hasil yang diinginkan. Salah satu contoh dari algoritma untuk langkah ini adalah Sorting (pengurutan). Sorting dapat didefinisikan sebagai pengurutan sejumlah data berdasarkan nilai tertentu. Pengurutan dapat dilakukan dari nilai terkecil ke nilai terbesar (ascending) atau sebaliknya.

Langsung saja kita bahas satu persatu,

Pemrograman dengan Array

Array merupakan jenis struktur data yang sangat dasar dan sangat penting. Teknik pengolahan array merupakan teknik pemrograman yang paling penting yang kita harus kuasai. Dua jenis teknik pengolahan array -- pencarian dan pengurutan -- akan dibahas kemudian. Bagian ini akan memperkenalkan beberapa ide dasar pengolahan array secara umum.
Dalam banyak hal, pengolahan array berarti menggunakan operasi yang sama kepada setiap elemen di dalam array. Biasanya sering dilakukan dengan perulangan for. Perulangan untuk mengolah semua elemen dalam array A dapat ditulis dalam bentuk :
// lakukan inisialiasi yang diperlukan sebelumnya
for (int i = 0; i < A.length; i++) {
    . . . // proses A[i]
}
Misalnya, A adalah array dengan tipe double[]. Misalnya kita ingin menjumlah semua nilai dalam array tersebut. Algoritma umum untuk melakukannya adalah :
Mulai dengan 0;
Tambah A[0];   (proses elemen pertama di dalam A)
Tambah A[1];   (proses elemen kedua di dalam A)
.
.
.
Tambah A[ A.length - 1 ];   (proses elemen terakhir di dalam A)
Dengan menggunakan pengetahuan yang kita telah pelajari tentang perulangan, kita bisa ubah algoritma di atas menjadi bentuk perulangan for seperti berikut:
double jumlah;  // Jumlah nilai di dalam A
jumlah  = 0;    // Mulai dengan 0
for (int i = 0; i < A.length; i++)
    jumlah += A[i];  // tambah A[i] ke dalam jumlah untuk i = 0, 1, ..., A.length - 1
Lihat bahwa kondisi kelanjutan "i < A.length" menyatakan bahwa nilai i terakhir yang akan diolah adalah A.length - 1 yaitu elemen terakhir dalam array. Ingat bahwa kita menggunakan "<" bukan "<=" karena dengan "<=" komputer akan memberikan kesalahan indeks di luar batas.
Pada akhirnya, nanti Anda akan bisa membuat perulangan seperti di atas di luar kepala. Kita akan lihat beberapa contohnya. Di sini perulangan akan menghitung banyaknya elemen di dalam array A yang nilainya kurang dari nol :
int hitung;  // Untuk menghitung elemen
hitung = 0;  // Mulai dengan nol
for (int i = 0; i < A.length; i++) {
    if (A[i] < 0.0)   // Jika elemen ini kurang dari nol
        hitung++;          // tambah hitung dengan 1
}
// Di sini nilai "hitung" adalah banyaknya elemen yang kurang dari 0.
Kita bisa mengganti "A[i] < 0.0" jika kita ingin menghitung banyaknya elemen di dalam array yang memiliki sifat tertentu. Variasinya akan memiliki tema yang sama. Misalnya kita ingin menghitung banyaknya elemen di dalam array A yang sama dengan elemen sesudahnya. Elemen setelah A[i] adalah A[i+1], sehingga kita bisa mengganti klausa if dengan "if (A[i] == A[i+1])". Akan tetapi tunggu dulu : Tes ini tidak bisa digunakan apabila A[i] adalah elemen terakhir dalam array, karena tidak ada lagi array sesudahnya. Komputer akan menolak pernyataan ini. Sehingga kita harus berhenti satu elemen sebelum array terakhir, sehingga menjadi,
int hitung = 0;
// lihat kondisi for berubah dibandingkan dengan contoh sebelumnya
for (int i = 0; i < A.length - 1; i++) { 
    if (A[i] == A[i+1])
        hitung++;
}
Masalah umum lainnya adalah mencari nilai terbesar di dalam array A. Strateginya adalah lihat semua isi array, catat nilai terbesar saat itu. Kita akan simpan nilai terbesar yang kita temui dalam variabel maks. Pada saat kita melihat elemen array satu per satu, kapanpun kita melihat nilai elemen tersebut lebih besar dari maks kita akan mengganti nilai maks dengan nilai yang lebih besar tersebut. Setelah semua elemen array diproses, maka maks merupakan nilai elemen terbesar di dalam array tersebut. Pertanyaannya adalah, apa nilai awal maks? Salah satu kemungkinannya adalah mulai dengan nilai maks sama dengan A[0], baru kemudian melihat isi elemen array lainnya mulai dengan A[1]. Misalnya,
double maks = A[0];  // nilai maks berisi elemen array pertama
for (int i = 1; i < A.length; i++) {  // i mulai dari elemen kedua
    if (A[i] > maks)
        max = A[i];
}
// Di sini maks berisi nilai elemen array yang paling besar
(Ada masalah yang lebih penting di sini. Java membolehkan array memiliki panjang nol. Artinya bahkan A[0] pun tidak ada di dalam array, sehingga memanggil A[0] akan menghasilkan kesalahan indeks keluar batas. Akan tetapi array biasanya array dengan panjang nol biasanya sesuatu yang kita ingin hindarkan dalam kehidupan sehari-hari. Lagian apa artinya mencari nilai terbesar di dalam suatu array yang panjangnya nol?)
Contoh terakhir dari operasi array, misalnya kita ingin mengkopi suatu array. Untuk mengkopi array A, tidak cukup untuk menggunakan perintah
double[] B = A;
karena perintah ini tidak membuat objek array baru. Yang dibuat di sini adalah variabel baru yang merujuk pada objek yang sama dengan A. (Sehingga perubahan yang terjadi pada A[i] akan juga menyebabkan B[i] berubah). Untuk membuat array baru yang merupakan kopi dari array A, kita harus membuat objek array baru, dan mengkopi isinya satu per satu dari array A ke array baru, sehingga
// Buat objek array baru, yang panjangnya sama dengan panjang A
double[] B = new double[A.length]; 
 
for (int i = 0; i < A.length; i++)
    B[i] = A[i];   // Kopi setiap elemen dari A ke B
Mengkopi nilai dari satu array ke array yang lain adalah operasi umum sehingga Java memiliki subrutin untuk melakukannya, yaitu System.arraycopy(), yang merupakan subrutin anggota statik dari kelas standar System. Deklarasinya memiliki bentuk seperti :
public static void arraycopy(Object arraySumber, int indeksAwalSumber,
    Object arrayTujuan, int indeksAwalTujuan, int jumlah)
di mana arraySumber dan arrayTujuan bisa berbentuk array dengan tipe apapun. Nilai akan dikopi dari arraySumber ke arrayTujuan. jumlah adalah berapa banyak elemen yang akan dikopi. Nilai akan dikopi dari arraySumber mulai dari posisi indeksAwalSumber dan akan disimpan pada arrayTujuan mulai dari posisi indeksAwalTujuan. Misalnya kita akan mengkopi array A, maka kita bisa menggunakan perintah
double B = new double[A.length];
System.arraycopy( A, 0, B, 0, A.length );
Suatu tipe array, misalnya double[] adalah tipe Java biasa, sehingga kita bisa menggunakannya seperti tipe-tipe Java lainnya. Termasuk juga digunakan sebagai parameter formal di dalam suatu subrutin. Juga bisa digunakan sebagai tipe keluaran suatu fungsi. Misalnya, kita bisa menulis fungsi yang membuat kopi array dengan tipe double sebagai berikut :
double[]  kopi( double[] sumber ) {
    // Membuat dan mengembalikan kopi array sumber
    // Jika sumber null, maka kembalikan null
    if ( sumber == null )
        return null;
    double[]  kpi;  // Kopi array sumber
    kpi = new double[sumber.length];
    System.arraycopy( sumber, 0, kpi, 0, sumber.length );
    return kpi;
}
Rutin main() memiliki parameter dengan tipe String[] yang merupakan array String. Ketika sistem memanggil rutin main(), string di dalam array ini adalah parameter dari baris perintah. Jika kita menggunakan konsol, user harus mengetikkan perintah untuk menjalankan program. User bisa menambahkan input tambahan dalam perintah ini setelah nama program yang akan dijalankan.
Misalnya, jika kelas yang memiliki rutin main() bernama programKu, maka user bisa menjalankan kelas tersebut dengan perintah "java programKu" di konsol. Jika kita tulis dengan "java programKu satu dua tiga", maka parameter dari baris perintahnya adalah "satu", "dua", dan "tiga". Sistem akan memasukkan parameter-parameter ini ke dalam array String[] dan memberikan array ini pada rutin main().
Berikut ini adalah contoh program sederhana yang hanya mencetak parameter dari baris perintah yang dimasukkan oleh user.
public class CLDemo {
    public static void main(String[] args) {
        System.out.println("Anda memasukkan " + args.length
            + " parameter dari baris perintah");
        if (args.length > 0) {
            System.out.println("Parameter tersebut adaah :");
            for (int i = 0; i < args.length; i++)
                System.out.println("   " + args[i]);
            }
    } // akhir main()
} // akhir kelas CLDemo
Perhatikan bahwa parameter args tidak mungkin null meskipun tidak ada parameter yang dimasukkan. Jika tidak ada parameter dari baris perintah yang dimasukkan, maka panjang array ini adalah nol.

Hingga sekarang, contoh yang telah diberikan adalah bagaimana mengolah array dengan mengakses elemennya secara berurutan (sequential access). Artinya elemen-elemen array diproses satu per satu dalam urutan dari awal hingga akhir. Akan tetapi salah satu keuntungan array adalah bahwa array bisa digunakan untuk mengakses elemennya secara acak, yaitu setiap elemen bisa diakses kapan saja secara langsung.
Misalnya, kita ambil contoh suatu masalah yang disebut dengan masalah ulang tahun: Misalnya ada N orang di dalam suatu ruangan. Berapa kemungkinan dua orang di dalam ruangan tersebut memiliki ulang tahun yang sama (yang dilahirkan pada tanggal dan bulan yang sama, meskipun tahunnya berbeda)? Kebanyakan orang salah menerka jawabannya. Sekarang kita lihat dengan versi masalah yang berbeda: Misalnya kita memilih orang secara acak dan menanyakan ulang tahunnya. Berapa orang yang Anda harus tanya untuk mendapatkan hari ulang tahun yang sama dengan orang sebelumnya?
Tentunya jawabannya akan tergantung pada faktor yang bersifat acak, akan tetapi kita bisa simulasikan dengan program komputer dan menjalankan beberapa kali hingga kita tahu berapa kira-kira orang harus dicek.
Untuk mensimulasikan percobaan ini, kita harus mencatat semua ulang tahun yang kita sudah tanyakan. Ada 365 kemungkinan hari ulang tahun (Kita abaikan sementara tahun kabisat). Untuk setiap kemungkinan hari ulang tahun, kita perlu tahu, apakah hari ulang tahun tersebut telah digunakan? Jawabannya adalah nilai boolean true atau false. Untuk menyimpan data ini, kita bisa gunakan array dari 365 nilai boolean:
boolean[] sudahDitanya;
sudahDitanya = new boolean[365];
Tanggal-tanggal pada satu tahun dinomori dari 0 hingga 364. Nilai sudahDitanya[i] akan bernilai true jika orang yang kita tanya berulang tahun pada hari tersebut. Pada awalnya semua nilai pada array sudahDitanya[i] bernilai false. Ketika kita memilih satu orang dan menanyakan hari ulang tahunnya, misalnya i, kita akan mengecek terlebih dahulu apakah sudahDitanya[i] bernilai true. Jika tidak maka orang ini adalah orang kedua dengan ulang tahun yang sama. Artinya kita sudah selesai.
Jika sudahDitanya[i] bernilai false, maka belum ada orang sebelum ini yang memiliki hari ulang tahun tersebut. Kita akan ganti sudahDitanya[i] dengan true, kemudian kita akan tanyakan lagi kepada orang lain, dan begitu seterusnya hingga semua orang di dalam ruangan ditanyakan.
static void masalahUlangTahun() {
    // Melakukan simulasi dengan memilih seseorang secara acak
    // dan mengecek hari ulang tahunnya. Jika hari ulang tahunnya
    // sama dengan orang yang pernah kita tanya sebelumnya,
    // hentikan program dan laporkan berapa orang yang sudah dicek
 
    boolean[] sudahDitanya;
    // Untuk mencatat ulang tahun yang sudah ditanyakan
    // Nilai true pada sudahDitanya[i] berarti orang lain
    // sudah ada yang berulang tahun pada hari i
 
    int hitung;
    // Jumlah orang yang sudah pernah ditanya
 
    sudahDitanya = new boolean[365];
    // Awalnya, semua nilai adalah false
 
    hitung = 0;
 
    while (true) {
        // Ambil ulang tahun secara acak dari 0 hingga 364
        // Jika ulang tahun telah ditanya sebelumnya, keluar
        // Jika tidak catat dalam array
 
        int ultah;  // Ulang tahun seseorang
        ultah = (int)(Math.random()*365);
        hitung++;
        if ( sudahDitanya[ultah] )
            break;
        sudahDitanya[ultah] = true;
    }
 
    System.out.println("Ulang tahun yang sama ditemukan setelah menanyakan "
        + hitung + " orang.");
 
} // akhir masalahUlangTahun()
Subrutin ini menggunakan fakta bahwa array boolean yang baru dibuat memiliki seluruh elemen yang bernilai false. Jika kita ingin menggunakan array yang sama untuk simulasi kedua, kita harus mereset ulang semua elemen di dalamnya menjadi false kembali dengan perulangan for
for (int i = 0; i < 365; i++)
    sudahDitanya[i] = false;
Array paralel adalah menggunakan beberapa array dengan indeks yang sama. Misalnya kita ingin membuat beberapa kolom secara paralel -- array x di kolom pertama, array y di kolom kedua, array warna di kolom ketiga, dan seterusnya. Data untuk baris ke-i bisa didapatkan dari masing-masing array ini. Tidak ada yang salah dengan cara ini, akan tetapi cara ini berlawanan dengan filosofi berorientasi objek yang mengumpulkan data yang berhubungan di dalam satu objek. Jika kita mengikuti aturan seperti ini, amaka kita tidak harus membayangkan hubungan data yang satu dan yang lainnya karena semua data akan dikelompokkan di dalam satu tempat.
Misalnya saya menulis kelas seperti
class DataString {
    // Data dari salah satu pesan
    int x,y;        // Posisi pesan
    Color warna;    // Warna pesan
}
Untuk menyimpan data dalam beberapa pesan, kita bisa menggunakan array bertipe DataString[], yang kemudian dideklarasikan sebagai variabel instansi dengan nama data sehingga
DataString[] data;
Isi dari data bernilai null hingga kita membuat array baru, misalnya dengan
data = new DataString[JUMLAH_PESAN];
Setelah array ini dibuat, nilai setiap elemen array adalah null. Kita ingin menyimpan data di dalam objek yang bertipe DataString, akan tetapi tidak ada objek yang dibuat. Yang kita sudah buat hanyalah kontainernya saja. Elemen di dalamnya berupa objek yang belum pernah kita buat. Untuk itu elemen di dalamnya bisa kita buat dengan perulangan for seperti :
for (int i = 0; i < JUMLAH_PESAN; i++)
    data[i] = new DataString();
Sekarang kita bisa mengambil data setiap pesan dengan data[i].x, data[i].y, dan data[i].warna.

Terakhir berkaitan dengan pernyataan switch. Misalnya kita memiliki nilai bulan dari 0 hingga 11, yang melambangkan bulan dalam satu tahun dari Januari hingga Desember. Kita ingin mencetaknya di layar, dengan perintah
switch (bulan) {
case 0:
    bulanString = "Januari";
    break;
case 1:
    bulanString = "Februari";
    break;
case 2:
    bulanString = "Maret";
    break;
case 3:
    bulanString = "April";
    break;
.
.
.
case 11:
    bulanString = "Desember";
    break;
default:
    bulanString = "Salah bulan";
}
Kita bisa mengganti keseluruhan perintah switch tersebut dengan menggunakan array, misalnya dengan array namaBulan yang dideklarasikan sebagai berikut :
static String[] namaBulan = { "Januari", "Februari", "Maret",
    "April", "Mei", "Juni", "Juli", "Agustus", "September",
    "Oktober", "November", "Desember" };
Kemudian kita bisa ganti keseluruhan switch di atas dengan
bulanString = namaBulan[bulan];

Membuat dan Menggunakan Array

Jika sekumpulan data digabungkan dalam satu unit, hasilnya adalah suatu struktur data. Data struktur dapat berupa struktur yang sangat kompleks, akan tetapi dalam banyak aplikasi, data struktur yang cocok hanya terdiri dari kumpulan data berurutan. Struktur data sederhana seperti ini bisa berupa array atau record.
Istilah "record" sebetulnya tidak digunakan pada Java. Suatu record pada intinya mirip dengan objek pada Java yang hanya memiliki variabel instansi tanpa metode instansi. Beberapa bahasa pemrograman lain yang tidak mendukung objek biasanya mendukung record. Dalam bahasa C yang bukan bahasa berorientasi objek, misalnya, memiliki tipe data record, dimana pada C disebut "struct". Data pada record -- dalam Java, adalah variabel instansi suatu objek -- disebut field suatu record. Masing-masing item disebut nama field. Dalam Java, nama field adalah nama variabel instansi. Perbedaan sifat dari suatu record adalah bahwa item pada record dipanggil berdasarkan namanya, dan field yang berbeda dapat berupa tipe yang berbeda. Misalnya, kelas Orang didefisikan sebagai :
class Orang {
    String nama;
    int nomorID;
    Date tanggalLahir;
    int umur;
}
maka objek dari kelas Orang bisa disebut juga sebagai record dengan 4 field. Nama fieldnya adalah nama, nomorID, tanggalLahir dan umur. Lihat bahwa tipe datanya berbeda-beda yaitu String, int, dan Date.
Karena record hanya merupakan bagian lebih kecil dari objek, kita tidak akan bahas lebih lanjut di sini.
Seperti record, suatu array adalah kumpulan item. Akan tetapi, item pada record dipanggil dengan nama, sedangkan item pada array dinomori, dan masing-masing item dipanggil besarkan nomor posisi pada array tersebut. Semua item pada array harus bertipe sama. Definisi suatu array adalah : kumpulan item bernomor yang semuanya bertipe sama. Jumlah item dalam suatu array disebut panjang array. Nomor posisi dari array disebut indeks item tersebut dalam array. Tipe dari item tersebut disebut tipe dasar dari array.
Tipe dasar suatu array bisa berupa tipe Java apa saja, baik berupa tipe primitif, nama kelas, atau nama interface. Jika tipe dasar suatu array adalah int, maka array tersebut disebut "array int". Suatu array bertipe String disebut "array String". Akan tetapi array bukan urutan int atau urutan String atau urutan nilai bertipe apapun. Lebih baik jika array adalah urutan variabel bertipe int atau String atau tipe lainnya.
Seperti biasa, ada dua kemungkinan kegunaan variabel : sebagai nama suatu lokasi di memori, dan nama suatu nilai yang disimpan pada lokasi memori. Setiap posisi pada array bersifat seperti variabel. Setiap posisi dapat menyimpan nilai dengan tipe tertentu (yaitu tipe dasar array). Isinya bisa diganti kapanpun. Nilai tersebut disimpan di dalam array. Array merupakan kontainer bukan kumpulan nilai.
Item pada array (maksudnya setiap anggota variabel dalam array tersebut) sering juga disebut elemen array. Dalam Java, elemen array selalu dinomori mulai dari nol. Yaitu, indeks dari elemen pertama suatu array adalah nol. Jika panjang array adalah N, maka indeks elemen terakhir adalah N-1. Sekali array dibuat, maka panjangnya tidak bisa diubah lagi.
Dalam Java, array adalah objek. Ada beberapa konsekuensi yang lahir dari fakta ini. Array harus dibuat dengan operator new. Variabel tidak bisa menyimpan array; variabel hanya bisa merujuk pada array. Variabel lain yang bisa merujuk array juga bisa bernilai null yang berarti ia tidak merujuk pada lokasi memori apapun. Seperti objek lain, array juga bagian dari suatu kelas, di mana seperti kelas lain adalah kelas turunan dari kelas Object. Elemen array pada dasarnya adalah variabel instansi dalam objek array, kecuali mereka dipanggil dalam indeksnya bukan namanya.
Meskipun array berupa objek, ada beberapa perbedaan antara array dan objek lainnya, dan ada beberapa fitur khusus Java untuk membuat dan menggunakan array.

Misalnya A adalah variabel yang merujuk pada suatu array. Maka indeks k di dalam A bisa dipanggil dengan A[k]. Item pertama adalah A[0], yang kedua adalah A[i], dan seterusnya. A[k] adalah suatu variabel dan bisa digunakan seperti variabel lainnya. Kita bisa memberinya nilai, bisa menggunakannya dalam ekspresi, dan bisa diberikan sebagai parameter pada subrutin. Semuanya akan didiskusikan di bawah nanti. Untuk sekarang ingat sintaks berikut,
variabel_array [ekspresi_integer]
untuk merujuk pada suatu array.

Meskipun setiap array merupakan suatu objek, kelas array tidak harus didefinisikan sebelumnya. Jika suatu tipe telah ada, maka kelas array dari tipe tersebut otomatis ada. Jika nama suatu tipe adalah TipeDasar, maka nama kelas arraynya adalah TipeDasar[]. Artinya, suatu objek yang diciptakan dari kelas TipeDasar[] adalah array dari item yang tiap itemnya bertipe TipeDasar. Tanda kurung "[]" dimaksudkan untuk mengingat sintaks untuk mengambil item di dalam suatu array. "TipeDasar[]" dibaca seperti "array TipeDasar". Mungkin perlu juga dijelaskan bahwa jika KelasA adalah kelas turunan dari KelasB maka KelasA[] otomatis menjadi kelas turunan KelasB[].
Tipe dasar suatu array dapat berupa tipe apapun yang ada atau sudah didefinisikan pada Java. Misalnya tipe primitif int akan diturunkan kelas array int[]. Setiap elemen di dalam array int[] adalah variabel yang memiliki tipe int dan bisa diisi dengan nilai dengan tipe int. Dari kelas yang bernama String diturunkan tipe array String[]. Setiap elemen di dalam array String[] adalah variabel dengan tipe String, yang bisa diisi dengan nilai bertipe String. Nilai ini bisa null atau referensi ke objek yang bertipe String (dan juga kelas turunan dari String)
Mari kita lihat contoh lebih konkrotnya menggunakan array bilangan bulat sebagai contoh pertama kita. Karena int[] adalah sebuah kelas, maka kita bisa menggunakannya untuk mendeklarasikan variabel. Misalnya,
int[] daftar;
yang membuat variabel bernama daftar dengan tipe int[]. Variabel ini bisa menunjuk pada array int, akan tetapi nilai awalnya adalah null (jika merupakan variabel anggota suatu kelas) atau tak tentu (jika merupakan variabel lokal di dalam suatu metode). Operator new digunakan untuk membuat objek array baru, yang kemudian bisa diberikan kepada daftar. Sintaksnya sama seperti sintaks sebelumnya, yaitu :
daftar = new int[5];
membuat array 5 buah integer. Lebih umum lagi, konstruktor "new TipeDasar[N]" digunakan untuk membuat array bertipe TipeDasar[]. Nilai N di dalam kurung menyatakan panjang array, atau jumlah elemen yang bisa ditampung. Panjang array adalah variabel instansi di dalam objek array, sehingga array tahu berapa panjangnya. Kita bisa mendapatkan panjang suatu array, misalnya daftar menggunakan daftar.length (akan tetapi kita tidak bisa mengubahnya)
Hasil dari pernyataan "daftar = new int[5];" dapat diilustrasikan sebagai berikut
Perlu dicatat bahwa array integer secara otomatis diisi dengan nol. Dalam Java, array yang baru dibuat akan selalu diisi dengan nilai tertentu: nol untuk angka, false untuk boolean, karakter dengan nilai Unicode 0 untuk char dan null untuk objek.
Elemen di dalam array daftar dapat dirujuk dengan daftar[0], daftar[1], daftar[2], daftar[3], dan daftar[4] (ingat juga bahwa nilai indeks terbesar adalah panjangnya array dikurang satu). Akan tetapi, referensi array sebetulnya lebih umum lagi. Tanda kurung di dalam referensi array bisa berisi ekspresi apapun yang nilainya suatu integer. Misalnya jika idks adalah variabel bertipe int, maka daftar[idks] dan daftar[2*idks+3] secara sintaks benar.
Contoh berikut akan mencetak semua isi integer di dalam array daftar ke layar :
for (int i = 0; i < daftar.length; i++) {
    System.out.println( daftar[i] );
}
Perulangan pertama adalah ketika i = 0, dan daftar[i] merujuk pada daftar[0]. Jadi nilai yang disimpan pada variabel daftar[0] akan dicetak ke layar. Perulangan kedua adalah i = 1, sehingga nilai daftar[i] dicetak. Perulangan berhenti setelah mencetak daftar[4] dan i menjadi sama dengan 5, sehingga kondisi lanjutan "i < daftar.length" tidak lagi benar. Ini adalah contoh umum dari menggunakan perulangan untuk mengolah suatu array.
Penggunaan suatu variabel dalam suatu program menyatakan lokasi di memori. Pikirkan sesaat tentang apa yang akan komputer lakukan ketika ia menemukan referensi ke elemen suatu array daftar[k] ketika program berjalan. Komputer harus menentukan lokasi memori di mana ia dijadikan referensi. Untuk komputer, daftar[k] berarti : "Ambil pointer yang disimpan di dalam variabel daftar. Ikuti pointer ini untuk mencari objek array. Ambil nilai k. Pergi ke posisi ke-k dari array tersebut, dan di sanalah alamat memori yang Anda ingin."
Ada dua hal yang bisa salah di sini. Misalnya nilai daftar adalah null. Dalam kasus ini, maka daftar tidak memiliki referensi sama sekali. Percobaan merujuk suatu elemen pada suatu array kosong adalah suatu kesalahan. Kasus ini akan menampilkan pesan kesalahan "pointer kosong". Kemungkinan kesalahan kedua adalah jika daftar merujuk pada suatu array, akan tetapi k berada di luar rentang indeks yang legal. Ini akan terjadi jika k < 0 atau jika k >= daftar.length. Kasus ini disebut kesalahan "indeks array keluar batas". Ketika kita menggunakan array dalam program, kita harus selalu ingat bahwa kedua kesalahan tersebut mungkin terjadi. Dari kedua kasus di atas, kesalahan indeks array keluar batas adalah kesalahan yang lebih sering terjadi.


Untuk suatu variabel array, seperti variabel lainnya, kita bisa mendeklarasikan dan mengisinya dengan satu langkah sekaligus, misalnya :
int[] daftar = new int[5];
Jika daftar merupakan variabel lokal dalam subrutin, maka perintah di atas akan persis sama dengan dua perintah :
int[] daftar;
daftar = new int[5];
(Jika daftar adalah variabel instansi, tentukan kita tidak bisa mengganti "int[] daftar = new int[5];" dengan "int[] daftar; daftar = new int[5];" karena ini hanya bisa dilakukan di dalam subrutin)
Array yang baru dibuat akan diisi dengan nilai awal yang tergantung dari tipe dasar array tersebut seperti dijelaskan sebelumnya. Akan tetapi Java juga menyediakan cara untuk memberi isi array baru dengan daftar isinya. Dalam pernyataan yang untuk membuat array, ini bisa dilakukan dengan menggunakan penginisialiasi array (array initializer), misalny :
int[] daftar = { 1, 4, 9, 16, 25, 36, 49 };
akan membuat array baru yang berisi 7 nilai, yaitu 1, 4, 9, 16, 25, 36, dan 49, dan mengisi daftar dengan referensi ke array baru tersebut. Nilai daftar[0] berisi 1, nilai daftar[1] berisi 4, dan seterusnya. Panjang daftar adalah 7, karena kita memberikan 7 nilai awal kepada array ini.
Suatu penginisialisasi array memiliki bentuk daftar angka yang dipisahkan dengan koma dan diapit dengan tanda kurung kurawal {}. Panjang array tersebut tidak perlu diberikan, karena secara implisit sudah bisa ditentukan dari jumlah daftar angkanya. Elemen di dalam penginisialisasi array tidak harus selalu berbentuk konstanta. Juga bisa merupakan variabel atau ekspresi apa saja, asalkan nilainya bertipe sama dengan tipe dasar array tersebut. Misalnya, deklarasi berikut membuat array dari delapan jenis Color beberapa warna telah dibentuk dengan ekspresi "new Color(r,g,b);"
Color[] palette =
{
    Color.black,
    Color.red,
    Color.pink,
    new Color(0,180,0),  // hijau gelap
    Color.green,
    Color.blue,
    new Color(180,180,255),  // biru muda
    Color.white
};
Inisialisasi array bentuk seperti ini hanya bisa digunakan dalam deklarasi suatu variabel baru, akan tetapi tidak bisa digunakan seperti operator pemberi nilai (=) di tengah-tengah suatu program. Akan tetapi ada cara lain yang bisa digunakan sebagai pernyataan pemberian nilai atau diberikan ke dalam subrutin. Yaitu menggunakan jenis lain dari operator new untuk membuat atau menginisialisasi objek array baru. (Cara ini agak kaku dengan sintaks aneh, seperti halnya sintaks kelas anonim yang telah didiskusikan sebelumnya). Misalnya untuk memberi nilai kepada suatu variabel daftar, kita bisa menggunakan :
daftar = new int[] { 1, 8, 27, 64, 125, 216, 343 };
Sintaks umum dari bentuk operator new seperti ini adalah,
new TipeDasar [ ] { daftar_nilai_nilai }
Ini adalah suatu ekspresi yang isinya merupakan objek, dan bisa digunakan untuk banyak situasi di mana suatu objek dengan tipe TipeDasar dipentingkan. Misalnya buatTombol merupakan metode yang mengambil array String sebagai parameter, maka kita bisa menuliskan
buatTombol( new String[] { "Stop", "Jalan", "Berikut", "Sebelum" } );
Catatan terakhir : untuk alasan sejarah, maka deklarasi,
int[] daftar;
akan bernilai sama dengan
int daftar[];
di mana sintaks tersebut digunakan dalam bahasa C dan C++. Akan tetapi sintaks alternatif ini tidak begitu masuk akan dalam Java, atau mungkin lebih baik dihindari. Lagian, maksudnya adalah mendeklarasikan variabel dengan tipe tertentu dan namanya adalah int[]. Akan lebih masuk akan untuk mengikuti siintaks "nama_tipe nama_variabel" seperti pada bentuk pertama.

Interface, Class Bertingkat, dan Detail Lain

Interface (Antar Muka)
Beberapa bahasa pemrograman berorientasi objek, misalnya C++, membolehkan suatu kelas memiliki dua atau lebih kelas super. Hal ini disebut pewarisan ganda (multiple inheritance). Pada ilustrasi berikut, kelas E memiliki kelas super A dan B, sedangkan kelas F memiliki 3 kelas super.

Pewarisan ganda seperti ini tidak diperbolehkan pada Java. Desainer Java ingin menjaga agar bahasa Java tetap sederhana, dan mereka merasa pewarisan ganda ini sangat kompleks dengan keuntungan yang tidak begitu besar. Akan tetapi, Java memiliki fitur lain yang bisa digunakan seperti halnya pewarisan berganda, yaitu antar muka (interface).
Kita telah mengenal istilah "antar muka" sebelumnya, yaitu dalam konteks umum tentang kotak hitam dan subrutin. Antar muka suatu subrutin terdiri dari nama, jenis keluarannya, jumlah dan tipe parameternya. Informasi ini dibutuhkan jika kita ingin memanggi subrutin tersebut. Suatu subrutin juga memiliki implementasi : yaitu blok yang berisi perintah yang akan dijalankan ketika subrutin ini dipanggil.
Dalam Java, kata interface adalah kata kunci yang memiliki arti tambahan. Suatu interface dalam hal ini adalah antar muka yang terdiri dari subrutin tanpa implementasi apa-apa. Suatu kelas dapat mengimplementasi suatu interface dengan memberikan kode detail pada setiap subrutin yang ditulis pada interface tersebut. Berikut adalah contoh interface Java sederhana :
public interface Gambar {
    public void gambar(Graphics g);
}
Deklarasi di atas mirip dengan definisi suatu kelas, akan tetapi isi metode gambar() dikosongkan. Suatu kelas yang mengimplementasi interface ini, yaitu interfaceGambar, harus mengisi implementasi metode gambar() ini. Tentunya kelas tersebut juga bisa memiliki variabel dan metode lain. Misalnya,
class Garis implements Gambar {
    public void gambar(Graphics g) {
        . . . // perintah untuk menggambar garis
    }
    . . . // variabel dan metode lain
}
Kelas apapun yang mengimplementasi antar muka Gambar[code] harus memberikan detail apa yang akan dilakukan oleh metode [code]gambar(). Objek yang diciptakan dari kelas tersebut akan memiliki metode gambar(). Perlu diingat bahwa hanya menambah metode gambar() saja tidak cukup. Definisi kelas yang ingin mengimplementasikan suatu interface harus menulis "implements Gambar" dalam definisi kelasnya.
Suatu kelas bisa menurunkan hanya satu kelas lain, akan tetapi suatu kelas bisa mengimplementasikan lebih dari suatu antar muka. Sebenarnya, suatu kelas bisa menurunkan kelas lain dan mengimplementasikan satu atau lebih antar muka sekaligus. Misalnya
class LingkaranBerwarna extends Lingkaran
    implements Gambar, BerisiWarna {
        . . .
    }
Intinya adalah meskipun interface bukan kelas, akan tetapi interface mirip dengan kelas. suatu interface mirip seperti kelas abstrak, yaitu kelas yang hanya digunakan untuk membuat kelas lain, bukan untuk membuat objek. Subrutin pada suatu interface merupakan metode abstrak yang harus diimplementasikan pada kelas kongkrit yang mengimplementasikan interface tersebut.
Seperti kelas abstrak, meskipun kita tidak bisa membuat objek dari interface, akan tetapi suatu variabel dapat bertipe suatu interface. Misalnya, jika Gambar adalah suatu interface, dan jika Garis dan LingkaranBerwarna adalah kelas yang mengimplementasikan Gambar, maka kita bisa menulis kode seperti,
Gambar gambarku; // Deklarasi variabel dengan tipe Gambar.
// Variabel ini bisa diisi objek yang
// mengimplementasi interface Gambar

gambarku = new Garis(); // gambarku berisi objek dengan kelas Garis
gambarku.gambar(g); // memanggil metode gambar() dari kelas Garis

gambarku = new LingkaranBerwarna(); // Sekarang gambarku berisi objek dengan
// kelas LingkaranBerwarna
gambarku.gambar(g); // memanggil metode gambar() dari kelas LingkaranBerwarna
Variabel dengan tipe Gambar boleh merujuk pada kelas apapun yang mengimplementasikan antar muka Gambar. Pernyataan di atas seperti "gambarku.gambar(g)" boleh ditulis karena gambarku adalah variabel dengan tipe Gambar, dan setiap objek bertipe Gambar pasti memiliki metode gambar().
Catatan bahwa tipe data merupakan sesuatu yang biasa digunakan untuk mendeklarasikan variabel. Tipe data juga digunakan untuk memberikan tipe suatu parameter pada subrutin, atau sebagai tipe keluaran suatu fungsi. Pada Java, tipe data bisa berupa kelas, interface, atau salah satu dari 8 tipe data primitif. Dari semuanya, hanya kelas yang bisa digunakan untuk membuat objek baru.
Kita biasanya tidak perlu menulis interface kita sendiri hingga program kita menjadi sangat kompleks. Akan tetapi ada beberapa interface yang sudah disediakan oleh Java yang mungkin bisa digunakan atau diimplementasi dalam program kita.

Class Bertingkat
Suatu kelas merupakan blok bangunan suatu program, yang melambangkan suatu ide beserta data dan perilaku yang dimilikinya. Kadang-kadang kita mungkin berasa sedikit aneh untuk membuat kelas kecil hanya untuk menggabungkan beberapa data. Akan tetapi kadang-kadang kelas-kelas kecil ini sering bermanfaat dan penting. Untungnya Java membolehkan kita untuk membuat kelas di dalam kelas lain, sehingga kelas-kelas kecil ini tidak perlu berdiri sendiri. Kelas kecil ini menjadi bagian dari suatu kelas besar yang bisa melakukan hal-hal kompleks lainnya. Kelas kecil ini misalnya berguna untuk mendukung operasi yang akan dikerjakan oleh kelas besarnya.
Dalam Java, kelas bertingkat atau kelas bagian dalam adalah kelas yang ditulis di dalam definisi kelas lain. Kelas bagian dalam ini bisa memiliki nama atau anonim (tanpa nama). Kelas bagian dalam yang memiliki nama tampak seperti kelas biasa, tetapi ia ditulis di dalam kelas lain. (Kelas bagian dalam ini juga bisa memiliki kelas bagian dalam yang lain, akan tetapi ingat akan konsekuensi kerumitannya apabila kita membuat terlalu banyak tingkatan).
Seperti komponen lain dalam suatu kelas, kelas bagian dalam yang memiliki nama bisa berupa kelas statik atau kelas non-statik. Kelas bertingkat statik merupakan bagian dari struktur statik dari kelas yang menaunginya. Kelas tersebut bisa digunakan di dalam kelas induknya untuk membuat objek seperti biasa. Jika tidak dideklarasikan sebagai private, makan kelas tersebut juga bisa digunakan dari luar kelas induknya. Jika digunakan dari luar kelas induknya, namanya harus jelas mencantumkan nama kelas induknya. Mirip seperti komponen statik dari suatu kelas : kelas bertingkat statik adalah bagian kelas di mana kelas tersebut mirip dengan variabel anggota statik lainnya di dalam kelas tersebut.
Misalnya, suatu kelas bernama ModelRangkaKawat melambangkan kumpulan garis dalam ruang 3 dimensi. Misalnya kelas ModelRangkaKawat memiliki kelas bertingkat statik yang bernama Garis yaitu sebuah garis. Maka dari luar kelas ModelRangkaKawat, kelas Garis akan dipanggil sebagai ModelRangkaKawat.Garis.
Kelas ModelRangkaKawat dan kelas bagian dalamnya dapat dituliskan seperti berikut :
public class ModelRangkaKawat {
 
    . . . // anggota lain kelas ModelRangkaKawat
 
    static public class Garis {
        // Melambangkan garis dari titik (x1,y1,z1)
        // ke titik (x2,y2,z2) dalam ruang 3-dimensi
        double x1, y1, z1;
        double x2, y2, z2;
    } // akhir kelas Garis
 
    . . . // anggota lain kelas ModelRangkaKawat
 
} // akhir kelas ModelRangkaKawat
Di dalam kelas ModelRangkaKawat, objek Garis bisa dibuat dengan konstruktor "new Garis()". Di luar kelas, perintah "new ModelRangkaKawat.Garis()" harus digunakan.
Kelas bertingkat statik memiliki akses penuh kepada anggota dari kelas induknya, termasuk ke anggota private. Mungkin ini juga motivasi sebagian orang untuk membuat kelas bertingkat, karena kelas bagian dalamnya bisa mengakses anggota private kelas lain tanpa harus membuat variabel atau metode anggotanya menjadi public.
Ketika kita mengkompilasi definisi kelas di atas, dua file kelas akan dibuat. Meskipun definisi kelas Garis berada di dalam ModelRangkaKawat, akan tetapi kelas Garis akan disimpan dalam file terpisah. Nama file kelas Garis akan menjadi ModelRangkaKawat$Garis.class


Kelas bertingkat yang tidak statik, pada prakteknya, tidak jauh berbeda dengan kelas bertingkat statik, akan tetapi kelas bertingkat non-statik berkaitan dengan suatu objek, bukan kelas induknya.
Anggota non-statik dari suatu kelas sebenarnya bukan merupakan bagian dari kelas itu. Hal ini juga berlaku untuk kelas bertingkat non-statik seperti juga bagian kelas non-statik lainnya. Anggota non-statik suatu kelas menjelaskan apa yang akan disimpan dalam objek yang diciptakan dari kelas tersebut. Hal ini juga berlaku (secara logis) dari kelas bertingkat non-statik.
Dengan kata lain, setiap objek yang diciptakan dari kelas induknya memiliki kopi kelas bertingkat masing-masing. Kopi ini memiliki akses ke semua variabel dan metode instansi objek tersebut. Dua objek kelas bagian dalam pada dua objek induk merupakan objek berbeda karena metode dan variabel instansi yang bisa diakses berasal dari objek yang berbeda.
Pada dasarnya, aturan untuk menentukan kapan suatu kelas bisa dimasukkan ke dalam kelas lain sebagai kelas statik atau non-statik adalah : Jika kelas tersebut perlu menggunakan variabel atau metode instansi suatu objek (bukan variabel atau metode statik kelas), maka kelas tersebut harus dibuat non-statik, jika tidak maka harus dibuat statik.
Dari luar kelas induknya, kelas bertingkat non-statik harus dipanggil dalam bentuk namaVariabel.NamaKelasBertingkat, misalnya namaVariabel adalah variabel yang merujuk pada objek yang memiliki kelas bertingkat tersebut. Sebetulnya cara ini agak langka. Kelas bertingkat non-statik biasanya digunakan hanya di dalam kelas induknya, sehingga bisa diakses dengan nama yang sederhana.
UNtuk membuat objek yang merupakan kelas bertingkat non-statik, kita harus membuat objek yang merupakan kelas induknya. (Ketika bekerja di dalam kelas, objek "this" akan secara otomatis digunakan). Objek dari kelas bertingkat tersebut dihubungkan secara permanen dengan objek dari kelas induknya, dan memiliki akses penuh atas anggota kelas induknya.
Mari lihat contoh berikut, dan mungkin bisa memberi pemahaman lebih baik bagaimana kelas bertingkat non-statik sebetulnya merupakan hal yang sangat alami. Misalnya suatu kelas yang melambangkan permainan kartu. Kelas ini memiliki kelas beringkat yang melambangkan para pemainnya. Struktur MainKartu bisa berbentuk seperti :

class MainKartu {  // Melambangkan permainan kartu
    class Pemain {  // Melambangkan salah satu pemain game ini
        .
        .
        .
    } // akhir kelas Pemain
    private Tumpukan tumpukan;      // Tumpukan kartu
 
    .
    .
    .
 
} // akhir kelas MainKartu
Jika game adalah variabel dengan tipe MainKartu, maka game memiliki kelas Pemain[code] sendiri. Dalam metode instansi objek [code]MainKartu, objek Pemain bisa dibuat dengan perintah "new Pemain()", seperti halnya kelas biasa. (Objek Pemain bisa dibuat di luar kelas MainKartu dengan perintah seperti "new game.Pemain()", tapi ini jarang dilakukan). Objek Pemain memiliki akses ke variabel instansi tumpukan dalam objek MainKartu.
Masing-masing objek MainKartu memiliki tumpukan dan Pemain sendiri-sendiri. Pemain kartu pada game tersebut akan menggunakan tumpukan kartunya sendiri sedangkan pemain kartu pada game yang lain akan menggunakan tumpukan kartu lain lagi.
Jika Pemain merupakan kelas bertingkat statik, maka pemain tersebut akan bermain di semua permainan kartu, yang tentu saja tidak mungkin terjadi.

Dalam beberapa kasus, mungkin kita harus menulis kelas bertingkat dan kemudian menggunakan kelas tersebut hanya 1 kali dalam program kita. Apakah berguna membuat kelas bertingkat jika begini kondisinya? Mungkin ya mungkin tidak. Dalam kasus seperti ini kita juga bisa membuat kelas bertingkat anonim. Kelas anonim dapat dibuat dengan menggunakan variasi dari operator new dengan bentuk
new  kelassuper_atau_interface () {
    metode_dan_variabel
}
Konstruktor ini membuat suatu kelas baru tanpa memberi nama, dan pada saat yang sama membuat objek dari kelas tersebut. Bentuk operator [code] seperti ini bisa digunakan dalam pernyataan apapun di mana pernyataan new biasa digunakan. Maksud dari pernyataan di atas adalah untuk membuat : "objek baru di dalam suatu kelas yang namanya sama dengan kelassuper_atau_interface dengan ditambah dengan metode_dan_varaibel baru."
Artinya pernyataan di atas sama dengan membuat objek baru dengan konfigurasi yang baru pula. Kita juga bisa membuat kelas anonim yang diturunkan dari interface. Dalam hal ini, kelas anonim tersebut harus mengimplementasikan semua metode yang dideklarasikan oleh interface tersebut.
Kelas anonim sering digunakan untuk menangani event pada GUI (graphical user interfaces). Misalnya interface Gambar seperti didefinisikan di awal bagian ini. Misalnya kita ingin membuat objek berupa gambar bujur sangkar berisi warna merah dengan ukuran 100 x 100 piksel. Daripada membuat kelas baru kemudian menggunakan kelas tersebut untuk membuat objek, kita bisa menggunakan kelas anonim untuk membuat objek sekaligus dalam satu pernyataan :
Gambar kotakMerah = new Gambar() {
        void gambar(Graphics g) {
            g.setColor(Color.red);
            g.fillRect(10,10,100,100);
        }
};
Tanda titik koma (;) di akhir pernyataan ini bukan bagian dari definisi suatu kelas, tapi merupakan bagian dari pernyataan secara keseluruhan.
Ketika kelas Java dikompilasi, setiap kelas bertingkat anonim akan dibuat dalam file kelas terpisah. Jika nama kelas utama adalah KelasUtama, misalnya, maka nama file kelas untuk setiap kelas bertingkat anonimnya menjadi KelasUtama$1.class, KelasUtama$2.class, KelasUtama$3.class dan seterusnya.

Sifat Akses dalam Class
Suatu kelas dapat dideklarasikan sebagai public, yang bisa diakses dari manapun. Beberapa kelas harus dideklarasikan sebagai publik, misalnya sebagai aplikasi desktop biasa, sehingga sistem operasi bisa menjalankan prosedur main() nya. Kelas pada applet misalnya harus juga dideklarasikan sebagai public supaya bisa diakses oleh web browser.
Jika suatu kelas tidak dideklarasikan sebagai public maka ia hanya akan bisa diakses dari paket yang sama. Bagian ini membahas tentang paket. Kelas yang tidak ditulis dalam suatu paket tertentu akan dimasukkan dalam paket default.
Suatu paket seharusnya terdiri dari beberapa kelas yang saling berhubungan. Beberapa dari kelas ini memang sengaja dibuat public agar bisa diakses dari desktop atau program lain misalnya. Bagian lain, yang merupakan bagian internal dari bagaimana paket tersebut bekerja dan tidak boleh disentuh dari luar, tidak boleh dibuat menjadi public. Paket adalah salah satu jenis dari kotak hitam, dan kelas public dalam paket tersebut adalah antar muka dengan dunia luarnya.
Variabel atau metode anggota suatu kelas juga bisa dideklarasikan sebagai public yang juga berarti bisa diakses dari manapun. Variabel atau metode anggota ini juga bisa dideklarasikan sebagai private yang artinya hanya bisa diakses dari dalam kelas di mana dia dideklarasikan. Membuat variabel menjadi private memastikan bahwa tidak ada bagian lain yang akan bisa mengubah variabel ini kecuali dari dalam kelas atau objek itu sendiri.
Jika kita tidak memberikan sifat akses pada metode atau variabel anggota tertentu, maka ia akan otomatis bisa diakses oleh semua kelas dalam paket yang sama.
Ada satu jenis sifat akses lain yang bisa digunakan pada variabel atau metode anggota kelas, yaitu protected. Sifat protected digunakan apabila kita ingin variabel atau metode anggota tersebut bisa diakses oleh turunan kelas tersebut. Artinya lebih leluasa dari private tapi lebih ketat daripada public. Kelas yang didesain untuk diturunkan, biasanya memiliki anggota protected. Anggota protected digunakan untuk menambah fondasi bagi kelas turunannya, akan tetapi tetap tak terlihat dari dunia luar.

Menggabungkan Statik dan Non-Statik
Seperti disebutkan sebelumnya, kelas dapat memiliki dua kegunaan yang sangat berbeda. Kelas bisa digunakan untuk menggabungkan variabel dan subrutin statik. Atau juga bisa digunakan sebagai produsen pembuat objek. Variabel dan subrutin non-statik dalam suatu kelas akan menentukan metode dan variabel instansi pada objek yang diciptakan dari kelas tersebut. Dalam banyak kasus, suatu kelas dapat melakukan salah satu atau kedua fungsi tersebut secara bersamaan.
Dalam hal anggota statik dan non-statik digabung dalam satu kelas, kelas tersebut mengharapkan adanya interaksi antara bagian statik dan bagian non-statik dari suatu kelas. Misalnya, metode instansinya menggunakan variabel statik atau memanggil subrutin statik. Metode instansi dimiliki oleh suatu objek, bukan oleh kelas tersebut. Karena kita bisa membuat banyak objek dari suatu kelas, di mana setiap objek yang diciptakan memiliki metode instansi masing-masing. Akan tetapi akan hanya ada satu variabel statik yaitu yang dimiliki oleh suatu kelas. Dengan demikian, kita memiliki banyak objek yang bisa mengakses variabel statik tersebut bersama-sama.
Misalnya anggap kita akan menulis kelas PasanganDadu yang menggunakan kelas Random seperti pada bagian sebelumnya untuk mengocok dadu. Objek PasanganDadu perlu mengakses objek Random. Akan tetapi membuat objek Random untuk setiap objek PasanganDadu adalah terlalu berlebihan, karena fungsinya hanya digunakan untuk menghasilkan nilai acak saja. Solusi yang bagus adalah dengan menggunakan variabel static yang digunakan oleh semua objek yang dibuat dari kelas PasanganDadu. Misalnya pada kode berikut ini :
class PasanganDadu {
    private static Random randGen = new Random();
    // (Catatan:  java.util.Random telah diimpor sebelum kelas ini dibuat)
 
    public int dadu1;   // Angka pada dadu pertama
    public int dadu2;   // Angka pada dadu kedua
 
    public PasanganDadu() {
        // Konstruktor. Membuat pasangan dadu dengan angka
        // awal berupa bilangan acak
        kocok();
    }
 
    public void kocok() {
        // Kocok dadu dengan membuat masing-masing dadu
        // bernilai bilangan acak 1 hingga 6
        dadu1= randGen.nextInt(6) + 1;
        dadu2= randGen.nextInt(6) + 1;
    }
 
} // akhir kelas PasanganDadu
Contoh lain adalah kelas Murid yang digunakan pada bagian sebelumnya. Kita tambahkan variabel instansi nomorMurid yaitu nomor unik yang berbeda untuk setiap murid. Untuk itu kita perlu melacak nomor baru yang belum dipakai dengan variabel nomorBerikutnya yang berbentuk variabel statik sehingga semua objek akan mengacu pada variabel yang sama. Ketika objek baru dibuat, objek baru akan mengambil nilai nomorBerikutnya untuk dijadikan nomorMurid yang baru.
public class Murid {
 
    private String nama;  // Nama murid
    private int nomorMurid;  // nomor murid unik
    public double ujian1, ujian2, ujian3;   // Nilai ujian
 
    private static int nomorBerikutnya = 0;
    // simpan nomor murid berikutnya
 
    Murid(String namaBaru) {
        // Konstruktor objek Murid:
        // memberi nama, dan memberi nomor murid baru
        nama = namaBaru;
        nomorBerikutnya++;
        nomorMurid = nomorBerikutnya;
    }
 
    public String getNama() {
        // Fungsi untuk mengambil isi variabel instansi private: nama
        return nama;
    }
 
    public int getNomorMurid() {
        // Fungsi untuk membaca isi nomorMurid
        return nomorMurid;
    }
 
    public double hitungRataRata() {
        // Hitung rata-rata nilai ujian
        return (ujian1 + ujian2 + ujian3) / 3;
    }
 
}  // akhir kelas Murid
Inisialisasi "nomorBerikutnya = 0" hanya dilakukan satu kali, yaitu ketika kelas ini pertama kali dipanggil (pada saat program dijalankan). Ketika objek baru bertipe Murid dibuat, dan di dalam konstruktor perintah "nomorBerikutnya++;", maka nomor berikutnya akan disimpan untuk digunakan pada objek baru lainnya.
Ketika objek pertama dibuat, nilai nomorBerikutnya akan bernilai 1. Ketika objek kedua dibuat, nilai nomorBerikutnya bernilai 2, dan seterusnya. Konstruktor akan menyimpan nilai baru nomorBerikutnya pada variabel instansinya sendiri yang tidak di-share dengan objek-objek lain yaitu nomorMurid. Dengan cara ini setiap murid baru akan selalu memiliki nomorMurid baru yang berbeda satu dengan yang lain.