【问题标题】:If I need serializable should i use concrete List (e.g. ArrayList) or (Serializable)List?如果我需要可序列化,我应该使用具体的列表(例如 ArrayList)还是(可序列化)列表?
【发布时间】:2011-07-29 12:37:32
【问题描述】:

我们在办公室讨论,不知道哪种方法更好

我有一个类(SomeClass),它带有一些接收可序列化对象的方法。签名如下:

public void someMethod(Serializable serializableObject){
    ...
}

我需要从另一个类调用这个方法,但我应该为它提供一些 List 作为事实参数。有两种不同的方法

1。可序列化

private SomeClass someClass;

public void doSomething() {
    List<String> al = new ArrayList<String>();

    al.add("text");

    someClass.someMethod((Serializable)al);
}

2。数组列表

private SomeClass someClass;

public void doSomething() {
    ArrayList<String> al = new ArrayList<String>();

    al.add("text");

    someClass.someMethod(al);
}
  1. 第一个示例的好处是它遵循 java 的最佳实践,即:使用接口而不是具体实现引用类型,任何程序员在阅读该源代码时都会明白我们不需要特殊行为数组列表。我们唯一需要它的地方是可序列化行为,我们通过将其转换为可序列化接口来添加此行为。程序员可以简单地将当前的 List 实现更改为其他可序列化的实现,例如 LinkedList,而不会对这个元素产生任何副作用,因为我们使用接口 List 作为它的引用类型。

  2. 第二个例子的好处是我们将 ArrayList 称为类,它不仅具有 List 行为,而且还具有 Serializable 行为。因此,如果有人查看此代码并尝试将 ArrayList 更改为 List,他会收到一个编译时错误,这将减少程序员了解那里发生的事情的时间

更新:我们无法更改 someMethod 签名。它来自第三方公司,我们不仅将其用于可序列化列表,还用于字符串、整数和其他一些可序列化对象

【问题讨论】:

    标签: java


    【解决方案1】:

    当您只需要接口提供的方法时,您应该使用接口。 (这是大多数情况)但是,如果您需要多个接口,则可以使用泛型,但最简单的方法是使用具体类型。

    【讨论】:

      【解决方案2】:

      最好定义ArrayList,因为它结合了两个接口——List + Serializable。您需要将它们都放在一个地方。

      这无关紧要,但并不是说使用接口应该更严格地应用于返回类型,而更严格地应用于局部变量。

      【讨论】:

        【解决方案3】:

        我会更改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 的元素来调用它

        【讨论】:

        • 这可能是一个很好的解决方案,但我们没有机会更改SomeClass.someMethod() 签名,因为此方法由第三方库提供,它应该接受所有类型的 Serializable 对象,不仅是可序列化列表。我们的问题是:当我们必须将 List 的实例传递给这样的方法时,当我们遇到这种情况时,哪种方法会更好。
        • 啊,好的。看起来在那种情况下我没有完全理解你的问题:) 在那种情况下我会使用具体的类。
        • 这种方法的缺陷是调用者现在必须提供一个可序列化的列表(例如ArrayList),这意味着调用者的签名必须接受相同的类型(例如ArrayList)。这可能会在许多方法/类中级联,这会非常糟糕,因为它不必要地限制了可以在这些方法中使用的 List 的类型。
        【解决方案4】:

        在这种情况下,我只会使用 List,而不必担心编译器无法保证您的对象是可序列化的(如果您在其他地方做了正确的事情,它很可能无论如何都是可序列化的)。

        请注意,以下类型的方法(接受 Serializable 参数)提供了一种错误的安全感,因为编译器永远无法保证需要序列化的整个对象图实际上是可序列化的。

        public void write(Serializable s);
        

        考虑一个包含不可序列化对象的 ArrayList(可序列化)。签名也可以是:

        public void write(Object o);
        

        然后您就不必担心所有无关的演员表。

        还要考虑到,虽然您无法更改正在使用的 API 的签名,但您可以非常轻松地创建具有不同签名的包装 API。

        【讨论】:

          【解决方案5】:

          1 通常是正确的做法。但是在这种情况下,我的观点是弯曲并将其声明为 ArrayList。这避免了强制转换并保证有人无法将 List 的实现更改为不可序列化的实现。

          【讨论】:

            【解决方案6】:

            您不能这样做 (1),因为您不能随意更改 List 实现类型,这就是这样做的全部想法。您只能使用实现 Serializable 的 List 实现。所以你也可以在代码中表达出来。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-02-13
              • 2023-03-22
              • 1970-01-01
              • 2011-06-21
              • 2011-11-05
              • 2013-01-20
              • 1970-01-01
              • 2013-10-22
              相关资源
              最近更新 更多