How does the “final” keyword in Java work? (I can still modify an object.)
在Java中,我们使用EDCOX1的0个关键字变量来指定其值不被改变。但我看到您可以更改类的构造函数/方法中的值。同样,如果变量是
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); } } |
以上代码工作正常,无误。
现在将变量改为
1 |
现在它是一个编译错误。这个
这是一个最喜欢的面试问题。通过这个问题,面试官试图了解您对对象在构造器、方法、类变量(静态变量)和实例变量方面的行为有多了解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
在上面的例子中,我们为"test"定义了一个构造函数,并给它一个"setfoo"方法。
关于构造函数:通过使用
关于方法:方法可以被调用任意多次(甚至永远不会),并且编译器知道它。
场景1
1 |
场景2
场景3
1 | t.foo.add("bar"); // Modification-2 |
以上是你的问题。在上述情况下,您不会更改第一个引用对象,而是在
最后一个类不能子类不能重写最终方法。(此方法在超类中)最终方法可以重写。(用语法的方式读这个。此方法在子类中)
始终允许您初始化
注意,对存储在
Java没有对象不可变的概念,这是通过仔细设计对象来实现的,并且远不是微不足道的努力。
final关键字有多种使用方法:
- 最后一个类不能子类。
- 最后一个方法不能被子类重写
- 最后一个变量只能初始化一次
其他用法:
- 当在方法体中定义匿名内部类时,该方法范围内声明为final的所有变量都是从内部类中访问
静态类变量将从JVM的开始就存在,并且应该在类中初始化。如果执行此操作,将不会显示错误消息。
价值类型:对于
引用类型:对于对象的引用,
因此,
如果使
类构造函数(不是实例):
内联:
这里的问题不是
当您在线初始化一个属性时,它会在为构造函数定义的代码运行之前被初始化,因此您会得到以下结果:
- 如果
foo 是static ,那么foo = new ArrayList() 将在为类定义的static{} 构造函数执行之前执行。 - 如果
foo 不是static 的话,foo = new ArrayList() 将在运行构造函数之前执行。
当您不在行中初始化属性时,
您在代码中遇到的错误来自这样一个事实:当类被加载时,在您实例化该类的对象之前,
把
边注:
当您声明一个
在声明
值得一提的是一些直截了当的定义:
类/方法
You can declare some or all of a class methods as
final , in order to indicate that the method cannot be overridden by subclasses.
变量
Once a
final variable has been initialized, it always contains the same value.
这是一个很好的面试问题。有时他们甚至会问你,最终对象和不变对象之间的区别是什么。
1)当有人提到最后一个对象时,这意味着引用不能更改,但是它的状态(实例变量)可以更改。
2)不可变对象是指其状态不能更改,但其引用可以更改的对象。前任:
可以更改引用变量x以指向不同的字符串,但不能更改"abc"的值。
3)实例变量(非静态字段)在调用构造函数时初始化。因此,可以在构造函数中初始化变量的值。
4)"但是我看到您可以更改类的构造函数/方法中的值"。--不能在方法内更改它。
5)在类加载期间初始化静态变量。因此,不能在构造函数内部初始化,必须在它之前完成。因此,您需要在声明过程中为静态变量赋值。
EDCOX1×7是Java中的一个保留关键字,用来限制用户,它可以应用于成员变量、方法、类和局部变量。最终变量通常用Java中的EDCOX1×25个关键字来声明,并被视为常量。例如:
1 |
当我们在变量声明中使用
例如:
1 2 3 4 5 6 | public class ClassDemo { private final int var1 = 3; public ClassDemo() { ... } } |
注意:声明为final的类不能扩展或继承(即,不能有超级类的子类)。值得注意的是,声明为final的方法不能被子类重写。
使用final关键字的好处在这个线程中得到了解决。
在Java中使用EDCOX1 0个关键字来限制用户。Java EDCOX1的0个关键字可以在许多上下文中使用。决赛可以是:
Java最终变量:
如果将任何变量设为
有一个最终变量speedlimit,我们要改变这个变量的值,但是它不能改变,因为一旦给最终变量赋值,就永远不能改变。
1 2 3 4 5 6 7 8 9 10 11 | 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最终类:
如果您将任何类设置为
最后一堂课的例子
1 2 3 4 5 6 7 8 9 10 11 12 |
Java最终方法:
如果将任何方法设为最终方法,则不能重写它。
1 2 3 4 5 6 7 8 9 10 11 12 |
共享:http://www.javatpoint.com/final-keyword
假设你有两个钱箱,红的和白的。你只给这些钱箱分配了两个孩子,不允许他们交换钱箱。所以你有红色或白色的钱箱(最终版),你不能修改这个盒子,但你可以把钱放在你的盒子上。没人在乎(修改-2)。
阅读所有答案。
还有另一个用户案例,其中可以使用
1 2 3 4 5 | public void showCaseFinalArgumentVariable(final int someFinalInt){ someFinalInt = 9; // won't compile as the argument is final } |
可用于不应更改的变量。
我想在这里写一个更新和深入的答案。
一个
前任:
1 2 3 4 | F myF; myF = new F(); //ok myF = someOther; //someOther cannot be in type of a child class of F. //because F cannot be extended. |
因此,当它执行该对象的任何方法时,不需要使用虚拟表在运行时解析该方法。也就是说,不能应用运行时多态性。所以运行时间并不麻烦。这意味着它可以节省处理时间,从而提高性能。
任何类的
如果上述任何一种指定为
前任:
对于字段,本地参数
1 2 3 4 5 6 | final FinalClass fc = someFC; //need to assign straight away. otherwise compile error. final FinalClass fc; //compile error, need assignment (initialization inside a constructor Ok, constructor can be called only once) final FinalClass fc = new FinalClass(); //ok fc = someOtherFC; //compile error fc.someMethod(); //no problem someOtherFC.someMethod(); //no problem |
用于方法参数
1 2 3 |
这仅仅意味着不能更改
因此,在上述3个场景中,当我们没有在可以使用的地方指定
1 |
当您将
当您在
当您使它成为静态的final时,它应该在静态初始化块中初始化。
1 2 3 4 5 6 7 8 9 10 11 |
首先,代码中初始化foo的位置(即第一次分配)如下:
1 |
foo是一个对象(带有类型列表),所以它是一个引用类型,而不是值类型(如int)。因此,它保存对存储列表元素的内存位置(例如,0xA7D2A834)的引用。像这样的线
1 | foo.add("foo"); // Modification-1 |
不要更改foo的值(同样,它只是对内存位置的引用)。相反,它们只是将元素添加到引用的内存位置。要违反最后一个关键字,您必须再次尝试重新分配foo,如下所示:
1 |
这会给你一个编译错误。
现在,排除了这一点,考虑一下添加静态关键字时会发生什么。
如果没有静态关键字,则实例化类的每个对象都有自己的foo副本。因此,构造函数为foo变量的空白新副本赋值,这是完全正确的。
但是,当您拥有static关键字时,在与类关联的内存中只存在一个foo。如果要创建两个或多个对象,构造函数将试图每次重新分配一个foo,这违反了最后一个关键字。
下面是使用final的不同上下文。
最终变量最终变量只能分配一次。如果变量是引用,这意味着变量不能重新绑定到引用另一个对象。
1 2 3 4 5 6 | class Main { public static void main(String args[]){ final int i = 20; i = 30; //Compiler Error:cannot assign a value to final variable i twice } } |
最终变量可以稍后赋值(声明时不强制赋值),但只能赋值一次。
final类不能扩展(继承)final类
1 2 3 4 5 6 7 | final class Base { } class Derived extends Base { } //Compiler Error:cannot inherit from final Base public class Main { public static void main(String args[]) { } } |
final方法final方法不能被子类重写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //Error in following program as we are trying to override a final method. class Base { public final void show() { System.out.println("Base::show() called"); } } class Derived extends Base { public void show() { //Compiler Error: show() in Derived cannot override System.out.println("Derived::show() called"); } } public class Main { public static void main(String[] args) { Base b = new Derived();; b.show(); } } |
最重要的是正确的。此外,如果您不希望其他人从您的类中创建子类,那么将您的类声明为final。然后它成为类树层次结构的叶级,没有人可以进一步扩展它。避免类的巨大层次结构是一个很好的实践。