为什么java.time.YearMonth会成为最后一堂课?

为什么java.time.YearMonth会成为最后一堂课?,java,class,java-stream,final,java-time,Java,Class,Java Stream,Final,Java Time,我计划编写一个扩展java.time.YearMonth的类,目的是用一种方法扩展YearMonth,使我能够流式处理YearMonth的LocalDate: public class ExtendedYearMonth extends YearMonth { public Stream<LocalDate> days() { LocalDate firstOfMonth = this.atDay(1); LocalDate lastOfMo

我计划编写一个
扩展java.time.YearMonth
的类,目的是用一种方法扩展
YearMonth
,使我能够流式处理
YearMonth
LocalDate

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
和一个
ExtendedYearMonth
,只为了
(和
过滤器
,主要目的)特定年份中特定月份的
LocalDate

公正的声明是它是
最终的
,但不是为什么它是最终的:

public final class YearMonth


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

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

我知道,要回答这个问题,需要对www中可能公开的设计决策有深入的了解,但是,不幸的是,我没有这样的了解,到目前为止我还没有找到来源

在Kotlin中,这并不重要,因为可以编写扩展函数,而不必从
类继承。这是Kotlin的一个很好的特性,但是Java目前还没有,我拒绝为此编写包装器类

我还可以问,为什么这样一个方法在Java 9中的
YearMonth
中不可用,或者在
LocalDate
got
datesUntil
时没有添加,但这将是一篇文章中的第二个问题,通常会被人皱眉(并投反对票或接近票),所以我可能会在稍后的另一篇文章中问这个问题


我当前的解决方案是一个
公共静态流daysOf(YearMonth YearMonth)
,它执行上述代码所做的操作,但我必须将实例传递给
静态方法,而不是直接使用它的方法。这是为我的要求而工作的,但它仍然不是我认为的近乎完美的解决方案。

,因为类的实例被保证为<强>不可变< /强>

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

从:

确实如此,但间接地说:

这是一门课;在
YearMonth
实例上使用标识敏感操作(包括引用相等(
=
)、标识哈希代码或同步)可能会产生不可预测的结果,应避免

鉴于:

基于值的类 有些类,例如
java.util.Optional
java.time.LocalDateTime
,是基于值的。基于值的类的实例:

  • 是最终的和不可变的(尽管可能包含对可变对象的引用)
  • 具有仅根据实例状态而非其标识或任何其他对象或变量的状态计算的
    equals
    hashCode
    toString
    的实现
  • 不要使用对身份敏感的操作,例如实例之间的引用相等(
    =
    ),实例的身份哈希代码,或实例的内在锁上的同步
  • 仅基于
    equals()
    ,而不是基于参考等式(
    ==
    )认为相等
  • 没有可访问的构造函数,而是通过工厂方法进行实例化,工厂方法不承诺返回实例的标识
  • 当相等时可以自由替换,这意味着在任何计算或方法调用中交换根据
    equals()
    相等的任何两个实例
    x
    y
如果程序试图区分对基于值的类的相等值的两个引用,无论是直接通过引用相等还是间接通过调用同步、标识散列、序列化或任何其他标识敏感机制,都可能产生不可预测的结果。在基于值的类的实例上使用此类标识敏感操作可能会产生不可预测的影响,应避免使用

这里没有明确说明,但子类化会与这些观点相矛盾,因为它可能会导致实例表示相同的值(根据基类的状态),但当它们不具有相同的类型时,不能自由替换。此外,即使类不是
final
,仅提供返回未指定标识实例的工厂方法的概念也不允许使用子类,因为子类需要可访问的构造函数


您可能会将基于值的类视为与基元值等价的类;不能将
int
子类化,因此不能将
YearMonth
子类化,因为它只表示一个特定的值(仅强类型),并且表示相同值的所有
YearMonth
实例都应该是相同的,无论是由不同的对象实例还是单个实例表示。这为Java中真正的值类型的未来开辟了道路。

就这样?为什么保证了这一点?文档还指出实例是线程安全的。不可变对象本质上是线程安全的。顺便说一句,Joshua Bloch在“第15项:最小化可变性”中的有效Java中提供了对不可变类优点的良好覆盖。它应该是不可变的。非final类不能保证其实例是不可变的。我认为这个问题可以概括为“您可以将
days()
移动到
YearMonths
非实例化实用程序类,它是
final
并具有
private
构造函数。关于java.time的所有类(现代Java日期和时间API)是v
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);
    }
}
* {@code YearMonth} is an immutable date-time object that represents the combination
* of a year and month.