在Java中,我们使用final带变量的关键字来指定其值不被更改.但我发现你可以改变类的构造函数/方法中的值.同样,如果变量是,static那么它是编译错误.
这是代码:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码工作正常,没有错误.
现在将变量更改为static:
private static final List foo;
Run Code Online (Sandbox Code Playgroud)
现在是编译错误.这final真的有用吗?
Ami*_*itG 562
这是一个最喜欢的面试问题.通过这些问题,访问者试图找出你对构造函数,方法,类变量(静态变量)和实例变量的对象行为的理解程度.
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.
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我们为'Test'定义了一个构造函数,并给它一个'setFoo'方法.
关于构造函数:通过使用关键字,每个对象创建 只能调用一次构造函数new.您不能多次调用构造函数,因为构造函数不是为此而设计的.
关于方法:可以根据需要多次调用方法(即使从不),编译器也知道它.
场景1
private final List foo; // 1
Run Code Online (Sandbox Code Playgroud)
foo是一个实例变量.当我们创建Test类对象然后实例变量时foo,将被复制到Test类的对象中.如果我们foo在构造函数内部分配,那么编译器知道构造函数只会被调用一次,所以在构造函数中分配它没有问题.
如果我们foo在方法内部分配,编译器知道可以多次调用方法,这意味着必须多次更改该值,这对于final变量是不允许的.所以编译器决定构造函数是个不错的选择!您只能为最终变量赋值一次.
情景2
private static final List foo = new ArrayList();
Run Code Online (Sandbox Code Playgroud)
foo现在是一个静态变量.当我们创建一个Test类的实例时,foo不会被复制到该对象,因为它foo是静态的.现在foo不是每个对象的独立属性.这是一个Test类的属性.但是foo可以通过多个对象看到,并且每个通过使用new关键字创建的对象最终会调用Test构造函数来更改多个对象创建时的值(记住static foo不会复制到每个对象中,而是在多个对象之间共享.)
场景3
t.foo.add("bar"); // Modification-2
Run Code Online (Sandbox Code Playgroud)
以上Modification-2是你的问题.在上面的例子中,您没有更改第一个引用的对象,但是您要添加foo允许的内容.如果您尝试将a分配new ArrayList()给foo引用变量,则编译器会抱怨.
规则如果已初始化final变量,则无法更改它以引用其他对象.(在这种情况下ArrayList)
最终类不能被子类化,
最终方法不能被重写.(此方法是超类)
最终方法可以覆盖.(以语法的方式阅读.此方法在子类中)
Mar*_*nik 497
你总是允许初始化一个final变量.编译器确保您只能执行一次.
请注意,对存储在final变量中的对象的调用方法与其语义无关final.换句话说:final只是关于引用本身,而不是引用对象的内容.
Java没有对象不变性的概念; 这是通过精心设计物体来实现的,并且是一项非常重要的工作.
czu*_*upe 205
Final关键字有多种使用方式:
其他用途:
静态类变量将从JVM的开头存在,并且应该在类中初始化.如果执行此操作,则不会显示错误消息.
Sma*_*ker 52
该final关键字可以在这取决于它的使用两种不同的解释:
值类型:对于ints,doubles等,它将确保值不会改变,
引用类型:对于对象final的引用,确保引用永远不会更改,这意味着它将始终引用同一对象.它不保证所引用的对象内部的值保持不变.
因此,final List<Whatever> foo;确保foo始终引用相同的列表,但是所述列表的内容可能随时间而改变.
luc*_*mon 23
如果您创建foo静态,则必须在类构造函数(或您定义它的内联)中初始化它,如下面的示例所示.
类构造函数(不是实例):
private static final List foo;
static
{
foo = new ArrayList();
}
Run Code Online (Sandbox Code Playgroud)
排队:
private static final List foo = new ArrayList();
Run Code Online (Sandbox Code Playgroud)
这里的问题不是final修饰符的工作原理,而是static修饰符的工作原理.
该final修正通过调用构造函数完成时间(即必须在构造函数初始化)强制参考的初始化.
当您在线初始化属性时,它会在您为构造函数定义的代码运行之前初始化,因此您将获得以下结果:
foois static,foo = new ArrayList()将在static{}您为类定义的构造函数执行之前执行foo不是static,foo = new ArrayList()将在构造函数运行之前执行如果不在线final初始化属性,则修饰符会强制您初始化它,并且必须在构造函数中执行此操作.如果你还有一个static修饰符,你必须初始化属性的构造函数是类的初始化块:static{}.
您在代码中获得的错误来自于在static{}实例化该类的对象之前加载类时运行的事实.因此,foo在创建类时,您将没有初始化.
将static{}块视为类型对象的构造函数Class.这是您必须初始化static final类属性的地方(如果没有内联完成).
边注:
该final修改确保常量性只对基本类型和引用.
声明final对象时,获得的是对该对象的final 引用,但对象本身不是常量.
在声明final属性时,您真正实现的是,一旦您为特定目的声明了一个对象(如final List您已声明的那个),那么该对象将仅用于此目的:您将无法更改List foo为另一个List,但你仍然可以List通过添加/删除项目来改变你(List你使用的将是相同的,只是改变了它的内容).
这是一个非常好的面试问题.有时他们甚至会问你最终对象和不可变对象之间的区别.
1)当有人提到最终对象时,意味着不能更改引用,但可以更改其状态(实例变量).
2)不可变对象是一个状态不能改变的对象,但它的引用可以改变.例如:
String x = new String("abc");
x = "BCG";
Run Code Online (Sandbox Code Playgroud)
ref变量x可以更改为指向不同的字符串,但不能更改"abc"的值.
3)在调用构造函数时初始化实例变量(非静态字段).因此,您可以将值初始化为构造函数中的变量.
4)"但我发现你可以改变类的构造函数/方法中的值". - 您无法在方法中更改它.
5)在类加载期间初始化静态变量.所以你不能在构造函数内初始化,它必须在它之前完成.因此,您需要在声明本身期间为静态变量赋值.
值得一提的是一些直截了当的定义:
类/方法
您可以将一些或所有类方法声明为
final,以指示该方法不能被子类覆盖.
变量
一旦一个
final变量被初始化,它总是包含相同的值.
final 基本上避免覆盖/替换任何东西(子类,变量"重新分配"),具体取决于具体情况.
finaljava中的关键字用于限制用户。java final关键字可以在许多上下文中使用。最终可以是:
的final关键字可与变量被应用,一个final不具有任何值的变量,被称为空白final变量或未初始化final变量。它只能在构造函数中初始化。空白final变量也可以仅static在static块中初始化。
Java最终变量:
如果你做任何变量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
Run Code Online (Sandbox Code Playgroud)
Java最终课程:
如果将任何类设置为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();
}
}
Run Code Online (Sandbox Code Playgroud)
Java最终方法:
如果将任何方法作为最终方法,则无法覆盖它。
final方法示例(本田中的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();
}
}
Run Code Online (Sandbox Code Playgroud)
共享自:http : //www.javatpoint.com/final-keyword
"A final variable can only be assigned once"
*Reflection*- “哇哇等等,拿着我的啤酒”。冻结的final领域在两种情况下发生:
让我们触犯法律
public class HoldMyBeer
{
final int notSoFinal;
public HoldMyBeer()
{
notSoFinal = 1;
}
static void holdIt(HoldMyBeer beer, int yetAnotherFinalValue) throws Exception
{
Class<HoldMyBeer> cl = HoldMyBeer.class;
Field field = cl.getDeclaredField("notSoFinal");
field.setAccessible(true);
field.set(beer, yetAnotherFinalValue);
}
public static void main(String[] args) throws Exception
{
HoldMyBeer beer = new HoldMyBeer();
System.out.println(beer.notSoFinal);
holdIt(beer, 50);
System.out.println(beer.notSoFinal);
holdIt(beer, 100);
System.out.println(beer.notSoFinal);
holdIt(beer, 666);
System.out.println(beer.notSoFinal);
holdIt(beer, 8888);
System.out.println(beer.notSoFinal);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
1
50
100
666
8888
Run Code Online (Sandbox Code Playgroud)
在“最后”现场已经被分配5个不同的 “最终”值(注意引号)。它可以一遍又一遍地被分配不同的值......
为什么?因为反射就像 Chuck Norris,如果它想改变一个初始化的 final 字段的值,它会改变。有人说他自己是将新值推入堆栈的人:
Code:
7: astore_1
11: aload_1
12: getfield
18: aload_1
19: bipush 50 //wait what
27: aload_1
28: getfield
34: aload_1
35: bipush 100 //come on...
43: aload_1
44: getfield
50: aload_1
51: sipush 666 //...you were supposed to be final...
60: aload_1
61: getfield
67: aload_1
68: sipush 8888 //ok i'm out whatever dude
77: aload_1
78: getfield
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
449558 次 |
| 最近记录: |