【问题标题】:On the static final keywords in Java关于 Java 中的 static final 关键字
【发布时间】: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

标签: java static constants final


【解决方案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并将它分配给变量。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2011-07-02
                              • 1970-01-01
                              • 2016-08-14
                              • 1970-01-01
                              • 2016-12-20
                              • 2011-06-09
                              • 2012-06-28
                              相关资源
                              最近更新 更多