Java的最终与C的const

问题

TheJava for C++ programmers tutorialsays(突出显示是我自己的):

关键字final大致相当于C中的const

在这种情况下,"粗略"是什么意思?它们是不是完全相同?

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


#1 热门回答(180 赞)

在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 {
   }
};

这很好,因为标记成员functionconst的语义不同。 (你也可以只通过其中一个成员函数来执行过载。(另请注意,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 {
};

(以前806909066建筑师可能是你在C中最接近这一点的人)

有趣的是,为了以通常的方式保持与前C 11 codefinalisn'ta关键字的向后兼容性。 (采取琐碎,合法的C 98示例struct final;,看看为什么使它成为关键字会破坏代码)


#2 热门回答(28 赞)

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

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

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

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


#3 热门回答(25 赞)

Aconst对象只能调用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)

Afinal对象不能设置为新对象,但它不是不可变的 - 没有什么能阻止某人调用anyset方法。

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