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 ++关键字中是看不到的。 所以,如果你想要一个成员函数是final
和const
你会做:
class Bar { public: virtual void foo() const final; };
(这里需要const
和final
的顺序)。
以前没有一个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属性之外 ,声明final
variables不需要在声明中初始化!
即这在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不使用它。