当前位置: 首页 > 面试题库 >

为什么要用Java声明一个不变的类final?

鲍俊杰
2023-03-14
问题内容

我读到要使一个类在Java中不可变,我们应该执行以下操作:

  1. Do not provide any setters
  2. Mark all fields as private
  3. Make the class final标记为私有

为什么需要步骤3?我为什么要上课final呢?


问题答案:

如果你不标记该类final,那么我可能会突然使你看似不变的类真正变得可变。例如,考虑以下代码:

public class Immutable {
     private final int value;

     public Immutable(int value) {
         this.value = value;
     }

     public int getValue() {
         return value;
     }
}

现在,假设我执行以下操作:

public class Mutable extends Immutable {
     private int realValue;

     public Mutable(int value) {
         super(value);

         realValue = value;
     }

     public int getValue() {
         return realValue;
     }
     public void setValue(int newValue) {
         realValue = newValue;
     }

    public static void main(String[] arg){
        Mutable obj = new Mutable(4);
        Immutable immObj = (Immutable)obj;              
        System.out.println(immObj.getValue());
        obj.setValue(8);
        System.out.println(immObj.getValue());
    }
}

注意,在我的Mutable子类中,我重写了getValue读取我的子类中声明的新的可变字段的行为。结果,你的类(最初看起来是不可变的)实际上并不是不可变的。我可以Mutable在需要对象的任何地方传递该对象Immutable,如果该对象确实是不可变的,则可以对代码做非常不好的事情。标记基类final可以防止这种情况的发生。



 类似资料:
  • 我正在标准中寻找对这一事实的正式解释。我找到了3.9.1/9所说的,并试图用该部分给出解释。 第3.9.1/9节,N3797: void类型有一组空值。void类型是不完整的类型,无法完成。它用作不返回值的函数的返回类型。任何表达式都可以显式转换为cv void类型(5.4)。void类型的表达式只能用作表达式语句(6.2)、逗号表达式的操作数(5.18)以及?的第二个或第三个操作数:(5.16)

  • 问题内容: 我试图找到为什么不能将类创建为静态类的原因?喜欢: 问题答案: 在Java中,关键字通常将一个方法或字段标记为不存在,而不是每个类实例一次,而是一次。一个类一旦存在就已经存在,因此实际上,所有类都以这种方式是“静态的”,并且所有对象都是该类的实例。 确实对 内部 类具有含义,这是完全不同的:通常,内部类实例可以访问与其绑定的外部类实例的成员,但是如果内部类为,则它没有这样的引用并且可以

  • 我现在在这里读到,为了实现我的目标的不变性,我必须: 宣布我的所有字段为私有和最终 不定义设定者 如果没有setter,为什么我需要声明字段是最终的。java编译器不允许这样的事情: 如果我尝试使用反射,那么关键字不会阻止我更改引用。 我在这里找到了一个很好的解释,为什么整个类需要是,但没有解释为什么私有字段需要是final。 编辑:作为对GotoFinal评论的回复,这里有一个类展示了我如何通过

  • 问题内容: 在Java中,当声明一个字符串变量时,单词“ String”被大写,但是我遇到的其他任何类型都不是(例如,“ int”或“ double”)。为什么是这样?设计师是否只是一些奇怪的任意决定? 问题答案: 为什么在Java中将字符串变量的声明大写? 该类型的资本,因为它是一个 类 ,象,而不是一个原始类型像或(其他类型,你可能跑过)。 作为一个类,遵循Sun提出的Java命名约定。简而言

  • 问题内容: 我和一个朋友正在学习Java。今天,我们正在研究接口,并且讨论了如何使用接口。 我的朋友向我展示的示例代码包含以下内容: 其中 IVehicle 的是,公司在汽车和自行车两个类实现的接口。定义接受 IVehicle 作为参数的方法时,可以使用接口方法,并且在运行代码时,上述对象可以正常工作。但是,这在声明汽车和自行车时非常正常,就像通常这样: 因此,我的问题是-在声明和实例化 mode

  • 约书亚·布洛赫在高效的Java中写道: 请注意,非零长度数组总是可变的,因此类具有公共静态最终数组字段或返回此类字段的访问器是错误的。如果类具有这样的字段或访问器,客户端将能够修改数组的内容。这是安全漏洞的常见来源: 请注意,许多IDE生成的访问器会返回对私有数组字段的引用,这恰恰导致了这个问题。有两种方法可以解决这个问题。您可以将公共数组设为私有,并添加公共不可变列表: 或者,可以将数组设为私有