Bagaimana cara kerja kata kunci "final" di Java? (Saya masih bisa memodifikasi objek.)

480

Di Jawa kami menggunakan finalkata kunci dengan variabel untuk menentukan nilainya tidak boleh diubah. Tetapi saya melihat bahwa Anda dapat mengubah nilai dalam konstruktor / metode kelas. Sekali lagi, jika variabelnya staticmaka itu adalah kesalahan kompilasi.

Ini kodenya:

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }
  public static void main(String[] args) 
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

Kode di atas berfungsi dengan baik dan tidak ada kesalahan.

Sekarang ubah variabel sebagai static:

private static final List foo;

Sekarang ini adalah kesalahan kompilasi. Bagaimana cara finalkerjanya?

GS
sumber
karena foo tidak terlihat - bagaimana bisa dikompilasi?
Björn Hallström
5
@therealprashant itu tidak benar. Variabel privat statis adalah valid, mereka dapat diakses dari metode statis di dalam kelas tempat mereka didefinisikan. Variabel statis berarti bahwa variabel tersebut ada satu kali dan tidak terikat dengan instance kelas.
mbdavis
3
@ Mbdavis Oh Ya! Terima kasih. Tapi tetap saja saya tidak akan menghapus komentar untuk membantu orang yang berpikir seperti saya dan kemudian komentar Anda akan membuat mereka berpikir ke arah yang benar.
therealprashant
@therealprashant oke jangan khawatir!
mbdavis

Jawaban:

518

Anda selalu diizinkan untuk menginisialisasi sebuah finalvariabel. Kompiler memastikan bahwa Anda hanya dapat melakukannya sekali.

Perhatikan bahwa metode pemanggilan pada objek yang disimpan dalam finalvariabel tidak ada hubungannya dengan semantik final. Dengan kata lain: finalhanya tentang referensi itu sendiri, dan bukan tentang isi objek yang direferensikan.

Java tidak memiliki konsep kekekalan objek; ini dicapai dengan hati-hati merancang objek, dan merupakan upaya yang jauh dari sepele.

Marko Topolnik
sumber
12
coba lakukan t.foo = new ArrayList (); dalam metode utama dan Anda akan mendapatkan kesalahan kompilasi ... foo referensi diikat hanya pada satu objek final ArrayList ... tidak dapat menunjuk ke ArrayList lainnya
Code2Interface
50
hmmm. Semuanya tentang referensi bukan nilai. Terima kasih!
GS
2
Saya punya pertanyaan. Seseorang yang saya kenal mengklaim "final" juga membuat variabel disimpan di stack. Apakah ini benar? Saya telah mencari di mana-mana dan tidak dapat menemukan referensi yang dapat menyetujui atau menolak klaim ini. Saya telah mencari pada dokumentasi Java dan Android. Juga mencari "model memori Java". Mungkin ini bekerja dengan cara ini pada C / C ++, tapi saya tidak berpikir itu berfungsi seperti ini di Jawa. Apakah saya benar?
pengembang android
4
@androiddeveloper Tidak ada di Jawa yang dapat secara eksplisit mengontrol penempatan tumpukan / tumpukan. Lebih khusus, penempatan tumpukan seperti yang ditentukan oleh kompiler JIT HotSpot tunduk pada analisis melarikan diri , yang jauh lebih terlibat daripada memeriksa apakah suatu variabel final. Objek yang bisa berubah juga dapat dialokasikan secara stack. finalbidang mungkin membantu analisis pelarian, tapi itu rute yang tidak langsung. Juga perhatikan bahwa variabel akhir yang efektif memiliki perlakuan yang sama seperti yang ditandai finaldalam kode sumber.
Marko Topolnik
5
finalhadir dalam file kelas dan memiliki konsekuensi semantik yang signifikan untuk mengoptimalkan runtime. Mungkin juga menimbulkan biaya karena JLS memiliki jaminan kuat tentang konsistensi finalbidang suatu objek. Sebagai contoh, prosesor ARM harus menggunakan instruksi penghalang memori eksplisit pada akhir setiap konstruktor dari kelas yang memiliki finalbidang. Pada prosesor lain, ini tidak diperlukan.
Marko Topolnik
574

Ini pertanyaan wawancara favorit . Dengan pertanyaan ini, pewawancara mencoba untuk mengetahui seberapa baik Anda memahami perilaku objek sehubungan dengan konstruktor, metode, variabel kelas (variabel statis) dan variabel instan.

import java.util.ArrayList;
import java.util.List;

class Test {
    private final List foo;

    public Test() {
        foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

    public void setFoo(List foo) {
       //this.foo = foo; Results in compile time error.
    }
}

Dalam kasus di atas, kami telah mendefinisikan konstruktor untuk 'Tes' dan memberinya metode 'setFoo'.

Tentang konstruktor: Konstruktor dapat dipanggil hanya satu kali per pembuatan objek dengan menggunakan newkata kunci. Anda tidak dapat memanggil konstruktor beberapa kali, karena konstruktor tidak dirancang untuk melakukannya.

Tentang metode: Suatu metode dapat dipanggil sebanyak yang Anda inginkan (Bahkan tidak pernah) dan kompiler mengetahuinya.

skenario 1

private final List foo;  // 1

fooadalah variabel instan . Ketika kita membuat Testobjek kelas maka variabel instan foo, akan disalin di dalam objek Testkelas. Jika kita menetapkan foodi dalam konstruktor, maka kompiler tahu bahwa konstruktor akan dipanggil hanya sekali, jadi tidak ada masalah menugaskannya di dalam konstruktor.

Jika kita menetapkan foodi dalam suatu metode, kompiler tahu bahwa suatu metode dapat dipanggil beberapa kali, yang berarti nilainya harus diubah beberapa kali, yang tidak diperbolehkan untuk suatu finalvariabel. Jadi kompiler memutuskan konstruktor adalah pilihan yang bagus! Anda dapat menetapkan nilai ke variabel akhir hanya satu kali.

Skenario 2

private static final List foo = new ArrayList();

foosekarang menjadi variabel statis . Ketika kita membuat turunan Testkelas, footidak akan disalin ke objek karena foostatis. Sekarang foobukan properti independen dari setiap objek. Ini adalah properti Testkelas. Tetapi foodapat dilihat oleh banyak objek dan jika setiap objek yang dibuat dengan menggunakan newkata kunci yang pada akhirnya akan memanggil Testkonstruktor yang mengubah nilai pada saat beberapa objek dibuat (Ingat static footidak disalin di setiap objek, tetapi dibagi antara beberapa objek .)

Skenario 3

t.foo.add("bar"); // Modification-2

Di atas Modification-2adalah dari pertanyaan Anda. Dalam kasus di atas, Anda tidak mengubah objek referensi pertama, tetapi Anda menambahkan konten di dalamnya fooyang diizinkan. Compiler mengeluh jika Anda mencoba untuk menetapkan new ArrayList()ke foovariabel referensi.
Aturan Jika Anda telah menginisialisasi finalvariabel, maka Anda tidak dapat mengubahnya untuk merujuk ke objek yang berbeda. (Dalam hal ini ArrayList)

kelas akhir tidak dapat disubklasifikasikan metode
akhir tidak dapat diganti. (Metode ini dalam superclass) metode
terakhir dapat menimpa. (Baca ini dengan cara tata bahasa. Metode ini dalam subkelas)

AmitG
sumber
1
Untuk lebih jelasnya. Dalam Skenario 2 apakah Anda mengatakan bahwa fooakan ditetapkan beberapa kali meskipun penunjukan akhir jika foodiatur dalam kelas Tes dan beberapa contoh Uji dibuat?
Rawr
Tidak mengerti baris terakhir untuk skenario 2: Tapi foobisa jadi .. beberapa objek.) Apakah itu berarti, jika saya membuat beberapa objek sekaligus, maka objek mana yang menginisialisasi variabel akhir tergantung pada eksekusi?
Saumya Suhagiya
1
Saya pikir cara yang bermanfaat untuk memikirkan skenario 3 adalah Anda menetapkan finalke alamat memori yang dirujuk oleh fooyang merupakan ArrayList. Anda tidak menetapkan finalalamat memori yang dirujuk oleh elemen pertama foo(atau elemen apa pun dalam hal ini). Karena itu Anda tidak bisa berubah footetapi Anda bisa berubah foo[0].
Pinkerton
@Rawr Seperti berdiri, Skenario 2 akan menyebabkan kesalahan waktu kompilasi karena foo = new ArrayList();- foomerujuk ke variabel statis karena kita berada di dalam kelas yang sama.
flow2k
Saya seorang pengembang C ++ yang mempelajari Java. Apakah aman untuk memikirkan finalvariabel sama seperti constkata kunci dalam C ++?
Doug Barbieri
213

Kata kunci terakhir memiliki banyak cara untuk digunakan:

  • Sebuah akhir kelas tidak dapat subclassed.
  • Metode terakhir tidak bisa ditimpa oleh subclass
  • Variabel akhir hanya dapat diinisialisasi satu kali

Penggunaan lainnya:

  • Ketika kelas dalam anonim didefinisikan dalam tubuh metode, semua variabel yang dinyatakan final dalam lingkup metode tersebut dapat diakses dari dalam kelas batin

Variabel kelas statis akan ada dari awal JVM, dan harus diinisialisasi di kelas. Pesan kesalahan tidak akan muncul jika Anda melakukan ini.

czupe
sumber
24
Sejauh ini, inilah jawaban favorit saya. Sederhana dan mudah, inilah yang saya harapkan untuk dibaca dalam dokumen online tentang java.
RAnders00
Jadi dalam variabel statis kita dapat menginisialisasi sebanyak yang kita inginkan?
jorge saraiva
1
@ jorgesaraiva ya, variabel statis bukan konstanta.
czupe
1
@ jorgesaraiva Anda dapat menetapkan (tidak menginisialisasi ) staticbidang (asalkan tidak final) sebanyak yang Anda inginkan. Lihat wiki ini untuk perbedaan antara penugasan dan inisialisasi .
56

Kata finalkunci dapat diartikan dalam dua cara berbeda tergantung pada apa yang digunakannya:

Jenis nilai: Untuk ints, doubles dll, itu akan memastikan bahwa nilai tidak dapat berubah,

Jenis referensi: Untuk referensi ke objek, finalpastikan bahwa referensi tidak akan pernah berubah, artinya akan selalu merujuk ke objek yang sama. Itu tidak membuat jaminan apa pun tentang nilai-nilai di dalam objek yang dirujuk tetap sama.

Dengan demikian, final List<Whatever> foo;pastikan bahwa fooselalu mengacu pada daftar yang sama , tetapi isi dari daftar tersebut dapat berubah seiring waktu.

Pemburu kecil
sumber
23

Jika Anda membuat foostatis, Anda harus menginisialisasi dalam konstruktor kelas (atau sebaris di mana Anda mendefinisikannya) seperti contoh berikut.

Konstruktor kelas (bukan turunan):

private static final List foo;

static
{
   foo = new ArrayList();
}

Di barisan:

private static final List foo = new ArrayList();

Masalahnya di sini bukanlah bagaimana finalmodifier bekerja, melainkan bagaimana staticmodifier bekerja.

The finalpengubah memberlakukan inisialisasi referensi Anda pada saat panggilan untuk Rampungkan konstruktor Anda (yaitu Anda harus menginisialisasi dalam constructor).

Ketika Anda menginisialisasi atribut in-line, itu akan diinisialisasi sebelum kode yang Anda tetapkan untuk konstruktor dijalankan, sehingga Anda mendapatkan hasil berikut:

  • jika fooini static, foo = new ArrayList()akan dieksekusi sebelum static{}konstruktor yang telah Anda tetapkan untuk kelas Anda dijalankan
  • jika footidak static, foo = new ArrayList()akan dieksekusi sebelum konstruktor Anda dijalankan

Ketika Anda tidak finalmenginisialisasi atribut in-line, pengubah memberlakukan bahwa Anda menginisialisasi dan bahwa Anda harus melakukannya di konstruktor. Jika Anda juga memiliki staticpengubah, konstruktor Anda harus menginisialisasi atribut adalah blok inisialisasi kelas ': static{}.

Kesalahan yang Anda dapatkan dalam kode Anda adalah dari fakta yang static{}dijalankan ketika kelas dimuat, sebelum saat Anda instantiate objek kelas itu. Dengan demikian, Anda belum menginisialisasi fooketika kelas dibuat.

Pikirkan static{}blok sebagai konstruktor untuk objek bertipe Class. Di sinilah Anda harus melakukan inisialisasi static finalatribut kelas Anda (jika tidak dilakukan inline).

Catatan:

The finalmenjamin pengubah const-ness hanya untuk tipe primitif dan referensi.

Saat Anda mendeklarasikan finalobjek, yang Anda dapatkan adalah final referensi ke objek itu, tetapi objek itu sendiri tidak konstan.

Apa yang sebenarnya Anda capai ketika mendeklarasikan finalatribut adalah bahwa, setelah Anda mendeklarasikan objek untuk tujuan spesifik Anda (seperti final Listyang telah Anda nyatakan), itu dan hanya objek itu yang akan digunakan untuk tujuan itu: Anda tidak akan dapat mengubah List fooke lain List, tetapi Anda masih dapat mengubah Anda Listdengan menambahkan / menghapus item (yang ListAnda gunakan akan sama, hanya dengan isinya diubah).

lucian.pantelimon
sumber
8

Ini pertanyaan wawancara yang sangat bagus. Kadang-kadang mereka bahkan mungkin bertanya kepada Anda apa perbedaan antara objek akhir dan objek abadi.

1) Ketika seseorang menyebutkan objek akhir, itu berarti bahwa referensi tidak dapat diubah, tetapi statusnya (variabel instan) dapat diubah.

2) Objek yang tidak berubah adalah objek yang kondisinya tidak dapat diubah, tetapi referensi dapat diubah. Ex:

    String x = new String("abc"); 
    x = "BCG";

variabel ref x dapat diubah untuk menunjukkan string yang berbeda, tetapi nilai "abc" tidak dapat diubah.

3) Variabel instance (bidang non statis) diinisialisasi ketika konstruktor dipanggil. Jadi, Anda dapat menginisialisasi nilai ke variabel di dalam konstruktor.

4) "Tetapi saya melihat bahwa Anda dapat mengubah nilai dalam konstruktor / metode kelas". - Anda tidak dapat mengubahnya di dalam suatu metode.

5) Variabel statis diinisialisasi selama pemuatan kelas. Jadi Anda tidak dapat menginisialisasi di dalam konstruktor, itu harus dilakukan bahkan sebelum itu. Jadi, Anda perlu menetapkan nilai ke variabel statis selama deklarasi itu sendiri.

pengguna892871
sumber
7

Kata finalkunci dalam java digunakan untuk membatasi pengguna. Kata finalkunci java dapat digunakan dalam banyak konteks. Final dapat:

  1. variabel
  2. metode
  3. kelas

Kata finalkunci dapat diterapkan dengan variabel, finalvariabel yang tidak memiliki nilai, disebut finalvariabel kosong atau finalvariabel tidak diinisialisasi . Ini dapat diinisialisasi dalam konstruktor saja. finalVariabel kosong dapat staticjuga yang akan diinisialisasi di staticblok saja.

Variabel akhir Java:

Jika Anda membuat setiap variabel seperti final, Anda tidak dapat mengubah nilai dari finalvariabel (Ini akan konstan).

Contoh finalvariabel

Ada speedlimit variabel akhir, kita akan mengubah nilai variabel ini, tetapi itu tidak dapat diubah karena variabel akhir setelah diberi nilai tidak pernah bisa diubah.

class Bike9{  
    final int speedlimit=90;//final variable  
    void run(){  
        speedlimit=400;  // this will make error
    }  

    public static void main(String args[]){  
    Bike9 obj=new  Bike9();  
    obj.run();  
    }  
}//end of class  

Kelas akhir Jawa:

Jika Anda menjadikan kelas apa pun sebagai final, Anda tidak dapat memperpanjangnya .

Contoh kelas akhir

final class Bike{}  

class Honda1 extends Bike{    //cannot inherit from final Bike,this will make error
  void run(){
      System.out.println("running safely with 100kmph");
   }  

  public static void main(String args[]){  
      Honda1 honda= new Honda();  
      honda.run();  
      }  
  }  

Metode final Java:

Jika Anda membuat metode apa pun sebagai final, Anda tidak dapat menimpanya .

Contoh finalmetode (lari () di Honda tidak bisa menimpa lari () di Sepeda)

class Bike{  
  final void run(){System.out.println("running");}  
}  

class Honda extends Bike{  
   void run(){System.out.println("running safely with 100kmph");}  

   public static void main(String args[]){  
   Honda honda= new Honda();  
   honda.run();  
   }  
}  

dibagikan dari: http://www.javatpoint.com/final-keyword

Ali Ziaee
sumber
7

Layak untuk menyebutkan beberapa definisi langsung:

Kelas / Metode

Anda dapat mendeklarasikan beberapa atau semua metode kelas sebagai final, untuk menunjukkan bahwa metode tidak dapat ditimpa oleh subclass.

Variabel

Setelah finalvariabel diinisialisasi, selalu berisi nilai yang sama.

final pada dasarnya hindari overwrite / superscribe oleh apa pun (subclass, variabel "tetapkan"), tergantung pada kasusnya.

ivanleoncz
sumber
1
Saya pikir definisi akhir tentang variabel agak pendek; "Di Jawa, ketika kata kunci akhir digunakan dengan variabel tipe data primitif (int, float, .. dll), nilai variabel tidak dapat diubah tetapi Ketika final digunakan dengan variabel non-primitif (Perhatikan bahwa variabel non-primitif selalu referensi ke objek di Jawa), anggota objek yang dirujuk dapat diubah. final untuk variabel non - primitif hanya berarti bahwa mereka tidak dapat diubah untuk merujuk ke objek lain ". geeksforgeeks.org/g-fact-48
ceyun
Juga valid, khusus untuk menyebutkan sebagai kasus primitif dan non-primitif. Tks.
ivanleoncz
4

finaladalah kata kunci yang dilindungi undang-undang di Jawa untuk membatasi pengguna dan dapat diterapkan ke variabel anggota, metode, kelas, dan variabel lokal. Variabel akhir sering dideklarasikan dengan statickata kunci di Jawa dan diperlakukan sebagai konstanta. Sebagai contoh:

public static final String hello = "Hello";

Saat kami menggunakan finalkata kunci dengan deklarasi variabel, nilai yang disimpan di dalam variabel itu tidak dapat diubah belakangan.

Sebagai contoh:

public class ClassDemo {
  private final int var1 = 3;
  public ClassDemo() {
    ...
  }
}

Catatan : Kelas yang dinyatakan sebagai final tidak dapat diperpanjang atau diwariskan (yaitu, tidak ada subkelas dari kelas super). Juga baik untuk dicatat bahwa metode yang dinyatakan sebagai final tidak dapat ditimpa oleh subclass.

Manfaat menggunakan kata kunci terakhir dibahas di utas ini .

Desta Haileselassie Hagos
sumber
2
the value stored inside that variable cannot be changed lattersebagian benar. Memang benar hanya untuk tipe data primitif. Dalam hal objek dibuat final, seperti arraylist, nilainya dapat berubah tetapi bukan referensi. Terima kasih!
GS
3

Misalkan Anda memiliki dua kotak uang, merah dan putih. Anda menetapkan kotak uang ini hanya dua anak dan mereka tidak diizinkan menukar kotak mereka. Jadi Anda memiliki kotak uang merah atau putih (final) Anda tidak dapat memodifikasi kotak tetapi Anda dapat menaruh uang di kotak Anda. Tidak ada yang peduli (Modifikasi-2).

huseyin
sumber
2

Baca semua jawabannya.

Ada kasus pengguna lain di mana finalkata kunci dapat digunakan yaitu dalam argumen metode:

public void showCaseFinalArgumentVariable(final int someFinalInt){

   someFinalInt = 9; // won't compile as the argument is final

}

Dapat digunakan untuk variabel yang tidak boleh diubah.

Pritam Banerjee
sumber
1

Ketika Anda membuatnya final statis, itu harus diinisialisasi dalam blok inisialisasi statis

    private static final List foo;

    static {
        foo = new ArrayList();
    }

    public Test()
    {
//      foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }
Evgeniy Dorofeev
sumber
1

Kata finalkunci menunjukkan bahwa suatu variabel hanya dapat diinisialisasi satu kali. Dalam kode Anda, Anda hanya melakukan satu inisialisasi akhir sehingga persyaratan terpenuhi. Pernyataan ini melakukan inisialisasi tunggal foo. Perhatikan bahwa final! = Tidak berubah, itu hanya berarti bahwa referensi tidak dapat berubah.

foo = new ArrayList();

Ketika Anda mendeklarasikan foosebagai static finalvariabel harus diinisialisasi ketika kelas dimuat dan tidak dapat mengandalkan instantiasi (alias panggil konstruktor) untuk menginisialisasi fookarena bidang statis harus tersedia tanpa turunan dari kelas. Tidak ada jaminan bahwa konstruktor akan dipanggil sebelum menggunakan bidang statis.

Ketika Anda menjalankan metode Anda di bawah static finalskenario Testkelas dimuat sebelum instantiating tsaat ini tidak ada instantiasi foomakna yang belum diinisialisasi sehingga foodisetel ke default untuk semua objek yang ada null. Pada titik ini saya menganggap kode Anda melempar NullPointerExceptionketika Anda mencoba untuk menambahkan item ke daftar.

Kevin Bowersox
sumber
1

Pertama-tama, tempat dalam kode Anda di mana Anda menginisialisasi (mis. Menetapkan untuk pertama kalinya) foo ada di sini:

foo = new ArrayList();

foo adalah objek (dengan tipe Daftar) sehingga merupakan tipe referensi , bukan tipe nilai (seperti int). Dengan demikian, ia menyimpan referensi ke lokasi memori (mis. 0xA7D2A834) tempat elemen Daftar Anda disimpan. Garis seperti ini

foo.add("foo"); // Modification-1

jangan ubah nilai foo (yang, sekali lagi, hanya referensi ke lokasi memori). Sebagai gantinya, mereka hanya menambahkan elemen ke lokasi memori yang dirujuk. Untuk melanggar kata kunci terakhir , Anda harus mencoba menetapkan ulang foo sebagai berikut lagi:

foo = new ArrayList();

Itu akan memberi Anda kesalahan kompilasi.


Sekarang, dengan hal itu, pikirkan apa yang terjadi ketika Anda menambahkan kata kunci statis .

Ketika Anda TIDAK memiliki kata kunci statis, setiap objek yang instantiate kelas memiliki salinan foo sendiri. Oleh karena itu, konstruktor memberikan nilai pada salinan kosong dari variabel foo, yang benar-benar baik-baik saja.

Namun, ketika Anda DO memiliki kata kunci statis, hanya ada satu foo di memori yang terkait dengan kelas. Jika Anda membuat dua objek atau lebih, konstruktor akan berusaha untuk menetapkan ulang satu foo setiap kali, melanggar kata kunci terakhir .

Niko Bellic
sumber
1
  1. Karena variabel terakhir adalah non-statis, ia dapat diinisialisasi dalam konstruktor. Tetapi jika Anda membuatnya statis itu tidak dapat diinisialisasi oleh konstruktor (karena konstruktor tidak statis).
  2. Penambahan daftar tidak diharapkan berhenti dengan membuat daftar final. finalhanya mengikat referensi ke objek tertentu. Anda bebas mengubah 'keadaan' objek itu, tetapi bukan objek itu sendiri.
Ankit
sumber
1

Berikut ini adalah konteks yang berbeda di mana final digunakan.

Variabel akhir Variabel akhir hanya dapat ditetapkan satu kali. Jika variabel adalah referensi, ini berarti bahwa variabel tidak dapat terikat kembali untuk referensi objek lain.

class Main {
   public static void main(String args[]){
      final int i = 20;
      i = 30; //Compiler Error:cannot assign a value to final variable i twice
   }
}

variabel akhir dapat diberi nilai nanti (tidak wajib untuk menetapkan nilai saat dideklarasikan), tetapi hanya sekali.

Kelas akhir Kelas akhir tidak dapat diperpanjang (diwariskan)

final class Base { }
class Derived extends Base { } //Compiler Error:cannot inherit from final Base

public class Main {
   public static void main(String args[]) {
   }
}

Metode akhir Metode akhir tidak dapat ditimpa oleh subclass.

//Error in following program as we are trying to override a final method.
class Base {
  public final void show() {
       System.out.println("Base::show() called");
    }
}     
class Derived extends Base {
    public void show() {  //Compiler Error: show() in Derived cannot override
       System.out.println("Derived::show() called");
    }
}     
public class Main {
    public static void main(String[] args) {
        Base b = new Derived();;
        b.show();
    }
}
roottraveller
sumber
1

Saya berpikir untuk menulis jawaban yang diperbarui dan mendalam di sini.

final kata kunci dapat digunakan di beberapa tempat.

  1. kelas

A final classberarti tidak ada kelas lain yang bisa memperpanjang kelas akhir itu. Ketika Java Run Time ( JRE ) tahu referensi objek dalam tipe kelas akhir (katakanlah F), ia tahu bahwa nilai referensi itu hanya bisa dalam tipe F.

Ex:

F myF;
myF = new F();    //ok
myF = someOther;  //someOther cannot be in type of a child class of F.
                  //because F cannot be extended.

Jadi ketika mengeksekusi metode apa pun dari objek itu, metode itu tidak perlu diselesaikan pada saat run time menggunakan tabel virtual . yaitu polimorfisme run-time tidak dapat diterapkan. Jadi jangka waktu tidak peduli tentang itu. Yang berarti menghemat waktu pemrosesan, yang akan meningkatkan kinerja.

  1. metode

A final methoddari sembarang kelas berarti bahwa setiap kelas anak yang memperluas kelas itu tidak dapat menggantikan metode akhir itu. Jadi perilaku run time dalam skenario ini juga sangat sama dengan perilaku sebelumnya yang saya sebutkan untuk kelas.

  1. bidang, variabel lokal, parameter metode

Jika seseorang menentukan jenis apa pun di atas sebagai final, itu berarti bahwa nilainya telah selesai, sehingga nilainya tidak dapat diubah .

Ex:

Untuk bidang, parameter lokal

final FinalClass fc = someFC; //need to assign straight away. otherwise compile error.
final FinalClass fc; //compile error, need assignment (initialization inside a constructor Ok, constructor can be called only once)
final FinalClass fc = new FinalClass(); //ok
fc = someOtherFC; //compile error
fc.someMethod(); //no problem
someOtherFC.someMethod(); //no problem

Untuk parameter metode

void someMethod(final String s){
    s = someOtherString; //compile error
}

Ini berarti bahwa nilai dari nilai finalreferensi tidak dapat diubah. yaitu hanya satu inisialisasi yang diizinkan. Dalam skenario ini, dalam jangka waktu, karena JRE tahu bahwa nilai tidak dapat diubah, ini memuat semua nilai akhir ini (dari referensi akhir) ke dalam cache L1 . Karena tidak perlu untuk memuat kembali lagi dan lagi dari memori utama . Kalau tidak dimuat ke L2 cache dan melakukan waktu ke waktu memuat dari memori utama. Jadi ini juga merupakan peningkatan kinerja.

Jadi dalam semua 3 skenario di atas, ketika kami belum menentukan finalkata kunci di tempat yang bisa kami gunakan, kami tidak perlu khawatir, optimisasi kompiler akan melakukannya untuk kami. Ada juga banyak hal lain yang dilakukan optimasi kompiler untuk kita. :)

Supun Wijerathne
sumber
0

Di atas semuanya benar. Selanjutnya jika Anda tidak ingin orang lain membuat sub kelas dari kelas Anda, maka nyatakan kelas Anda sebagai final. Maka itu menjadi tingkat daun hierarki pohon kelas Anda yang tidak ada yang bisa memperpanjangnya. Ini adalah praktik yang baik untuk menghindari hierarki kelas yang besar.

Shehan Simen
sumber