Остаточний показник Java проти C ++


151

У підручнику для програмістів Java для C ++ йдеться про те, що (виділити - це моя власна робота):

Кінцеве ключове слово приблизно еквівалентне const у C ++

Що означає "приблизно" в цьому контексті? Хіба вони точно так же?

У чому полягають відмінності, якщо такі є?

Відповіді:


195

У C ++ маркування функції-члена constозначає, що вона може бути викликана в constекземплярах. У Java немає еквіваленту цьому. Наприклад:

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

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

Значення можуть бути призначені один раз, пізніше на Java, наприклад:

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

є законним для Java, але не C ++, тоді як:

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

І в Java, і в C ++ змінними можуть бути final/ constвідповідно. Їм потрібно присвоїти значення до моменту побудови екземпляра класу.

У Java вони повинні бути встановлені до того, як конструктор закінчить, це можна досягти одним із двох способів:

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

У C ++ вам потрібно буде використовувати списки ініціалізації, щоб дати constчленам значення:

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

У Java фінал можна використовувати для позначення речей, які не можна перезаписати. C ++ (pre-C ++ 11) цього не робить. Наприклад:

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

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

Але в C ++:

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

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

це добре, тому що семантика позначення функції члена constє різною. (Ви також можете перевантажуватись , лише увімкнувши constодну з функцій-членів. (Зауважте також, що C ++ 11 дозволяє функції члена відзначати остаточними, див. Розділ оновлення C ++ 11)


Оновлення C ++ 11:

C ++ 11 насправді дозволяє позначати як класи, так і функції членів як final, з однаковою семантикою тієї самої функції на Java, наприклад на Java:

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

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

Тепер на C ++ 11 можна точно записати так:

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

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

Мені довелося скласти цей приклад із попереднім випуском G ++ 4.7. Зауважте, що це не замінює constв цьому випадку, а скоріше збільшує його, забезпечуючи поведінку, схожу на Java, яка не була помічена з найближчим еквівалентним ключовим словом C ++. Тож якби ви хотіли, щоб функція члена була обома, finalі constви зробили б:

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

(Порядок constі finalтут потрібно).

Раніше не було прямого еквівалента constфункцій-членів, хоча перетворення функцій не virtualбуло б потенційним варіантом, хоча і не викликало помилки під час компіляції.

Так само і Java:

public final class Bar {
}

public class Error extends Bar {
}

стає в C ++ 11:

class Bar final {
};

class Error : public Bar {
};

(Раніше privateконструктори були, мабуть, найближчими, до яких ви могли дійти до цього в C ++)

Цікаво, що для підтримки зворотної сумісності з кодом pre-C ++ 11 final це не ключове слово звичайним чином. (Візьміть тривіальний, легальний приклад C ++ 98, struct final;щоб дізнатися, чому створення ключового слова порушить код)


3
Ви повинні зробити ці методи віртуальними; в іншому випадку ви насправді не робите те саме
BlueRaja - Danny Pflughoeft

1
У вашому останньому прикладі ви маєте законний характер, але варто згадати, що final int a; a = 10; a = 11;це не є (це є метою finalмодифікатора змінної.) Також, остаточних членів клас можна встановити лише під час оголошення або один раз у конструкторі .
corsiKa

2
Зауважте, що C ++ 0x додає finalдекоратор функції члена саме для цієї мети. VC ++ 2005, 2008 та 2010 вже реалізували це, sealedскоріше використовуючи контекстне ключове слово final.
ildjarn

@ildjarn -це цікаво знати і ще одна порівняно невелика зміна 0 + 0 разів, про яку я не знав! Я, мабуть, десь до тексту додаю невеликий коментар, який вказує, що це змінюється за допомогою C ++ 0x.
Flexo

1
Мабуть, люди все ще роблять s / const / final / g у кодових базах з finalructor як результат!
Flexo

30

У Java остаточне ключове слово можна використовувати для чотирьох речей:

  • про клас або метод його закріплення (не допускаються підкласи / переопределення)
  • на змінній члена оголосити, що це може бути встановлено рівно один раз (я думаю, це саме те, про що ви говорите)
  • на змінну, оголошену в методі, щоб переконатися, що вона може бути встановлена ​​рівно один раз
  • в параметрі методу, щоб оголосити, що він не може бути змінений в методі

Важливо одне: змінна остаточного члена Java повинна бути встановлена ​​рівно один раз! Наприклад, у конструкторі, декларації на місцях або в програмі intializer. (Але ви не можете встановити змінну остаточного члена в методі).

Інший наслідок отримання остаточної змінної члена стосується моделі пам'яті, що важливо, якщо ви працюєте в потоковому середовищі.


Що ви маєте на увазі під словом "модель пам'яті"? Я не розумію.
Тоні

1
@Tony: Специфікація мови Java, глава 17.4. Модель пам'яті - docs.oracle.com/javase/specs/jls/se8/html/index.html - перший удар googles
Ральф

27

constОб'єкт може викликати тільки constметоди, і як правило , вважається незмінні.

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)

finalОб'єкт не може бути встановлений на новий об'єкт, але це не є незмінним - є ніщо не заважає кому - то з виклику будь-яких setметодів.

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

Java не властивий спосіб оголошення об'єктів непорушними; вам потрібно спроектувати клас як непорушний сам.

Коли змінна є примітивним типом, final/ constпрацюйте так само.

const int a = 10; //C++
final int a = 10; //Java
a = 11; //Invalid in both languages

3
Це теж чудова відповідь (як і багато інших тут). На жаль, я можу прийняти лише одну відповідь. :)
WinWin

1
Ідеальна відповідь!
ADJ

13

Фінал Java еквівалентний Cst + const для примітивних типів значень.

Для типів посилань Java кінцеве ключове слово еквівалентно покажчику const ... тобто

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

//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();

"остаточне ключове слово еквівалентно const pointer" добре сказано
ADJ

8

Ви вже маєте кілька чудових відповідей, але один момент, який, здавалося, варто додати: constу C ++ зазвичай використовується для запобігання, щоб інші частини програми змінювали стан об'єктів. Як уже зазначалося, finalв Java не може це зробити (за винятком примітивів) - це просто запобігає посилання від змін на інший об'єкт. Але якщо ви використовуєте a Collection, ви можете запобігти змінам у ваших об'єктах, використовуючи статичний метод

 Collection.unmodifiableCollection( myCollection ) 

Це повертає Collectionпосилання, яке надає доступ для читання елементів, але видає виняток у разі спроб модифікації, що робить його трохи схожим constна C ++


8

Java finalпрацює лише на примітивних типах і посиланнях, ніколи на самих об'єктних екземплярах, де ключове слово const працює на що-небудь.

Порівняння const list<int> melist;з final List<Integer> melist;першим унеможливлює зміну списку, тоді як останнє лише перешкоджає призначенню нового списку melist.


3

Окрім наявності певних і тонких властивостей багатопотоковоїfinal передачі , декларовані змінні не потрібно ініціалізувати при декларуванні!

тобто Це дійсно на Java:

// declare the variable
final int foo;

{
    // do something...

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

Це не буде дійсним, якщо писати з C ++ const.


2

За вікіпедією :

  • У C ++ поле const не тільки захищене від переназначення, але є додаткове обмеження, що на нього можуть бути викликані лише методи const, і воно може передаватися лише як аргумент const інших методів.
  • Нестатичні внутрішні класи можуть вільно отримувати доступ до будь-якого поля класу, що додається, остаточного чи ні.

1
Слово "переназначений" не відображається в поточній версії цієї сторінки, і ніщо не нагадує вашу другу точку, що є неправильним або неактуальним, залежно від того, що ви розумієте під "доступом". "Нестатичний внутрішній" - це подвійне спілкування. Вікіпедія не є нормативним посиланням ні на C ++, ні на Java.
Маркіз Лорн

2

Я здогадуюсь, що це говорить "приблизно", оскільки значення constв C ++ ускладнюється, коли ви говорите про покажчики, тобто постійні вказівники проти вказівників на постійні об'єкти. Оскільки в Яві немає "явних" покажчиків, finalцих проблем не виникає.


1

Дозвольте пояснити, що я зрозумів на прикладі вимикача / випадку заяви.

Значення у кожному операторі випадку повинні бути постійними значеннями часу компіляції того ж типу даних, що і значення комутатора.

оголосити щось на зразок нижче (або у вашому методі як локальні екземпляри, або у вашому класі як статична змінна (додайте до цього статичну) або змінну екземпляра.

final String color1 = "Red";

і

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;
}

Цей код не буде компілюватися, якщо color1це змінна клас / екземпляр, а не локальна змінна. Це складеться, якщо color1визначено як статична остаточна (тоді вона стає статичною остаточною змінною).

Коли вона не компілюється, ви отримаєте таку помилку

error: constant string expression required

-7

ключове слово "const" означає, що ваша змінна збережена в ПЗУ (за допомогою мікропроцесора). в комп'ютері ваша змінна зберігається в області оперативної пам’яті для асемблерного коду (лише читання ОЗУ). це означає, що ваша змінна не знаходиться в оперативній пам'яті, що записується, включає: статичну пам'ять, стек-пам'ять і купу пам'яті.

ключове слово "остаточний" означає, що ваша змінна збережена в оперативній пам'яті, що записується, але ви помітили компілятору, що ваша змінна змінюється лише один раз.

//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

Я думаю, що "const" поганий у виконанні, тому Java не використовує його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.