在Java中将对象声明为final

17

有人能解释一下以下代码的重要性吗?

class A
{
    int i = 10;

    public void setI(int b)
    {
        i = b;
    }

    public int getI()
    {
        return i;
    }
}

class Test
{    
    public static void main(String args[]) throws Throwable
    { 
        final A ob = new A();
        ob.setI(10);
        System.out.println(ob.getI());
    }
}

对象A被声明为final,但是我可以更改该对象实例变量的值,并检索更新后的值。那么将对象声明为final有什么意义呢?我知道声明基本数据类型为final可以使该变量为常量。

7个回答

37

如果一个对象被用 final 关键字 声明,那么该对象无法引用其他对象。

final 对象无法被重新分配。但是,如果 final 对象是可变的,你可以更改它的内部内容。因此以下代码是有效的:

  final A ob = new A();
  ob.setI(6)

但这样不行:

  final A ob = new A();
  ob = new A();

那么基本上这不允许分配一个对象的新实例?其他像 Image img = loadImage("img.png"); 这样的东西呢?你能做到:img = loadImage("image.png"); 吗?还是说这是非法的? - AMDG
@LinkTheProgrammer 你觉得呢? - NimChimpsky

12

如果你将任何变量标记为final,意味着你不想改变它所包含的值。对于原始类型,在变量中表示的值就是实际的值。对于对象类型,在内存中的值是指向对象的引用而不是实际的对象。

例如,你有:

final int x = 7;
final Object y = new Object();

你可以这样想象数据在内存中的表示方式:

+----------+----------+
|  block   |  value   |
+----------+----------+
|  1001    |    7     |
|  1002    |  2110    |
+----------+----------+

为了讨论方便,我们先不考虑Java实际上是如何管理内存的(因为我对此也不太了解)。所以,在上面的例子中,块1001由变量x表示,块1002由y表示。它们都是final变量,这意味着它们所代表的值是不可更改的。在x的情况下,它的值是7,这是实际值,但在y的情况下,2110只是指向另一个内存位置的引用。它们都不能改变,但原始类型变量之所以成为常量,是因为它们代表实际值。但事实上,对于对象类型变量来说,你也可以这样说,只不过它们代表的常量是引用而已。所以,final关键字在这方面基本上是一致的。

所以,对于final变量,如果它们是原始类型,它们将始终表示您设置它们的任何特定值。如果它们是对象/引用类型,则它们将始终指向您指向的任何对象(无论对象的可变性如何)。


4
这意味着以下内容是不可能的:
final A ob = new A();
ob = new A(); // This is not possible

变量 ob 也将引用首次分配给它的类 A 的实例。这就是在此情况下 final 关键字的含义。这意味着您可以修改 ob 的属性,因为它像 A 的任何其他实例一样是普通对象。


请问您能否给我一些实时情境,可以说明在哪些对象中使用final关键字? - Pearl

3
如果一个对象被声明为final,则您可以像平常一样调用任何进行内部更改的方法,但是您无法重新分配引用以指向不同的对象。试着这样做:
final A ob = new A();
ob = new A();

请注意,代码将无法编译。

将其视为常量引用。


2

在对象的情况下,引用的值是指向对象的地址。因此,ob的值将是指向new A();创建的对象的地址,这将是最终的,您将无法更改其值。也就是说,您不能将一个新对象分配给这个引用。

您不能以这种方式编写代码。

final A ob = new A();

ob= new A(); // not allowed

1
Java中不会有任何常量(final)对象。对象是在堆内存区域中创建的,我们可以随时修改对象。
Java中只有常量(final)引用:这意味着您无法修改引用并将其重新分配给任何其他对象,因为它是常量,并且在整个final引用期间仅引用被分配的一个对象,该对象在声明时被分配。

因此:

 final A objectA = new A();
 objectA.setI(6);  

这是有效的,因为我们只改变了对象内容,而没有改变引用。

但是:

   final A objectA = new A();
   objectA = new A();  

因为您试图修改引用,所以无效。


1
在Java中,与C++不同的是,所有对象都是指针,因此一个final对象可以被改变,只是它不能指向任何新的位置,也就是说,你不能把它放在赋值运算符的左边。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接