Java 的 final 和 C + + 的 const

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

关键字 final 大致是 < strong > 等效于 C + + 中的 const

“粗略”在这个上下文中是什么意思? 它们不是一样的吗?

如果有区别的话,有什么区别?

75942 次浏览

在 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 + + (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,而是增强了它,提供了类 Java 的行为,而这种行为在最接近等效的 C + + 关键字中是看不到的。所以如果你想让一个成员函数同时是 finalconst,你可以这样做:

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

(这里需要 constfinal的订单)。

以前没有直接等价于 const成员函数,尽管使函数非 virtual将是一个潜在的选择,尽管在编译时不会导致错误。

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 关键字可用于以下四个方面:

  • 对类或方法进行密封(不允许子类/重写)
  • 对一个成员变量声明它只能被设置一次(我想这就是你所说的)
  • 对方法中声明的变量进行设置,以确保该变量只能设置一次
  • 在方法参数上声明它不能在方法内修改

一件重要的事情是: Java 最终成员变量 必须的只设置一次!例如,在构造函数、字段声明或初始化器中。(但不能在方法中设置最终成员变量)。

使成员变量成为 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

根据 维基百科:

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

我猜它说“粗略”是因为当你谈论指针时,C + + 中 const的含义变得复杂了,比如常量指针和指向常量对象的指针。因为在 Java 中没有“显式”指针,所以 final没有这些问题。

Java 的 final只能处理基本类型和引用,而不能处理 const 关键字处理任何事情的对象实例本身。

const list<int> melist;final List<Integer> melist;进行比较,前者使得不可能修改列表,而后者只会阻止您将新列表分配给 melist

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();

这里已经有了一些很好的答案,但有一点似乎值得补充: C + + 中的 const通常用于防止程序的其他部分改变对象的状态。正如已经指出的那样,Java 中的 final不能这样做(除了原语)-它只是阻止 参考文献被更改为另一个对象。但是,如果您使用的是 Collection,则可以通过使用静态方法来防止对对象的更改

 Collection.unmodifiableCollection( myCollection )

这将返回一个 Collection引用,该引用提供对元素的读访问,但是如果尝试进行修改,将抛出一个异常,使其有点像 C + + 中的 const

除了具有某些和 微妙的多线程属性,声明的变量 final不需要在声明时初始化!

这在 Java 中是有效的:

// declare the variable
final int foo;


{
// do something...


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

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

关键字“ const”表示您的变量保存在 ROM 中(使用微处理器)。在计算机中,变量保存在 RAM 区域中,用于汇编代码(只读 RAM)。这意味着变量不在可写 RAM 中,包括: 静态内存、堆内存和堆内存。

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

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

让我用 switch/case 语句的例子来解释我所理解的内容。

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

声明类似下面的内容(在方法中作为本地实例,或者在类中作为静态变量(然后向它添加静态变量) ,或者一个实例变量。

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被定义为 static final (那么它就变成 static final 变量) ,那么它将进行编译。

当它不编译时,您将得到以下错误

error: constant string expression required