在Java中的静态最终关键字
根据教程 :
static
修饰符与final
修饰符一起也用于定义常量。final
修饰符表示这个字段的值不能改变。
只有涉及的types是原始的,我才会同意这一点。 对于引用types,例如一个Point2D
类的实例,其位置属性不是final
(即,我们可以改变它的位置),这类variables的属性如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 pb = 10; // OK pa = 20; // Fails } } class Point { static final int a = 10; static int b = 20; }
Groovy (一种替代的JVM语言)有一个名为@Immutable的注解,它在构造之后阻止更改为对象的内部状态。
正确的,它仍然可以改变。 在这种情况下,“静态最终”是指参考本身,它是不能改变的。 但是,如果它所引用的对象是可变的,那么它所引用的对象可以被改变。
一个不可变的对象,比如一个String,将是一个常量。
public static final Point2D A = new Point2D(x,y);
这里的引用 A
是final的,而不是 Point2D
类中的值 。
在定义一个static final之后你不能这样做:
//somewhere else in code A = new Point2D(x1,y1);
这是真的。 final
修饰语不是以任何可能的方式传递的。
这只意味着参考不会改变。 引用的内容(对象的字段)可能随时间而改变。
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
属性是final的,那么Point2D
class
将是immutable
。
或者您可以发送可克隆的对象。
喜欢 –
private static final Point2D A = new Point2D(x,y); public static getA(){ return A.clone(); }
点( A
在你的情况下)的参考不能改变。 只有对象的状态才能改变。 所以你不能创build一个新的Point2D
并将其分配给variables。
只有引用是final的,被引用的对象可以被改变(除非它是一个不可变的对象,比如Integer或类似的)。 所以是的,只有恒定的恒定值
是。
当然,你也可以稍后改变最终字段的值, 如别处所述 。
你可以在这里find一个非常类似的问题,相当好的解释:
这里: 为什么可以修改最终对象?
顺便说一下,我开始思考reflection机制….
在理论上…我相信你可以得到拥有类实例..然后获得类成员,find当前的实例,并检查它是最终….
我没有检查,如果可能的话,我甚至不知道 – 这只是一个想法(也许?)
在
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(); } }
我在想你还能做什么…再次只是一个!!!!!!!!! PSEUDOCODE !!! 我不确定它是否会工作: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(); } } } } }
这仍然是事实。
有一种方法,你所引用的索赔是真实的。 static final
描述了一个variables ,这个variables是不能改变的,所以是一个常量。 variables是一个指向对象的指针,该对象可以改变。 但是这并不能阻止这个variables是一个常量。
这是一个不太强大的方法,你可以用C ++中的const
来实现,但这是事实。
是的,你是对的。 引用不能改变,但被引用的对象可以是。 像这样的东西是完全合法的:
public static final List<Object> someList = new ArrayList<Object>(); // ... someList.add(someThing); // <-- this would be illegal if the referenced object was also constant
您可以更改Point2D的属性,但不能创build它的新实例。
我还应该提到Point2D是抽象的,所以你必须创build一个扩展这个子类的实例。
正如其他人已经提到的那样,它是对你的Point2D对象的引用是静态的最终的,而不是属性x和y。 如果你想确保你不能改变Point2D对象的位置,你应该在Point2D类中设置属性x和y static和final(初始化)。
static final Point2D A = new Point2D(x,y);
所有它说的是Point2D
引用无法改变。
_____________ | | A----------|--->(x,Y) | | | |_____________|Heap
所以你不能通过指向不同的对象来改变A,当然你可以改变(x,y)的值或Point对象的内容
如果你想让你的对象也是常量,你将不得不使Point对象不可变。
当一个引用variables被声明为final时,一旦引用了一个对象,就不能重新分配一个新的对象。 但是,您可以更改最终引用variables所指向的对象的状态。 看下面的例子..
class A { int i = 10; } public class UseOfFinalKeyword { public static void main(String[] args) { final A a = new A(); //final reference variable ai = 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关键字