关于 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 referencereference 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 Afinal 并且 不是 Point2D 类中的值

在定义了静态final之后你就不能这样做了:

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

【讨论】:

【参考方案15】:

对该点的引用(在您的情况下为A)无法更改。只有对象的状态可以改变。所以你不能创建一个新的Point2D并将它分配给变量。

【讨论】:

以上是关于关于 Java 中的 static final 关键字的主要内容,如果未能解决你的问题,请参考以下文章

Java基础 | 关于Final Static Abstract修饰需要注意的地方

Java关键字——final

Java finally关键字

java 中的static和final怎么使用?它们的区别?

关于JAVA中的前期绑定 后期绑定(动态绑定)

[转] Java中public,private,final,static等概念的解读