为什么java.time.YearMonth进行了最后一堂课? 基于值的类

问题描述

我计划编写一个extends java.time.YearMonth类,目的是通过一种使我能够流式传输YearMonth的{​​{1}}的方法来扩展LocalDate

YearMonth

好吧,当我发现public class ExtendedYearMonth extends YearMonth { public Stream<LocalDate> days() { LocalDate firstOfMonth = this.atDay(1); LocalDate lastOfMonth = firstOfMonth.with(TemporalAdjusters.lastDayOfMonth()); return firstOfMonth.datesUntil(lastOfMonth); } } YearMonth final class是不可扩展的时,该计划立即失败了。

我当然可以写一个像这样的课

final class

但这不是我想要的,因为它需要我实例化{{1}的public class ExtendedYearMonth { private YearMonth yearMonth; // parameterized constructor,getters and setters omitted for brevity public Stream<LocalDate> days() { LocalDate firstOfMonth = this.yearMonth.atDay(1); LocalDate lastOfMonth = firstOfMonth.with(TemporalAdjusters.lastDayOfMonth()); return firstOfMonth.datesUntil(lastOfMonth); } } YearMonth(主要目的是ExtendedYearMonth){{特定年份中特定月份的1}} s。

JavaDocs of YearMonth仅声明 stream,而不是为什么filter

LocalDate
...
YearMonth是一个不可变的日期时间对象,表示年份和月份的组合。
...

为什么将final设为final

或更准确地说:public final class YearMonthYearMonth有什么好处?
我无法想象任何原因...

我知道,要回答这一问题,必须了解可能在www某个地方公开的设计决策,但是,不幸的是,我没有这种见识,并且到目前为止,我还没有找到任何资料。

在Kotlin中,这无关紧要,因为您可以编写扩展功能而不必从该final继承。这是Kotlin的一个不错的功能,但是Java(暂时没有),我拒绝为此编写包装类。

我还可以问为什么final class YearMonth中没有这样的方法,或者当class YearMonth在Java 9中获得class时却没有添加这种方法,但这是第二个问题。单个帖子,通常会皱着眉头(和否决或不赞成投票),因此我稍后可能会在其他帖子中提出。

我当前的解决方案是执行上述代码所执行的YearMonth,但是我必须将实例传递给LocalDate方法,而不是直接使用该方法。这可以满足我的要求,但仍然不是我认为完美的解决方案。

解决方法

The documentation of YearMonth确实是这样说的,但间接是这样的:

这是value-based类;在==的实例上使用身份敏感的操作(包括引用相等性(YearMonth,身份哈希码或同步)可能会产生不可预知的结果,应避免使用。

value-based说:

基于值的类

某些类(例如java.util.Optionaljava.time.LocalDateTime)是基于值的。基于值的类的实例:

  • 是最终的且不可变的(尽管可能包含对可变对象的引用);
  • 具有equalshashCodetoString的实现,它们仅根据实例的状态而不是根据其标识或任何其他对象或变量的状态来计算;
  • 不使用身份敏感的操作,例如实例之间的引用相等(==),实例的身份哈希码或实例的固有锁上的同步;
  • 仅基于equals()被认为是相等的,而不是基于引用相等(==)被认为是相等的;
  • 没有可访问的构造函数,而是通过工厂方法实例化的,该方法不承诺返回实例的身份;
  • 当相等时,
  • 可自由替换的,这意味着在任何计算或方法调用中,根据x互换相等的两个实例yequals()不会产生明显的行为变化。

如果程序试图将两个引用区分为基于值的类的相等值,则可能会产生不可预测的结果,无论是直接通过引用相等还是间接通过调用同步,身份哈希,序列化或任何其他身份敏感的方法机制。在基于值的类的实例上使用这种对身份敏感的操作可能会产生不可预知的影响,应避免使用。

这里没有明确说明,但是子类化会与这些要点相抵触,因为这会导致实例表示相同值的可能性(就基类的状态而言),但是当实例不表示时,它们可以自由替换具有相同的类型。同样,即使当类不是final时,仅提供返回未指定身份实例的工厂方法的概念也将不允许子类,因为子类需要可访问的构造函数。

您可能会看到基于值的类等同于原始值;您不能将int子类化,因此也不能将YearMonth子类化,因为它仅表示特定值(只是强类型化),并且所有表示相同值的YearMonth实例无论是由不同的对象实例还是由单个实例表示,都应该是相同的。这样,使用Java的实际值类型就可以为将来开辟道路。

,

因为该类的实例保证是不可变的

如果允许子类,则无法保证。

来自YearMonth class documentation

* {@code YearMonth} is an immutable date-time object that represents the combination
* of a year and month. 

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...