在Java中,我们使用带有变量的final关键字来指定其不被更改的值。 但我看到你可以改变类的构造函数/方法的值。同样,如果变量是静态的,那么这是一个编译错误。

代码如下:

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }
  public static void main(String[] args) 
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

以上代码工作正常,没有错误。

现在将变量更改为静态:

private static final List foo;

现在它是一个编译错误。期末考试是怎么进行的呢?


当前回答

final是Java中限制用户的保留关键字,它可以应用于成员变量、方法、类和局部变量。Final变量通常在Java中使用static关键字声明,并被视为常量。例如:

public static final String hello = "Hello";

当我们在变量声明中使用final关键字时,存储在该变量中的值不能在后面更改。

例如:

public class ClassDemo {
  private final int var1 = 3;
  public ClassDemo() {
    ...
  }
}

注意:声明为final的类不能扩展或继承(也就是说,不能有超类的子类)。同样值得注意的是,声明为final的方法不能被子类重写。

使用final关键字的好处将在本文中讨论。

其他回答

值得一提的是一些简单的定义:

类/方法

您可以将类的部分或全部方法声明为final,以指示该方法不能被子类覆盖。

变量

一旦final变量初始化,它总是包含相同的值。

Final基本上避免被任何东西(子类,变量“重赋”)覆盖/上写,这取决于情况。

首先,在你的代码中初始化(即第一次赋值)foo的地方在这里:

foo = new ArrayList();

foo是一个对象(类型为List),因此它是一个引用类型,而不是一个值类型(如int)。因此,它持有对存储List元素的内存位置(例如0xA7D2A834)的引用。像这样的线

foo.add("foo"); // Modification-1

不要更改foo的值(同样,它只是一个对内存位置的引用)。相反,它们只是在引用的内存位置中添加元素。要违反final关键字,你必须尝试重新分配foo,如下所示:

foo = new ArrayList();

这将导致编译错误。


现在,考虑一下当您添加static关键字时会发生什么。

当你没有static关键字时,实例化类的每个对象都有自己的foo副本。因此,构造函数将一个值赋给foo变量的一个空白的新副本,这是完全没问题的。

然而,当你有static关键字时,内存中只有一个foo与类相关联。如果要创建两个或多个对象,构造函数每次都会尝试重新分配那个foo,这违反了final关键字。

这是一个很常见的面试问题。通过这些问题,面试官试图了解你对对象行为的理解程度,包括构造函数、方法、类变量(静态变量)和实例变量。 如今,面试官们会问另一个最受欢迎的问题:java 1.8的最终版本是什么?我将在最后在java 1.8中解释这个有效的final。

import java.util.ArrayList;
import java.util.List;

class Test {
    private final List foo;

    public Test() {
        foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

    public void setFoo(List foo) {
       //this.foo = foo; Results in compile time error.
    }
}

在上面的例子中,我们为'Test'定义了一个构造函数,并给了它一个'setFoo'方法。

关于构造函数:通过使用new关键字,每次创建对象只能调用构造函数一次。不能多次调用构造函数,因为构造函数不是这样设计的。

关于方法:一个方法可以被你想调用多少次就调用多少次(甚至从来没有调用过),而且编译器知道它。

场景1

private final List foo;  // 1

foo is an instance variable. When we create Test class object then the instance variable foo, will be copied inside the object of Test class. If we assign foo inside the constructor, then the compiler knows that the constructor will be invoked only once, so there is no problem assigning it inside the constructor. If we assign foo inside a method, the compiler knows that a method can be called multiple times, which means the value will have to be changed multiple times, which is not allowed for a final variable. So the compiler decides constructor is good choice! You can assign a value to a final variable only one time.

场景2

private static final List foo = new ArrayList();

foo is now a static variable. When we create an instance of Test class, foo will not be copied to the object because foo is static. Now foo is not an independent property of each object. This is a property of Test class. But foo can be seen by multiple objects and if every object which is created by using the new keyword which will ultimately invoke the Test constructor which changes the value at the time of multiple object creation (Remember static foo is not copied in every object, but is shared between multiple objects.)

场景3

t.foo.add("bar"); // Modification-2

以上修改-2来自你的问题。在上面的例子中,你没有改变第一个被引用的对象,但是你在foo中添加了允许的内容。如果你试图给foo引用变量赋值一个新的ArrayList(),编译器会报错。 如果你已经初始化了一个final变量,那么你不能改变它来引用一个不同的对象。(在本例中是ArrayList)

Final类不能被子类化 Final方法不能被覆盖。(此方法在超类中) Final方法可以被重写。(请按语法方式阅读。这个方法在一个子类中)

现在让我们看看在java 1.8中什么是有效的最终版本?

public class EffectivelyFinalDemo { //compile code with java 1.8
    public void process() {
        int thisValueIsFinalWithoutFinalKeyword = 10; //variable is effectively final
        
        //to work without final keyword you should not reassign value to above variable like given below 
        thisValueIsFinalWithoutFinalKeyword = getNewValue(); // delete this line when I tell you.
        
        class MethodLocalClass {
            public void innerMethod() {
                //below line is now showing compiler error like give below
                //Local variable thisValueIsFinalWithoutFinalKeyword defined in an enclosing scope must be final or effectively final
                System.out.println(thisValueIsFinalWithoutFinalKeyword); //on this line only final variables are allowed because this is method local class
                // if you want to test effectively final is working without final keyword then delete line which I told you to delete in above program.  
            }
        }
    }

    private int getNewValue() {
        return 0;
    }
}

如果你没有使用final关键字,上面的程序将在java 1.7或<1.8中抛出错误。effective final是方法局部内部类的一部分。我知道你很少在本地类中使用这样有效的final,但是对于面试,我们必须做好准备。

假设你有两个储蓄罐,红的和白的。你把这些钱箱只分配给两个孩子,他们不允许交换他们的钱箱。所以你有红色或白色的钱箱(最终),你不能修改盒子,但你可以把钱放在你的盒子上。没人在乎(修改-2)。

java中的final关键字用于限制用户。java final关键字可以在许多上下文中使用。Final可以是:

变量 方法 类

final关键字可以与变量一起应用,没有值的final变量称为空白final变量或未初始化final变量。它只能在构造函数中初始化。空白的final变量也可以是静态的,它只会在静态块中初始化。

Java final变量:

如果你让任何变量作为final,你不能改变final变量的值(它将是常量)。

final变量示例

有一个最终变量的速度限制,我们将改变这个变量的值,但它不能改变,因为最终变量一旦赋值就永远不能改变。

class Bike9{  
    final int speedlimit=90;//final variable  
    void run(){  
        speedlimit=400;  // this will make error
    }  

    public static void main(String args[]){  
    Bike9 obj=new  Bike9();  
    obj.run();  
    }  
}//end of class  

Java最终类:

如果将任何类设置为final类,则不能扩展它。

final类示例

final class Bike{}  

class Honda1 extends Bike{    //cannot inherit from final Bike,this will make error
  void run(){
      System.out.println("running safely with 100kmph");
   }  

  public static void main(String args[]){  
      Honda1 honda= new Honda();  
      honda.run();  
      }  
  }  

Java final方法:

如果您将任何方法设置为final,则不能重写它。

final方法示例 (Honda中的run()不能覆盖Bike中的run())

class Bike{  
  final void run(){System.out.println("running");}  
}  

class Honda extends Bike{  
   void run(){System.out.println("running safely with 100kmph");}  

   public static void main(String args[]){  
   Honda honda= new Honda();  
   honda.run();  
   }  
}  

共享: http://www.javatpoint.com/final-keyword