在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;
现在它是一个编译错误。期末考试是怎么进行的呢?
首先,在你的代码中初始化(即第一次赋值)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关键字。
“最终变量只能赋值一次”
*反思* -“哇哦,等等,拿着我的啤酒”。
在两种情况下冻结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);
}
}
输出:
1
50
100
666
8888
“final”字段已经被分配了5个不同的“final”值(注意引号)。它可以一直被赋予不同的值……
为什么?因为反射就像chucknorris,如果它想改变一个初始化的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
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
我只能回答你的问题,在这种情况下,你不能改变foo的参考值。你只需要在同一个引用中放入值,这就是为什么你可以在foo引用中添加值。这个问题发生在你不能很好地理解参考值和原始值之间的区别。引用值也是在堆内存中存储对象地址(即value)的值。
public static void main(String[] args)
{
Test t = new Test();
t.foo.add("bar"); // Modification-2
System.out.println("print - " + t.foo);
}
但是在这种情况下,您可以看到,如果尝试编写以下代码,将会出现编译时错误。
public static void main(String[] args)
{
Main main = new Main();
main.foo=new ArrayList<>();//Cannot assign a value to final variable 'foo'
System.out.println("print - " + main.foo);
}