(我以为我曾经在一本书中读过这个,但现在我不知道在哪里可以找到它。如果这个问题提醒你一些你读过的材料,请发表参考文献!)
接口中原语的优点和缺点是什么?
换句话说,其中一个优于另一个,为什么?在某些情况下,也许一个人比另一个更好?
public interface Foo {
int getBar();
}
或
public interface Foo {
Integer getBar();
}
类似地:
public interface Boz {
void someOperation(int parameter);
}
或
public interface Boz {
void someOperation(Integer parameter);
}
显然,在非原始情况下必须处理null
s的问题,但有更深层次的关注吗?
答案 0 :(得分:11)
除非有特定原因要使用对象类型(例如,您需要null
),否则应使用原始类型来提高效率和简单性。使用对象类型可能会导致各种细微错误,例如错误地比较两个引用是否属于同一个对象,而不是具有相同的值。观察Java自己的库如何使用除容器之外的基本类型,它采用Object
s。
答案 1 :(得分:2)
我会说对于基元,通常没有理由使用基元包装器作为返回类型。一个论点就是内存要求。使用原始返回值,您只需要返回值的X字节与您拥有对象开销的包装器。您可以保存的唯一位置是Integer.valueOf(1)之类的缓存值,但是例如使用整数,这仅适用于值-128 - > 127。
虽然lexicore使用null作为特殊情况返回值确实产生了一个有效点,但是很多时候你可以使用primitve值执行相同的操作(例如API中的某些内容“当返回Integer.MIN_VALUE时返回结果不能被计算“。在许多情况下,除了布尔值之外,所有基元都是可行的。
也总是存在异常选项,因为有人可能认为接口应始终为所有可能的输入定义良好,并且导致返回值未确定的输入是异常情况的定义(以及这可能是IllegalArgumentException的好例子。
最终(非常不那么重要)解决方案是在接口上添加某种状态检查方法,可以在调用可能无法按预期执行的方法后对其进行测试:
boolean b = (interface).doFoo();
if((interface).wasError()){
//doFoo did not complete normally
}else{
//do something fooish
}
其中wasError可以以Thread的中断标志的样式自动清除(注意这种方法在多线程代码中容易出错)。
答案 2 :(得分:2)
除了极少数情况下原语很麻烦(我对CORBA有一些“好的”经验),我建议使用原语。
答案 3 :(得分:1)
我也在考虑这样的事情:
假设我们有这种类型:
public interface Foo {
int getID();
}
然后,无论出于何种原因,都会引入ID类型:
public interface Foo {
FooID getID();
}
现在,假设在更改之前编写了一些客户端,并且客户端包含如下代码:
if (A.getID() == B.getID()) {
someBehavior();
}
A
和B
为Foos
。
这个代码在更改后会被破坏,因为==
之间的原始相等比较(int
)在更改之前是正确的,现在错误地比较了参考值而不是调用{{ 1}}关于标识符。
如果equals(Object)
从一开始就产生了getID()
,那么正确的客户端代码就已经存在(好吧,正确的客户端代码可能就是这样。装箱转换会有已经应用Integer
以便也可以使用):
==
软件发展后,这仍然是正确的。
如果改变是“相反的”,换句话说,如果if (A.getID().equals(B.getID())) {
someBehavior();
}
最初产生了一些getID()
类型,那么如果将其更改为生成FooID
,则编译器会抱怨关于在基元上调用int
并且客户端代码已被更正。
似乎有一些非原始类型的“未来证明”的感觉。同意?不同意?
答案 4 :(得分:1)
使用原语。自动装箱/自动装箱会将int
转换为Integer
,依此类推。基元也分配在堆栈上,而不是堆。通过使用包装器类,您使用更多内存并产生更多开销;你为什么要那样做?
答案 5 :(得分:0)
是的,当您通过网络传输对象时,您可以看到的主要用途。 **使用序列化。 **