关于 Java 中的 static final 关键字
Posted
技术标签:
【中文标题】关于 Java 中的 static final 关键字【英文标题】:On the static final keywords in Java 【发布时间】:2012-12-30 18:53:45 【问题描述】:根据the tutorial:
static
修饰符与final
修饰符结合使用,也用于定义常量。final
修饰符表示该字段的值不能改变。
只有当涉及的类型是原始类型时,我才会同意这一点。使用引用类型,例如一个类Point2D
的实例,它的位置属性不是final
(即,我们可以改变它的位置),这种变量的属性,比如public static final Point2D A = new Point2D(x,y);
,仍然可以改变。这是真的吗?
【问题讨论】:
是的,这个“定义常量”部分具有误导性。 嗯。我们可以在这里用更多的答案来说明这一点。 别忘了 Point2D 是抽象的所以你不能做 new Point2D(x,y); 不可替代 vs 不可变。 让我想起了c++
s const reference 和 reference to const
【参考方案1】:
当引用变量被声明为 final 时,一旦它引用了一个对象,你就不能重新分配一个新对象给它。但是,您可以更改最终引用变量指向的对象的状态。看下面的例子..
class A
int i = 10;
public class UseOfFinalKeyword
public static void main(String[] args)
final A a = new A(); //final reference variable
a.i = 50;
//you can change the state of an object to which final reference variable is pointing
a = new A(); //compile time error
//you can't re-assign a new object to final reference variable
更多信息,请点击链接:final keyword in java
【讨论】:
【参考方案2】:static final Point2D A = new Point2D(x,y);
它所说的只是 Point2D
类的引用不能更改。
_____________
| |
A----------|--->(x,Y) |
| |
|_____________|Heap
所以你不能通过指向不同的对象来改变 A,但是你当然可以改变 (x,y) 的值或点对象的内容
如果你想让你的对象也保持不变,你必须让 Point 对象不可变。
【讨论】:
【参考方案3】:你可以在这里找到一个非常相似的问题,并且解释得很好:
这里: Why can final object be modified?
顺便说一下,我开始思考反射机制......
理论上......我相信你可以获得拥有类实例..然后获取类成员,找到当前实例并检查它是否是最终的......
我没有检查它,我什至不知道它是否可能 - 这只是一个想法(也许?)
在
public class Final
static final Point p = new Point();
public static void main(String[] args) throws MyImmutableException
p = new Point(); // Fails
p.setB(10); // OK
p.setA(20); // Fails - throws MyImmutableException
public class Point()
int a = 10;
int b = 20;
public setA(int a)
this.a = a;
public setB(int b) throws MyImmutableException
detectIsFinal()
this.b = b;
private void detectIsFinal() throws MyImmutableException
int mod = this.getClass().getModifiers()
if (Modifier.isFinal(mod))
throw new MyImmutableException();
public class MyImmutableException extends Exception
public MyImmutableException() super();
我在想你还能做什么......这只是一个!!!!!!!!!伪代码!!! 我不确定它是否会起作用:P
也许有注释知识的人会受到启发并使其发挥作用。不幸的是,我这周没有更多的时间。也许以后我会尝试做一个POC。
public class Final
@Immutable
static final Point p = new Point();
public static void main(String[] args)
p = new Point(); // Fails
p.setB(10); // Fails
p.setA(20); // OK
public class Point()
int a = 10;
@ImmutableOnThisInstance
int b = 20;
@DetectIsImmutable
public setA(int a)
this.a = a;
@DetectIsImmutable
public setB(int b)
this.b = b;
class Immutable
?????????????????
class DetectIsImmutable
/**
* Just a pseudocode - I don't know how to work with ANNOTATIONS :) :) :)
* SORRY :)
* @throws MyImmutableException
*/
private void detectMethod() throws MyImmutableException
Immutable instance = CLASS_THAT_IS_ANNOTATED.getClass().getAnnotation(Immutable.class)
if (instance != null)
// get parent Method invocation name (from stacktrace list)
String methodName = .............;
if (methodName.startsWith("set"))
// check id we have variable with this settername
String fieldName = ...; // cut "set" get rest of it, make first letterSmall
// find this field in object fields
Field f = this.getClass().getDeclaredField(fieldName);
if (f.getAnnotation(ImmutableOnThisInstance.class) != null)
throw MyImmutableException();
【讨论】:
【参考方案4】:是的,可以更改。只有引用不能更改,但其内部字段可以。下面的代码显示了它:
public class Final
static final Point p = new Point();
public static void main(String[] args)
p = new Point(); // Fails
p.b = 10; // OK
p.a = 20; // Fails
class Point
static final int a = 10;
static int b = 20;
【讨论】:
C++ 中的 const 对象呢?【参考方案5】:是的。
当然,你也可以稍后更改final字段的值as described elsewhere。
【讨论】:
【参考方案6】:public static final Point2D A = new Point2D(x,y);仍然可以更改。这是真的吗?
A 的引用不能改变,但如果属性不是最终的,它的真实关联对象的值可以改变。
class Point2D
private int x;
private int y;
<getter & setter>
class Constant
Public static final Point2D A = new Point2D(1,2);
public static void main(String[] args)
A.setX(10); // this will work
A = new Point2D(10,20);// this will not work
如果Point2D's
属性是最终属性,那么Point2D
class
将是immutable
。
或者您可以发送可克隆对象。
喜欢-
private static final Point2D A = new Point2D(x,y);
public static getA()
return A.clone();
【讨论】:
【参考方案7】:正如其他已经提到的,它是对您的 Point2D 对象的引用是静态最终的,而不是属性 x 和 y。如果您想确保不能更改 Point2D 对象的位置,您应该在 Point2D 类中设置属性 x 和 y 静态和最终(初始化)。
【讨论】:
【参考方案8】:这是真的。 final
修饰符不能以任何可能的方式传递。
仅表示参考不会改变。引用的内容(对象的字段)可能会随着时间而改变。
【讨论】:
【参考方案9】:没错,还是可以改的。在这种情况下,“静态最终”是指引用本身,不能更改。但是,如果它所引用的对象是可变的,那么它所引用的对象是可以改变的。
一个不可变的对象,例如一个字符串,将是一个常量。
【讨论】:
【参考方案10】:您可以更改 Point2D 的属性,但不能创建它的新实例。
我还应该提到 Point2D 是抽象的,因此您必须创建一个子类的实例来扩展它。
【讨论】:
【参考方案11】:是的,你是对的。引用不能改变,但被引用的对象可以。这样的事情是完全合法的:
public static final List<Object> someList = new ArrayList<Object>();
// ...
someList.add(someThing); // <-- this would be illegal if the referenced object was also constant
【讨论】:
【参考方案12】:它仍然是真的。
有一种方法可以证明您引用的声明是正确的。 static final
描述了一个变量,这个变量确实不能改变,常数也是如此。变量是指向对象的指针,并且该对象可以更改。但这并不能阻止变量成为常量。
这是一种不太强大的真实方式,您可以在 C++ 中使用 const
实现,但它确实是。
【讨论】:
【参考方案13】:只有引用是最终的,被引用的对象是可以改变的(除非它是一个不可变的对象,比如 Integer 之类的)。所以是的,它仅对于给定的“常量”值是常量。
【讨论】:
【参考方案14】:public static final Point2D A = new Point2D(x,y);
这里 reference A
是 final 并且 不是 Point2D
类中的值。
在定义了静态final之后你就不能这样做了:
//somewhere else in code
A = new Point2D(x1,y1);
【讨论】:
【参考方案15】:对该点的引用(在您的情况下为A
)无法更改。只有对象的状态可以改变。所以你不能创建一个新的Point2D
并将它分配给变量。
【讨论】:
以上是关于关于 Java 中的 static final 关键字的主要内容,如果未能解决你的问题,请参考以下文章
Java基础 | 关于Final Static Abstract修饰需要注意的地方