Java for C++ programmers tutorial中说(此处突出显示是我加的):
关键字final在Java中大致等同于C++中的const。
这里的“大致”是什么意思?它们难道不是完全相同的吗?
如果有任何区别,那会是什么?
Java for C++ programmers tutorial中说(此处突出显示是我加的):
关键字final在Java中大致等同于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++中,成员变量可以分别为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中,final可以用于标记不可重写的内容。在C++(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实际上允许您将类和成员函数都标记为final
,其语义与Java中的相同功能相同,例如在Java中:
public class Bar {
public final void foo() {
}
}
public class Error extends Bar {
// Error in java, can't override
public void foo() {
}
}
class Bar {
public:
virtual void foo() final;
};
class Error : public Bar {
public:
virtual void foo() final;
};
我不得不使用 G++ 4.7 的预发布版本编译这个示例。需要注意的是,在这种情况下,它并没有替换 const
,而是增加了它,提供了最接近的 C++ 关键字所没有的类似 Java 的行为。因此,如果你想让一个成员函数同时具有 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 {
};
以前在C++中,private
构造函数可能是实现此功能的最接近方式。
有趣的是,为了与C++11之前的代码保持向后兼容性,final
并不像通常的关键字那样。 (看看简单合法的C++98示例struct final;
,就可以知道将其作为关键字会破坏代码)
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
在Java中,final关键字可以用于四个方面:
一个重要的事情是: Java final成员变量必须被设置一次!例如,在构造函数、字段声明或初始化器中。(但您不能在方法中设置final成员变量)。
另一个将成员变量声明为final的后果与内存模型有关,如果您在线程环境中工作,则很重要。
Java中的final关键字相当于C++中对于基本数据类型的const。
对于Java的引用类型,final关键字相当于一个const指针...
//java
final int finalInt = 5;
final MyObject finalReference = new MyObject();
//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();
Java中的final
仅适用于原始类型和引用,而不是对象实例本身,其中const关键字适用于任何内容。
将const list<int> melist;
与final List<Integer> melist;
进行比较,前者使修改列表变得不可能,而后者仅阻止您将新列表分配给melist
。
Collection.unmodifiableCollection( myCollection )
Collection
的引用,它可以读取元素,但如果尝试进行修改则会抛出异常,有点像C++中的const
。final
的变量不需要在声明时进行初始化!// declare the variable
final int foo;
{
// do something...
// and then initialize the variable
foo = ...;
}
const
写法将不被视为有效。const
含义变得复杂,例如常量指针与指向常量对象的指针。由于Java中没有“显式”指针,所以final
就没有这些问题。让我通过一个switch/case语句的例子来解释一下我的理解。
每个case语句中的值必须是编译时常量,并且与switch值具有相同的数据类型。
声明以下内容(可以在您的方法中作为本地实例,也可以在您的类中作为静态变量(然后添加static),或者是一个实例变量)。
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
final int a; a = 10; a = 11;
不是合法的(这就是final
作为变量修饰符的目的)。此外,类的 final 成员只能在声明时或构造函数中设置一次。 - corsiKa