Konstanta final vs C ++ Java

151

The Java untuk C ++ programmer tutorial mengatakan bahwa (sorot adalah saya sendiri):

Final kata kunci kira - kira setara dengan const di C ++

Apa arti "kasar" dalam konteks ini? Bukankah mereka persis sama?

Apa perbedaannya, jika ada?

Menang
sumber

Jawaban:

195

Dalam C ++ menandai fungsi anggota constberarti dapat dipanggil pada constinstance. Java tidak memiliki yang setara dengan ini. Misalnya:

class Foo {
public:
   void bar();
   void foo() const;
};

void test(const Foo& i) {
   i.foo(); //fine
   i.bar(); //error
}

Nilai dapat ditetapkan, sekali, nanti hanya di Jawa mis.:

public class Foo {
   void bar() {
     final int a;
     a = 10;
   }
}

legal di Jawa, tetapi tidak C ++ sedangkan:

public class Foo {
   void bar() {
     final int a;
     a = 10;
     a = 11; // Not legal, even in Java: a has already been assigned a value.
   }
}

Dalam Java dan C ++ variabel anggota dapat final/ constmasing-masing. Ini perlu diberi nilai pada saat instance kelas selesai dibangun.

Di Jawa mereka harus ditetapkan sebelum konstruktor selesai, ini dapat dicapai dengan salah satu dari dua cara:

public class Foo {
   private final int a;
   private final int b = 11;
   public Foo() {
      a = 10;
   }
}

Di C ++ Anda harus menggunakan daftar inisialisasi untuk memberi constnilai pada anggota:

class Foo {
   const int a;
public:
   Foo() : a(10) {
      // Assignment here with = would not be legal
   }
};

Di Java final dapat digunakan untuk menandai hal-hal yang tidak dapat ditimpa. C ++ (pre-C ++ 11) tidak melakukan ini. Misalnya:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

Namun dalam C ++:

class Bar {
public:
   virtual void foo() const {
   }
};

class Error: public Bar {
public:
   // Fine in C++
   virtual void foo() const {
   }
};

ini baik-baik saja, karena semantik penandaan fungsi anggota constberbeda. (Anda juga dapat membebani dengan hanya memiliki fungsi constsalah satu anggota. (Catat juga bahwa C ++ 11 memungkinkan fungsi anggota ditandai sebagai final, lihat bagian pembaruan C ++ 11)


Pembaruan C ++ 11:

C ++ 11 sebenarnya memungkinkan Anda untuk menandai kedua kelas dan fungsi anggota sebagai final, dengan semantik identik dengan fitur yang sama di Jawa, misalnya di Jawa:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

Sekarang dapat ditulis dengan tepat di C ++ 11 sebagai:

class Bar {
public:
  virtual void foo() final;
};

class Error : public Bar {
public:
  virtual void foo() final;
};

Saya harus mengkompilasi contoh ini dengan pra-rilis G ++ 4.7. Perhatikan bahwa ini tidak menggantikan constdalam kasus ini, tetapi menambahkannya, memberikan perilaku mirip Java yang tidak terlihat dengan kata kunci C ++ setara terdekat. Jadi jika Anda ingin fungsi anggota menjadi keduanya finaldan constAnda akan melakukannya:

class Bar {
public:
  virtual void foo() const final;
};

(Urutan constdan di finalsini diperlukan).

Sebelumnya tidak ada yang setara langsung dengan constfungsi anggota meskipun membuat fungsi tidak virtualakan menjadi opsi yang potensial meskipun tanpa menyebabkan kesalahan pada waktu kompilasi.

Demikian juga dengan Java:

public final class Bar {
}

public class Error extends Bar {
}

menjadi di C ++ 11:

class Bar final {
};

class Error : public Bar {
};

(Sebelumnya privatekonstruktor mungkin yang paling dekat dengan C + +)

Menariknya, untuk menjaga kompatibilitas dengan kode pra-C ++ 11 final bukanlah kata kunci dengan cara biasa. (Ambil contoh C ++ 98 yang sepele dan legal struct final;untuk melihat mengapa menjadikannya kata kunci akan memecahkan kode)

Flexo
sumber
3
Anda harus membuat metode-metode itu virtual; jika tidak, Anda benar-benar tidak melakukan hal yang sama
BlueRaja - Danny Pflughoeft
1
Dalam contoh terakhir Anda, Anda memiliki apa yang legal, tetapi perlu disebutkan bahwa final int a; a = 10; a = 11;itu tidak (yang menjadi tujuan finalsebagai pengubah variabel.) Juga, anggota akhir suatu kelas hanya dapat ditetapkan pada waktu deklarasi, atau sekali dalam konstruktor .
corsiKa
2
Perhatikan bahwa C ++ 0x menambahkan finaldekorator fungsi anggota untuk tujuan yang tepat ini. VC ++ 2005, 2008, dan 2010 sudah menerapkan ini, menggunakan kata kunci kontekstual sealeddaripada final.
ildjarn
@ildjarn -yaitu menarik untuk diketahui dan perubahan C ++ 0x yang relatif kecil yang tidak saya sadari! Saya mungkin akan menambahkan komentar kecil di suatu tempat di teks yang menunjukkan bahwa ini berubah dengan C ++ 0x.
Flexo
1
Tampaknya orang masih melakukan s / const / final / g dalam basis kode dengan finalructor sebagai hasilnya!
Flexo
30

Di Jawa, kata kunci terakhir dapat digunakan untuk empat hal:

  • pada kelas atau metode untuk menutupnya (tidak ada subclass / overriding yang diizinkan)
  • pada variabel anggota untuk menyatakan bahwa itu dapat diatur tepat sekali (saya pikir ini adalah apa yang Anda bicarakan)
  • pada variabel yang dideklarasikan dalam suatu metode, untuk memastikan bahwa itu dapat diatur tepat satu kali
  • pada parameter metode, untuk menyatakan bahwa itu tidak dapat dimodifikasi dalam metode

Satu hal penting adalah: Variabel anggota akhir Java harus diset tepat sekali! Misalnya, dalam konstruktor, deklarasi lapangan, atau intializer. (Tetapi Anda tidak dapat menetapkan variabel anggota akhir dalam suatu metode).

Konsekuensi lain dari pembuatan variabel variabel anggota berkaitan dengan model memori, yang penting jika Anda bekerja di lingkungan berulir.

Muntah
sumber
Apa yang Anda maksud dengan mengatakan 'model memori'? Saya tidak mengerti.
Tony
1
@Tony: Spesifikasi Bahasa Jawa, Bab 17.4. Memory Model - docs.oracle.com/javase/specs/jls/se8/html/index.html - hit pertama googles
Ralph
27

Sebuah constobjek hanya dapat memanggil constmetode, dan umumnya dianggap berubah.

const Person* person = myself;
person = otherPerson; //Valid... unless we declared it const Person* const!
person->setAge(20); //Invalid, assuming setAge isn't a const method (it shouldn't be)

Sebuah finalobjek tidak dapat diatur untuk objek baru, tetapi tidak berubah - tidak ada yang menghentikan seseorang dari menelepon setiap setmetode.

final Person person = myself;
person = otherPerson; //Invalid
person.setAge(20); //Valid!

Java tidak memiliki cara yang melekat untuk mendeklarasikan objek yang tidak dapat diubah; Anda perlu merancang kelas sebagai diri Anda sendiri yang tidak berubah.

Ketika variabel adalah tipe primitif, final/ constbekerja sama.

const int a = 10; //C++
final int a = 10; //Java
a = 11; //Invalid in both languages
BlueRaja - Danny Pflughoeft
sumber
3
Ini adalah jawaban yang bagus juga (seperti banyak orang lain di sini). Sayangnya, saya hanya dapat menerima satu jawaban. :)
WinWin
1
Jawaban sempurna!
ADJ
13

Java final sama dengan C ++ const pada tipe nilai primitif.

Dengan tipe referensi Java, kata kunci terakhir setara dengan pointer const ... yaitu

//java
final int finalInt = 5;
final MyObject finalReference = new MyObject();

//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();
James Schek
sumber
"kata kunci terakhir setara dengan pointer const" kata baik
ADJ
8

Anda sudah memiliki beberapa jawaban hebat di sini, tetapi satu hal yang sepertinya layak ditambahkan: constdalam C ++ biasanya digunakan untuk mencegah bagian lain dari program mengubah keadaan objek. Seperti yang telah ditunjukkan, finaldi java tidak dapat melakukan ini (kecuali untuk primitif) - itu hanya mencegah referensi dari diubah ke objek yang berbeda. Tetapi jika Anda menggunakan Collection, Anda dapat mencegah perubahan pada objek Anda dengan menggunakan metode statis

 Collection.unmodifiableCollection( myCollection ) 

Ini mengembalikan Collectionreferensi yang memberikan akses baca ke elemen, tetapi melemparkan pengecualian jika modifikasi dilakukan, membuatnya sedikit seperti constdi C ++

pocketdora
sumber
8

Java finalhanya bekerja pada tipe dan referensi primitif, tidak pernah pada instance objek itu sendiri di mana kata kunci const bekerja pada apa pun.

Bandingkan const list<int> melist;dengan final List<Integer> melist;yang pertama membuat tidak mungkin untuk mengubah daftar, sementara yang terakhir hanya menghentikan Anda dari menetapkan daftar baru melist.

Josefx
sumber
3

Selain memiliki sifat multi-threading tertentu dan halus , variabel yang dideklarasikan finaltidak perlu diinisialisasi pada deklarasi!

Yaitu ini berlaku di Java:

// declare the variable
final int foo;

{
    // do something...

    // and then initialize the variable
    foo = ...;
}

Ini tidak akan valid jika ditulis dengan C ++ const.

antak
sumber
2

Menurut wikipedia :

  • Dalam C ++, bidang const tidak hanya dilindungi dari penugasan kembali, tetapi ada batasan tambahan bahwa hanya metode const yang bisa dipanggil dan hanya bisa dilewatkan sebagai argumen const dari metode lain.
  • Kelas dalam non-statis dapat dengan bebas mengakses bidang apa pun dari kelas penutup, final atau tidak.
KevenK
sumber
1
Kata 'ditugaskan kembali' tidak muncul dalam versi halaman saat ini, dan tidak ada yang menyerupai poin kedua Anda, yang salah atau tidak relevan, tergantung pada apa yang Anda maksud dengan 'akses'. 'Batin non-statis' adalah pembicaraan ganda. Wikipedia bukan referensi normatif untuk C ++ atau Java.
Marquis of Lorne
2

Saya menduga itu mengatakan "kira-kira" karena makna constdalam C + + menjadi rumit ketika Anda berbicara tentang pointer, yaitu pointer konstan vs pointer ke objek konstan. Karena tidak ada pointer "eksplisit" di Jawa, finaltidak memiliki masalah ini.

Dima
sumber
1

Biarkan saya menjelaskan apa yang saya pahami dengan contoh pernyataan switch / case.

Nilai dalam setiap pernyataan kasus harus berupa nilai konstanta waktu kompilasi dari tipe data yang sama dengan nilai sakelar.

mendeklarasikan sesuatu seperti di bawah ini (baik dalam metode Anda sebagai instance lokal, atau di kelas Anda sebagai variabel statis (tambahkan statik padanya), atau variabel instan.

final String color1 = "Red";

dan

static final String color2 = "Green";

switch (myColor) { // myColor is of data type String
    case color1:
    //do something here with Red
    break;
    case color2:
    //do something with Green
    break;
}

Kode ini tidak akan dikompilasi, jika color1merupakan variabel kelas / instance dan bukan variabel lokal. Ini akan mengkompilasi jikacolor1 didefinisikan sebagai final statis (kemudian menjadi variabel final statis).

Ketika tidak dikompilasi, Anda akan mendapatkan kesalahan berikut

error: constant string expression required
Subbu Mahadevan
sumber
-7

kata kunci "const" berarti bahwa variabel Anda disimpan dalam ROM (dengan Mikroprosesor). di komputer, variabel Anda disimpan di area RAM untuk kode Majelis (RAM hanya baca). itu berarti bahwa variabel Anda tidak ada dalam RAM yang dapat ditulisi termasuk: memori statis, memori tumpukan dan memori tumpukan.

kata kunci "final" berarti bahwa variabel Anda disimpan dalam RAM yang dapat ditulisi, tetapi Anda melihat kepada kompiler bahwa variabel Anda hanya berubah satu kali saja.

//in java language you can use:
static final int i =10;
i =11; //error is showed here by compiler

//the same in C++ the same as follows
int i =10;
const int &iFinal = i;

iFinal = 11; //error is showed here by compiler the same as above

Saya pikir, "const" buruk dalam kinerja, jadi Java tidak menggunakannya.

HungNM2
sumber