根据教程:
修饰符与修饰符
static
结合使用final
,也用于定义常量。修饰符表示该final
字段的值不能改变。
只有当所涉及的类型是原始的时,我才会同意这一点。对于引用类型,例如Point2D
位置属性不存在的类的实例final
(即,我们可以更改其位置),此类变量的属性public static final Point2D A = new Point2D(x,y);
仍然可以更改。这是真的?
是的,它可以改变。只有引用不能更改,但其内部字段可以。以下代码显示了它:
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;
}
Groovy(另一种JVM语言)有一个名为@Immutable的注解,它会阻止对象在构造后更改为内部状态。
没错,还是可以改的。在这种情况下,“静态最终”是指引用本身,不能更改。但是,如果它所引用的对象是可变的,那么它所引用的对象就可以改变。
一个不可变的对象,例如一个字符串,将是一个常量。
public static final Point2D A = new Point2D(x,y);
这里的引用 A
是最终的,而不是类中的值Point2D
。
在定义 A static final 后你不能这样做:
//somewhere else in code
A = new Point2D(x1,y1);
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();
}
这是真的。final
修饰符不是以任何可能的方式传递的。
这只意味着参考不会改变。引用的内容(对象的字段)可能会随着时间而改变。
对这一点的引用(A
在你的情况下)不能改变。只有对象的状态可以改变。所以你不能创建一个新的Point2D
并将它分配给变量。
只有引用是最终的,被引用的对象是可以改变的(除非它是一个不可变的对象,比如 Integer 之类的)。所以是的,它仅对于给定的“常数”值是常数。
你可以在这里找到一个非常相似的问题,并有很好的解释:
HERE: 为什么可以修改最终对象?
顺便说一句,我开始考虑反射机制....
理论上......我相信你可以获得拥有类实例..然后获取类成员,找到当前实例并检查它是否是最终的......
我没有检查它,我什至不知道它是否可能 - 这只是一个想法(也许?)
在
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();
}
}
}
}
}
是的。
当然,您也可以稍后更改 final 字段的值,如别处所述。
正如其他已经提到的,它是对您的 Point2D 对象的引用,它是静态最终的,而不是属性 x 和 y。如果要确保不能更改 Point2D 对象的位置,则应在 Point2D 类中设置属性 x 和 y 静态和最终(初始化)。
它仍然是真实的。
有一种方法可以证明您引用的声明是真实的。static final
描述了一个变量,这个变量确实不能改变,常数也是如此。变量是指向对象的指针,并且该对象可以更改。但这并不能阻止变量成为常数。
这是一种不太强大的真实方式,您可以const
在 C++ 中实现,但它确实如此。
是的,你是对的。引用不能改变,但被引用的对象可以。这样的事情是完全合法的:
public static final List<Object> someList = new ArrayList<Object>();
// ...
someList.add(someThing); // <-- this would be illegal if the referenced object was also constant
您可以更改 Point2D 的属性,但不能创建它的新实例。
我还应该提到 Point2D 是抽象的,因此您必须创建一个子类的实例来扩展它。
当引用变量被声明为 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
}
}
有关更多信息,请点击链接:java 中的 final 关键字
static final Point2D A = new Point2D(x,y);
它所说的只是类的引用Point2D
不能改变。
_____________
| |
A----------|--->(x,Y) |
| |
|_____________|Heap
所以你不能通过指向不同的对象来改变 A 但是你当然可以改变 (x,y) 的值或者 Point Object 的内容
如果你想让你的对象也保持不变,你必须使 Point 对象不可变。