我们在办公室进行讨论,无法理解哪种方法更好
我有一个类(SomeClass)和一些接收Serializable对象的方法。签名如下:
public void someMethod(Serializable serializableObject){
...
}
我需要从另一个类调用此方法,但我应该为它提供一些List作为事实参数。有两种不同的方法
private SomeClass someClass;
public void doSomething() {
List<String> al = new ArrayList<String>();
al.add("text");
someClass.someMethod((Serializable)al);
}
private SomeClass someClass;
public void doSomething() {
ArrayList<String> al = new ArrayList<String>();
al.add("text");
someClass.someMethod(al);
}
第一个例子的好处是它坚持java的最佳实践,它说:使用接口而不是具体实现参考类型和任何程序员,同时阅读该源将理解我们不需要特殊的行为ArrayList。并且我们需要它的唯一可行序列化行为是通过将其转换为Serializable接口来添加此行为。程序员可以简单地将List的当前实现更改为其他一些可序列化的实现,例如LinkedList,对此元素没有任何副作用,因为我们使用接口List作为它的引用类型。
第二个例子的好处是我们将ArrayList称为类,它不仅具有List行为,还具有Serializable行为。因此,如果有人查看此代码并尝试将ArrayList更改为List,则会收到编译时错误,这会减少程序员理解其中发生的事情的时间
更新:我们无法更改someMethod签名。它来自第三方公司,我们不仅将它用于Serializable Lists,还用于Strings,Integers和其他一些Serializable对象
答案 0 :(得分:2)
当您需要的只是接口提供的方法时,您应该使用接口。 (这是大多数情况)但是,如果您需要多个接口,可以使用泛型,但最简单的方法是使用具体类型。
答案 1 :(得分:1)
最好定义ArrayList
,因为它结合了两个接口 - List + Serializable
。你需要在一个地方同时使用它们。
这并不重要,但并不是说使用接口应该更严格地应用于返回类型,而不是严格地应用于局部变量。
答案 2 :(得分:1)
我会更改someMethod
的签名,以便它反映出该方法的调用者需要的内容:
public class SomeClass {
public <T extends List<? extends Serializable> & Serializable> void someMethod(T t) {
}
public static void main(String[] args) {
SomeClass test = new SomeClass();
test.someMethod(new ArrayList<String>()); //Works
test.someMethod(new ArrayList<Image>()); //Compile time error, Image is not Serializable
List<String> l = null;
test.someMethod(l); //Compile time error
}
}
someMethod
的签名现在表示您必须使用List
,即Serializable
,并包含Serializable
的元素来调用它p>
答案 3 :(得分:0)
1通常是正确的做法。但是在这种情况下,我的观点是弯曲并将其声明为ArrayList&lt;&gt;。这样可以避免转换并保证某人无法将List的实现更改为不可序列化的实现。
答案 4 :(得分:0)
你不能这样做(1),因为你不能随意改变List实现类型,这就是这样做的全部想法。您只能使用实现Serializable的List实现。所以你也可以在代码中表达它。
答案 5 :(得分:0)
在这种情况下,我只会使用List,而不用担心编译器无法保证您的对象是可序列化的(如果您在其他地方做了正确的事情,很可能会这样做。)
请注意,以下类型的方法(接受Serializable参数)提供了错误的安全感,因为编译器永远无法保证需要序列化的整个对象图实际上是可序列化的。
public void write(Serializable s);
考虑一个包含不可序列化对象的ArrayList(可序列化)。签名也可以是:
public void write(Object o);
然后你不必担心所有无关的演员。
另外请注意,尽管您无法更改所使用的API的签名,但您可以非常轻松地创建具有不同签名的包装API。