Java final vs. C ++ const

时间:2011-02-11 16:07:49

标签: java c++ const final

Java for C++ programmers tutorial说(突出显示是我自己的):

  

关键字final是粗略   相当于C ++中的const

在这种情况下,“粗略”是什么意思?他们完全不一样吗?

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

11 个答案:

答案 0 :(得分:182)

在C ++中标记成员函数const意味着可以在const个实例上调用它。 Java没有与之相当的东西。 E.g:

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)不会这样做。 E.g:

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;为例,了解为什么将其作为关键字会破坏代码)

答案 1 :(得分:29)

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

  • 关于密封它的类或方法(不允许子类/覆盖)
  • 在一个成员变量上声明它可以设置一次(我认为这就是你所说的)
  • 对方法中声明的变量,以确保它可以设置一次
  • 关于方法参数,声明它不能在方法
  • 中修改

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

使成员变量final的另一个结果与内存模型有关,如果您在线程环境中工作,这很重要。

答案 2 :(得分:25)

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 :(得分:12)

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

答案 4 :(得分:8)

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

来阻止对对象的更改
 Collection.unmodifiableCollection( myCollection ) 

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

答案 5 :(得分:7)

Java的final仅适用于原始类型和引用,而不适用于const关键字适用于任何事物的对象实例本身。

const list<int> melist;final List<Integer> melist;进行比较,第一个使得无法修改列表,而后者只会阻止您将新列表分配给melist

答案 6 :(得分:3)

除了具有某些subtle multi-threading properties之外,声明 final 的变量不需要在声明时初始化!

即。这在Java中有效:

// declare the variable
final int foo;

{
    // do something...

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

如果使用C ++的 const 编写,则无效。

答案 7 :(得分:2)

根据wikipedia

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

答案 8 :(得分:2)

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

答案 9 :(得分:0)

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

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

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

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定义为静态final(然后它变为静态最终变量),这将编译。

如果不编译,您将收到以下错误

error: constant string expression required

答案 10 :(得分:-5)

关键字“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不会使用它。