当前位置: 首页 > 知识库问答 >
问题:

创建不可变类的最佳设计方法

商品
2023-03-14

我正在阅读有关在有效 Java 中创建不可变类时需要遵循的特定准则。

我知道在不可变类中,方法不应该被覆盖,否则被覆盖的方法可能会改变方法的行为。下面是java中解决这个问题的html" target="_blank">设计方法

> 我们可以将类标记为final,但是根据我的理解,它有一个缺点,就是使类不可扩展。

其次是使单个方法最终化,但我不能得到其他缺点,除了我们需要单独将每个方法标记为最终,以防止覆盖。

根据书本,更好的方法是使构造函数私有或包私有,并提供公共静态工厂方法来创建对象。

我的问题是:即使我们在类中包含私有构造函数或默认构造函数,它也不能在同一个包中扩展(在包私有构造函数的情况下,在其他包中),它也有与第一个相同的问题。它如何被认为是比以前的方法更好的方法?

共有2个答案

宓和同
2023-03-14

提供静态工厂方法,为您提供实现Flyweight模式的空间。

他们指出,您应该隐藏使用构造函数创建新对象的可能性,并且应该调用一个方法来检查“对象池”中是否存在具有相似状态的对象(充满等待重新使用的对象的映射)。不重复使用不可变对象是对内存的浪费;这就是鼓励String文字的原因,并且避免new String()(除非需要)。

class ImmutableType {
    private static final Map<Definition, ImmutableType> POOL = new HashMap<>();

    private final Definition definition;

    private ImmutableType(Definition def) {
         definition = def;
    }

    public static ImmutableType get(Definition def) {
         if(POOL.contains(def))
              return POOL.get(def);
        else {
              ImmutableType obj = new ImmutableType(def);
              POOL.put(def, obj);

              return obj;
        }
    }
}

定义存储不可变类型的状态。如果池中已存在具有相同定义的类型,请重新使用该类型。否则,请创建它,将其添加到池中,然后将其作为值返回。

至于将类<code>标记为final</code>的语句,不可变类型首先不应该是可扩展的(以避免可能的修改行为)。对于不可变类来说,将每个方法<code>标记为final</code>简直太疯狂了。

毋树
2023-03-14

不可变对象不应该是可扩展的。为什么?

因为扩展它将允许直接访问字段(如果它们受到保护,这将允许编写更改它们的方法),或者添加可能是可变的状态。

想象一下,我们编写了一个扩展 Double 的类 FlexiblyRoundableDouble,它有一个额外的字段舍入模式,让我们可以选择“舍入模式”。你可以为这个字段写一个资源库,现在你的对象是可变的。

你可以争辩说,如果所有方法都设置为 final,则无法更改对象的原始行为。唯一可以访问舍入模式字段的方法是在将对象分配给 Double 变量时无法多态使用的新方法。但是当一个类的契约说它是不可变的时,你会根据它做出决定。例如,如果您为具有 Double 字段的类编写 clone() 方法或复制构造函数,您知道您不需要深复制 Double 字段,因为它们不会改变其状态,因此可以在两个克隆之间安全地共享。

此外,您可以编写返回内部对象的方法,而不必担心调用者会更改该对象。如果对象是可变的,您必须对其进行“防御复制”。但是如果它是不可变的,返回对实际内部对象的引用是安全的。

但是,如果有人将一个< code > flexiblyrundabledouble 赋给了您的一个< code>Double字段,会发生什么情况呢?该对象是可变的。< code>clone()会假设它不是,它将在两个对象之间共享,甚至可能由一个方法返回。然后,调用方可以将其转换为< code > flexiblyrundabledouble ,更改该字段...并且它会影响使用该实例的其他对象。

因此,不可变对象应该是最终的。

所有这些都与构造函数问题无关。对象可以通过公共构造函数安全地保持不变(如< code>String 、< code>Double 、< code>Integer和其他标准Java不变量所示)。静态工厂方法是一种简单的方法,它利用了这样一个事实,即对象是不可变的,其他几个对象可以安全地保存对它的引用,从而创建更少的具有相同值的对象。

 类似资料:
  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 8年前关闭。 我一直在阅读有关使用PHP创建PDF文件的信息,并且想知道最简单的选择是什么。 创建PDF模板,将其打开并替换占位符文本-我应使用哪个功能打开现有PDF进行编辑

  • 问题内容: 我想在Django中创建多个用户。我想知道哪种方法最好。 还是应该使用.. 还是我必须创建自定义用户模型…这将对创建多种类型的用户非常有用… ?? 问题答案: Django没有多个用户-它只有一个用户,然后根据权限,用户可以执行不同的操作。 因此,首先-django中只有一种用户类型。如果你使用默认的身份验证框架,则从将此用户的模型称为。 如果要自定义django中的用户行为,可以执行

  • 本文向大家介绍ThreadPoolExecutor 创建方法最佳实践?相关面试题,主要包含被问及ThreadPoolExecutor 创建方法最佳实践?时的应答技巧和注意事项,需要的朋友参考一下 在《阿里巴巴 Java 开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。 为什么呢? 使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源开

  • 问题内容: 我有一百万行.txt格式的数据。格式很简单。对于每一行: 你知道我的意思。对于每个用户,它可能出现很多次,或者只出现一次(您永远不会知道)。我需要找出每个用户的所有值。因为用户可能会随机出现,所以我使用了Hashmap来做到这一点。即:HashMap(键:字符串,值:ArrayList)。但是要向arrayList添加数据,我必须不断使用HashMap get(key)来获取array

  • 在我的Java web应用程序中,我确实生成了一个报告,每个客户都检测到一个页面。 我已经创建了一个JasperReport,如果客户列表超过1个,我想连接生成的报告。 这是我的代码: 我想获取合并的PDF,但我找不到在ByteArrayOutputStream中导出JasperPrint列表的功能。 有什么建议吗?

  • 问题内容: 使类型代表一组字符串的最佳方法是什么? 我尝试了这个: 然后如何将它们用作? 问题答案: 我不知道您想做什么,但这是我实际上翻译示例代码的方式。 另外,您可以为创建一个getter方法。 你现在可以做