ric*_*kyk -1 java oop access-modifiers immutability
如何创建不可变的星球以便名称不会改变?我很挣扎,因为我认为这是具有可变对象的不可变项目。如果我错了请纠正我。
每次我更改输出中的名称也会更改。我错过了什么吗?
我尝试将所有字段设为私有和最终(不在本例中),但我认为我缺少一些工作代码。
我知道 java.util.Date 已被弃用,但这只是示例。
import java.util.Date;
public final class Planet {
String name;
private final Date discoveryDate;
public Planet (String name, Date discoveryDate) {
this.name = name;
this.discoveryDate = new Date(discoveryDate.getTime());
}
public String getName()
return name;
}
public Date getDiscoveryDate() {
return new Date(discoveryDate.getTime());
}
public static void main(String [] args) {
Planet Earth = new Planet("Earth Planet", new Date(2020,01,16,17,28));
System.out.println("Earth");
System.out.println("------------------------------------");
System.out.println("Earth.getName: " + Earth.getName());
System.out.println("Earth.getDiscoveryDate: " + Earth.getDiscoveryDate());
}
}
Run Code Online (Sandbox Code Playgroud)
任何一个:
\nrecord
在 Java 16 及更高版本中进行如下操作:public record Planet( String name , LocalDate discovered ) {}
final
和private
。只需使用Java 16 中的新记录功能(在 Java 15 中预览)。
\n将您的类定义为 a record
,其主要工作是透明且不可变地携带数据。编译器隐式创建一个构造函数、getter、hashCode
&equals
和toString
。
请注意,记录中隐式定义的 getter 方法不以JavaBeans风格的措辞开头get\xe2\x80\xa6
。getter 方法只是类名后面括号中定义的成员字段的名称。
当然,如果您的 getter 方法提供对本身可变的对象的访问,则包含在记录中并不会阻止调用程序员改变所包含的对象。请注意,在接下来的示例类中,String
和LocalDate
类本身在设计上都是不可变的。因此,所包含对象的可变性在这里不是问题。
package org.example;\n\nimport java.time.LocalDate;\n\npublic record Planet( String name , LocalDate discovered )\n{\n}\n
Run Code Online (Sandbox Code Playgroud)\n使用该记录。
\nPlanet Earth = new Planet( "Earth" , LocalDate.of( 2020 , 1 , 16 ) );\n\nSystem.out.println( "Earth" );\nSystem.out.println( "------------------------------------" );\nSystem.out.println( "Earth.name: " + Earth.name() );\nSystem.out.println( "Earth.discovered: " + Earth.discovered() );\n
Run Code Online (Sandbox Code Playgroud)\n运行时。
\nEarth\n------------------------------------\nEarth.name: Earth\nEarth.discovered: 2020-01-16\n
Run Code Online (Sandbox Code Playgroud)\n如果没有记录功能,要确保类不可变,您应该:
\nfinal
。这意味着构造函数完成后不能为该字段分配不同的对象。private
。这意味着其他类的对象将无法直接访问读取或更改这些字段。get\xe2\x80\xa6
或命名。is\xe2\x80\xa6
您还应该提供hashCode
、equals
和的适当覆盖实现toString
。您的IDE将帮助生成这些的源代码。
package org.example;\n\nimport java.time.LocalDate;\nimport java.util.Objects;\n\npublic class Plan\xc3\xa8te\n{\n // Member fields\n final String name;\n final LocalDate discovered;\n\n // Constructors\n public Plan\xc3\xa8te ( String name , LocalDate discovered )\n {\n Objects.requireNonNull( name );\n Objects.requireNonNull( discovered );\n this.name = name;\n this.discovered = discovered;\n }\n\n // Getters (read-only immutable class, no setters)\n public String getName ( ) { return this.name; }\n\n public LocalDate getDiscovered ( ) { return this.discovered; }\n\n // Object class overrides\n @Override\n public boolean equals ( Object o )\n {\n if ( this == o ) return true;\n if ( o == null || getClass() != o.getClass() ) return false;\n Plan\xc3\xa8te plan\xc3\xa8te = ( Plan\xc3\xa8te ) o;\n return getName().equals( plan\xc3\xa8te.getName() ) && getDiscovered().equals( plan\xc3\xa8te.getDiscovered() );\n }\n\n @Override\n public int hashCode ( )\n {\n return Objects.hash( getName() , getDiscovered() );\n }\n\n @Override\n public String toString ( )\n {\n return "Plan\xc3\xa8te{ " +\n "name=\'" + name + \'\\\'\' +\n " | discovered=" + discovered +\n " }";\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n使用那个类。
\nPlan\xc3\xa8te Earth = new Plan\xc3\xa8te( "Earth" , LocalDate.of( 2020 , 1 , 16 ) );\n\nSystem.out.println( "Earth" );\nSystem.out.println( "------------------------------------" );\nSystem.out.println( "Earth.getName: " + Earth.getName() );\nSystem.out.println( "Earth.getDiscoveryDate: " + Earth.getDiscovered() );\n
Run Code Online (Sandbox Code Playgroud)\n不要以 开头十进制整数文字0
。前导零使数字成为八进制而不是十进制。所以你的代码传递2020,01,16
应该是2020,1,16
.
切勿使用该类Date
,也不要使用Calendar
或SimpleDateFormat
。这些可怕的类现在已经成为遗留物,几年前被JSR 310 中定义的现代java.timejava.time.LocalDate
类所取代。在上面的代码中,我们用来表示仅日期值,没有日期时间和时区。