关于Java中的静态final关键字

时间:2013-01-16 12:38:48

标签: java static constants final

根据the tutorial

  

static修饰符与final修饰符结合使用,也用于定义常量。 final修饰符表示此字段的值不能更改。

只有涉及的类型是原始的,我才同意这一点。使用参考类型,例如类Point2D的实例,其位置属性不是final(即,我们可以更改其位置),此类变量(如public static final Point2D A = new Point2D(x,y);)的属性仍然可以更改。这是真的吗?

15 个答案:

答案 0 :(得分:67)

是的,它可以改变。只能更改引用,但其内部字段可以是。以下代码显示了它:

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的注释,它在构造对象后阻止更改为对象的内部状态。

答案 1 :(得分:16)

正确,它仍然可以改变。在这种情况下," static final"指的是引用本身,不能更改。但是,如果它是引用的对象是可变的,则可以更改它引用的对象。

不可变对象(如String)将是常量。

答案 2 :(得分:10)

public static final Point2D A = new Point2D(x,y);

此处参考 A 最终不是类Point2D内的值

定义静态最终结果后,您无法执行此操作:

//somewhere else in code
A = new Point2D(x1,y1);

答案 3 :(得分: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属性为final,则Point2D class将为immutable

或者您可以发送可克隆的对象。

喜欢 -

 private static final Point2D A = new Point2D(x,y);
 public static getA(){
     return A.clone();
 }

答案 4 :(得分:6)

这是真的。 final修饰符不会以任何可能的方式传递。

这只表示引用不会改变。参考的内容(对象的字段)可能会随着时间而改变。

答案 5 :(得分:2)

对点(您的案例中为A)的引用无法更改。只有对象的状态才能改变。因此,您无法创建新的Point2D并将其分配给变量。

答案 6 :(得分:2)

只有引用是最终的,引用的对象可以更改(除非它是一个不可变的对象,如Integer等)。所以是的,对于给定的“常数”值,它只是常数。

答案 7 :(得分:1)

当然,您也可以稍后更改最终字段的值as described elsewhere

答案 8 :(得分:1)

你可以在这里找到一个非常类似的问题,并有很好的解释:

下面: 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(); }
}

我在想你还能做些什么...再次它只是一个!!!!!!!!! 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();
                }
            }
        }
    }           

}

答案 9 :(得分:0)

仍然如此。

您引用的声明有一种方法是正确的。 static final描述了变量,并且该变量无法更改,因此是常量。变量是指向对象的指针,该对象可以更改。但这并不能阻止变量成为常数。

这是一种不那么强大的方法,你可以用C ++中的const来实现,但它就是这样。

答案 10 :(得分:0)

是的,你是对的。引用不能更改,但引用的对象可以是。这样的事情是完全合法的:

public static final List<Object> someList = new ArrayList<Object>();

// ...

someList.add(someThing); // <-- this would be illegal if the referenced object was also constant

答案 11 :(得分:0)

您可以更改Point2D的属性,但不能创建它的新实例。

我还应该提到Point2D是抽象的,所以你必须创建一个扩展它的子类的实例。

答案 12 :(得分:0)

正如其他已经提到的那样,它是对Point2D对象的引用,它是静态final,而不是属性x和y。如果你想确保你不能改变Point2D对象的位置,你应该在Point2D类中设置属性x和y static和final(初始化)。

答案 13 :(得分:0)

static final Point2D A = new Point2D(x,y);

所有它都说是Point2D类的引用无法改变。

            _____________
           |             |
A----------|--->(x,Y)    |
           |             | 
           |_____________|Heap

所以你不能通过指向不同的对象来改变A,当然你可以改变(x,y)的值或点对象的内容

如果你想使你的对象也是常数,你必须使Point对象不可变。

答案 14 :(得分:0)

当引用变量声明为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