Java 如何在泛型中实现空对象模式?
我喜欢的想法,并迫使我使用它,直到它真的感觉正常和良好。目前我不知道如何在泛型类型中使用它。我知道有可能定义第二个泛型类型并传入类来构造默认对象,但对于这种模式来说,这感觉开销太大了。有好办法吗Java 如何在泛型中实现空对象模式?,java,generics,design-patterns,null,Java,Generics,Design Patterns,Null,我喜欢的想法,并迫使我使用它,直到它真的感觉正常和良好。目前我不知道如何在泛型类型中使用它。我知道有可能定义第二个泛型类型并传入类来构造默认对象,但对于这种模式来说,这感觉开销太大了。有好办法吗 public class GenericExample<T> { public static final GenericExample NULL = ???; private T attribute; public GenericExample(T attribu
public class GenericExample<T> {
public static final GenericExample NULL = ???;
private T attribute;
public GenericExample(T attribute) {
this.attribute = attribute;
}
}
public class HoldGeneric {
private GenericExample<String> name = GenericExample.NULL;
public initLater(String name) {
this.name = new GenericExample<String>(name);
}
}
公共类泛型示例{
公共静态最终GenericExample NULL=???;
私有T属性;
公共泛型示例(T属性){
this.attribute=属性;
}
}
公共类HoldGeneric{
private GenericExample name=GenericExample.NULL;
公共initLater(字符串名称){
this.name=新的GenericeExample(名称);
}
}
根据我对你问题的理解,我将同意以下观点
public class GenericExample<T> {
public static final GenericExample<?> NULL = new GenericExample<Object>(new Object()) {
public void print() {
}
};
private T attribute;
public GenericExample(T attribute) {
this.attribute = attribute;
}
public void print() {
System.out.print(attribute.toString());
}
@SuppressWarnings("unchecked")
public static <X> GenericExample<X> nil() {
return (GenericExample<X>) NULL;
}
}
public class Test {
private static GenericExample<String> name = GenericExample.nil();
public static void main(String[] args) {
String x = "blah";
name.print();
if (name == GenericExample.NULL) {
name = new GenericExample<String>(x);
}
name.print();
}
}
公共类泛型示例{
public static final GenericExample NULL=new GenericExample(new Object()){
公开作废印刷品(){
}
};
私有T属性;
公共泛型示例(T属性){
this.attribute=属性;
}
公开作废印刷品(){
System.out.print(attribute.toString());
}
@抑制警告(“未选中”)
公共静态泛型示例nil(){
返回(GenericExample)NULL;
}
}
公开课考试{
私有静态GenericExample name=GenericExample.nil();
公共静态void main(字符串[]args){
字符串x=“blah”;
name.print();
if(name==GenericExample.NULL){
名称=新的通用示例(x);
}
name.print();
}
}
如果不传入T类
就无法正确实现它。您所能做的最接近于滥用类型擦除的操作是:
class GenericExample<T>
{
private static final GenericExample<Object> NULL = new GenericExample<Object>();
public static <T> GenericExample<T> nil()
{
@SuppressWarnings("unchecked")
final GenericExample<T> withNarrowedType = (GenericExample<T>)NULL;
return withNarrowedType;
}
}
class GenericExample
{
private static final GenericExample NULL=new GenericExample();
公共静态泛型示例nil()
{
@抑制警告(“未选中”)
最后一个GenericExample,其窄类型=(GenericExample)为NULL;
返回窄类型;
}
}
但是,您必须接受GenericExample.nil()
将与GenericExample.nil()
相同,您可以按照JDK所做的操作,使用静态方法推断泛型类型并执行未经检查的强制转换
java.util.Collections
为空列表和集合实现空对象。在Java预泛型中,有一个公共静态字段
public static final List EMPTY_LIST = new EmptyList();
后仿制药:
现在有一些静态方法可以推断泛型类型并执行未经检查的强制转换,以便将其强制转换为正确的类型。类型实际上并不重要,因为集合是空的,但它使编译器感到高兴
@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
@SuppressWarnings(“未选中”)
公共静态最终列表emptyList(){
返回(列表)空_列表;
}
Guava有一个解决方案(),谢谢你的链接,虽然我看不到与我的具体问题之间的联系。我明白了,你也可以用Optional
来包装类成员,即private Optional属性
,但这确实使整个处理复杂化了。我认为这是实现空对象模式的最严格的方法,必须由顶层决定。这不会编译,哪里定义了GenericExample.nil()
?假设您实际上是指GenericExample.NULL
那么您将无法将GenericExample
分配给GenericExample
。复制/粘贴问题,我修复了我的答案。+1我将只传递属性的NULL
,而不是新对象()
,因为如果属性恰好被暴露(只需执行System.out.print(属性)
),则类型不安全。@PaulBellora,这一点很好,但很大程度上取决于用例。如果参数在构造函数中使用,可能它不能为null。@jan现在可以了,因为属性没有公开。但是如果有public T getAttribute()
,那么例如,调用方可以执行String str=GenericExamplenil().getAttribute()这将抛出一个ClassCastException
。您的想法是正确的,但是存在多个编译错误。对不起,我在这里直接键入了答案,而没有通过编译器运行它。如果你能说出你认为编译错误是什么,那就更有用了,而不是暗示它们的存在……明白了,我只是做些编辑(我不想惹人生气)。主要是,null
是一个关键字-如果你愿意,我会让你选择其他的。我不喜欢这个答案,因为它没有考虑到我的问题代码中没有空构造函数。类型安全的nil()
方法很好,但我的主要问题是缺少默认构造函数。第一个答案也使用了newobject()
,但注释指出使用null
。但是我想使用@Nonnull
并相信使用null
来实现空对象模式是矛盾的。这取决于如何使用属性。您可以使用一个方法来访问该属性,如果该属性为null,则抛出一个异常,就像Scala的Option.get一样。感谢您对JDK的引用。我不清楚如何在我的问题代码中实现一个新的EmptyGenericExample()
。当然可以使用null
,查看其他注释…我开始认为这应该是唯一可行的null对象,也就是说,否则应该使用Guava Optional。