Java的最终与C ++的const

Java for C ++程序员教程说(重点是我自己的):

final关键字大致等于C ++中的const

在这方面“粗略”是什么意思? 他们不完全一样吗?

有什么区别?

在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 ++中,成员variables可能分别是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允许成员函数被标记为final,参见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 ,而是增加const ,从而提供类似于Java的行为,而这种行为在最接近的等效C ++关键字中是看不到的。 所以,如果你想要一个成员函数是finalconst你会做:

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

(这里需要constfinal的顺序)。

以前没有一个const成员函数的直接等价物,虽然使函数非virtual将是一个潜在的选项,尽pipe在编译时不会造成错误。

同样的Java:

 public final class Bar { } public class Error extends Bar { } 

成为在C + + 11:

 class Bar final { }; class Error : public Bar { }; 

(以前private构造函数可能是最接近你在C ++中得到的)

有趣的是,为了保持与C ++ 11之前的代码的后向兼容性, final 通常不是关键字。 (以简单的,合法的C ++ 98示例struct final;看看为什么使它成为关键字会破坏代码)

在Java中,final关键字可以用于四件事情:

  • 在一个类或方法来密封它(没有子类/超越允许)
  • 在一个成员variables声明,它可以被设置一次(我认为这就是你在说什么)
  • 在一个方法中声明的variables,以确保它可以被设置一次
  • 在方法参数上声明它不能在方法内被修改

一个重要的事情是:一个Java最终成员variables必须设置一次! 例如,在构造函数,字段声明或intializer中。 (但是你不能在方法中设置最终的成员variables)。

使成员variablesfinal的另一个结果涉及到内存模型,这对于在线程环境中工作是非常重要的。

一个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没有固有的方式来声明对象不可变; 你需要把这个类devise成不可变的。

当variables是一个原始types时, final / const工作是一样的。

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

对于原始值types,Java final相当于C ++ const。

对于Java引用types,final关键字等价于一个const指针…即

 //java final int finalInt = 5; final MyObject finalReference = new MyObject(); //C++ const int constInt = 5; MyObject * const constPointer = new MyObject(); 

Javascript只能在原始types和引用上工作,而不能在const关键字在任何东西上工作的对象实例本身。

比较const list<int> melist; final List<Integer> melist; 第一个使得不可能修改列表,而后者只能阻止你为melist分配一个新列表。

你已经有了一些很好的答案,但是有一点似乎值得加上:C ++中的const通常用来防止程序的其他部分改变对象的状态。 正如已经指出的那样,java中的final不能做到这一点(除了原语) – 它只是防止引用被改变为一个不同的对象。 但是,如果您正在使用Collection ,则可以使用静态方法阻止对对象进行更改

  Collection.unmodifiableCollection( myCollection ) 

这将返回一个Collection引用,它提供对元素的读取访问权限,但是如果尝试修改则会引发exception,使得它在C ++中类似于const

除了具有某些细微的multithreading属性之外 ,声明finalvariables不需要在声明中初始化!

即这在Java中是有效的:

 // declare the variable final int foo; { // do something... // and then initialize the variable foo = ...; } 

如果用C ++的const编写,这将是无效的。

根据维基百科 :

  • 在C ++中,const字段不仅不能被重新分配,而且还有一个额外的限制,只有const方法可以被调用,并且只能作为其他方法的constparameter passing。
  • 非静态的内部类可以自由地访问封闭类的任何字段,最终与否。

我猜它说“粗略”,因为当你谈论指针时,C ++中const的含义变得复杂,即常量指针与常量对象的指针。 由于Java中没有“显式”指针,因此final没有这些问题。

让我通过switch / case语句的例子来解释我所理解的。

每个case语句中的值必须是与开关值相同数据types的编译时常量值。

声明如下(在你的方法中作为本地实例,或在你的类中作为静态variables(然后添加静态)或实例variables)。

 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是类/实例variables而不是本地variables,则此代码将不会编译。 如果color1被定义为static final(那么它变成了静态finalvariables),这将会被编译。

当它不编译时,你会得到以下错误

 error: constant string expression required 

关键字“const”表示你的variables被保存在ROM(带有微处理器)中。 在计算机中,您的variables被保存在RAM区域以获取汇编代码(只读RAM)。 这意味着你的variables不在可写RAM中,包括:静态内存,堆栈内存和堆内存。

关键字“final”表示你的variables保存在可写入的RAM中,但是你注意到编译器你的variables只改变了一次。

 //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不使用它。