1Java’s finalkeyword has slightly different meanings depending on the context, but in general it says "This cannot be changed."
2A constant is useful for two reasons:
It can be a compile-time constantthat won’t ever change.
It can be a value initialized at run time that you don’t want changed.
3In Java, these sorts of constants must be primitives and are expressed with thefinalkeyword. A value must be given at the time of definition of such a constant.
A field that is both staticandfinalhas only one piece of storage that cannot be changed.
When finalis used with object references rather than primitives, the meaning can be confusing. With a primitive,finalmakes thevaluea constant, but with an object reference,finalmakes the referencea constant. Once the reference is initialized to an object, it can never be changed to point to another object. However, the object itself can be modified; Java does not provide a way to make any arbitrary object a constant.
看个例子:
package access;
//: reusing/FinalData.java
//The effect of final on fields.
import java.util.*;
class Value {
inti;// Package access
public Value(int i) { this.i = i; }
}
public class FinalData {
privatestatic Randomrand =new Random(47);
private Stringid;
public FinalData(String id) {this.id = id; }
//Can be compile-time constants:
privatefinalintvalueOne = 9;
privatestaticfinalintVALUE_TWO = 99;
//Typical public constant:
publicstaticfinalintVALUE_THREE = 39;
//Cannot be compile-time constants:
privatefinalinti4 =rand.nextInt(20);
staticfinalintINT_5 =rand.nextInt(20);
private Valuev1 =new Value(11);
privatefinal Valuev2 =new Value(22);
privatestaticfinal ValueVAL_3 =new Value(33);
//Arrays:
privatefinalint[]a = { 1, 2, 3, 4, 5, 6 };
public String toString() {
returnid +": " +"i4 = " +i4 +", INT_5 = " +INT_5;
}
publicstaticvoid main(String[] args) {
FinalData fd1 = new FinalData("fd1");
//! fd1.valueOne++; // Error: can’t change value
//fd1.valueOne为final,所以不可以改变,参考这句话:
With a primitive, finalmakes thevaluea constant, but with an object reference,finalmakes the referencea constant. Once the reference is initialized to an object, it can never be changed to point to another object. However, the object itself can be modified;
fd1.v2.i++;// Object isn’t constant!
v2指向一个对象,对象可以改变,但v2本身不可变
fd1.v1 =new Value(9);// OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++;// Object isn’t constant!
//! fd1.v2 = new Value(0); // Error: Can’t
不能更改v2所指向的对象
//! fd1.VAL_3 = new Value(1); // change reference
//! fd1.a = newint[3];
a实际指向一个数组的地址,所以不能改变其指向
System.out.println(fd1);
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
final参数:
Java allows you to make arguments final by declaring them as such in the argument list. This means that inside the method you cannot change what the argument reference points to 。
package access;
class Gizmo {
publicinti;
public Gizmo(int i)
{
this.i=i;
}
publicvoid spin() {
i=i+1;
System.out.println(i);
}
}
public class FinalArguments {
void with(final Gizmo g) {
//! g = new Gizmo(); // Illegal -- g is final
System.out.println("it is a final argument");
System.out.println(g.i);
g.i++;
System.out.println((g.i++));
System.out.println(g.toString());
}
void without(Gizmo g) {
g = new Gizmo(2);// OK -- g not final
System.out.println(g.toString());
g.spin();
}
// void f(finalint i) { i++; } // Can’t change
// You can only read from a final primitive:
int g(finalint i) {return i + 1; }
publicstaticvoid main(String[] args) {
FinalArguments bf = new FinalArguments();
Gizmo test = new Gizmo(2);
System.out.println(test.toString());
bf.without(test);
bf.with(test);
}
} ///:~
output:
access.Gizmo@5f155f15
access.Gizmo@5f705f70
3
it is a final argument
2
3
access.Gizmo@5f155f15
通过输出access.Gizmo@5f705f70可以看出在调用without函数的时候实际改变了指向。而由于在with函数中声明为final,对象所指向不能改变。
Final methond:put a "lock" on the method to prevent any inheriting class from changing its meaning. 关于代码优化的已经不是考虑的因素。
Any privatemethods in a class are implicitlyfinal :这句话我还迷惑了一会,注意这里说的是private方法,不是成员变量。
Final class
When you say that an entire class is final(by preceding its definition with thefinalkeyword), you state that you don’t want to inherit from this class or allow anyone else to do so.
static final变量在申明的时候就需要初始化。
static表示所有的类的对象共享一块内存区域,但是static的变量不一定是final的。
如果定义为static final则表示除了所有的对象共享一块内存区域外,还不能修改。
final变量则表示这个变量为常量,但是所有类的对象有各自的存储空间。
摘自Think in Java
Pitfall: “overriding” private methods:
Here’s something you might innocently try to do:
//: polymorphism/PrivateOverride.java
// Trying to override a private method.
package polymorphism;
import static net.mindview.util.Print.*;
public class PrivateOverride {
private void f() { print("private f()"); }
public static void main(String[] args) {
PrivateOverride po = new Derived();
po.f();
}
}
class Derived extends PrivateOverride {
public void f() { print("public f()"); }
} /* Output:
private f()
*///:~
You might reasonably expect the output to be “public f( )”, but a private method is automatically final, and is also hidden from the derived class. So Derived’s f( ) in this case is a brand new method; it’s not even overloaded, since the base-class version of f( ) isn’t visible in Derived.
The result of this is that only non-private methods may be overridden, but you should watch out for the appearance of overriding private methods, which generates no compiler warnings, but doesn’t do what you might expect. To be clear, you should use a different name from a private base-class method in your derived class.
static methods are associated with the class, and not the individual objects
记住一句话:constructors are not polymorphic (they’re actually static methods, but the static declaration is implicit)
the order of constructor calls for a complex object is as follows:
1.
The base-class constructor is called. This step is repeated recursively such that the root of the hierarchy is constructed first, followed by the next-derived class, etc., until the most-derived class is reached.
2.
Member initializers are called in the order of declaration.
3.
The body of the derived-class constructor is called.
The order of disposal should be the reverse of the order of initialization, in case one subobject is dependent on another. For fields, this means the reverse of the order of declaration (since fields are initialized in declaration order). For base classes (following the form that’s used in C++ for destructors), you should perform the derived-class cleanup first, then the base-class cleanup.