Java SonarQube 规则鱿鱼:S1948 - 如何使用可序列化列表而不绑定到例如 ArrayList

out*_*ind 4 java serialization arraylist sonarqube

SonarQube 规则鱿鱼:S1948要求可序列化类的所有字段都是可序列化的或瞬态的。另一条规则指出,应该使用接口而不是实现类型。

当我有一个

public class myClass implements Serializable
{
  List<String> names;
  ...
}
Run Code Online (Sandbox Code Playgroud)

那么names应该是 aList<String>而不是 eg ArrayList<String>。但规则 S1948 告诉我们这List是不可序列化的。

乍一看,解决方案:定义一个interface SerializableList- 可能像这样:

public interface SerializableList<E> extends List<E>, Serializable
{
}
Run Code Online (Sandbox Code Playgroud)

如果我们声明names是一个

  SerializableList<String> names;
Run Code Online (Sandbox Code Playgroud)

规则 S1948 中的警告已消失,但分配names = new ArrayList<String>();结果为Type mismatch: cannot convert from ArrayList<String> to SerializableList<String>.

两个问题:

  • 为什么我可以List<String> names = new ArrayList<String>();在没有警告的情况下声明,也不需要强制转换,但不能声明SerializableList<String> names = new ArrayList<String>();?我想知道,因为ArrayList<E> implements List<E>, Serializable, ...- 为什么它不是 a SerializableList
  • 如何names以 S1948 和其他规则都不会发出警告的方式声明,但我仍然可以自由使用任何类型的ListSerializable例如ArrayList,...)并且不需要显式强制转换。

感谢您的任何提示。

aga*_*rys 5

\n

为什么我可以List<String> names = new ArrayList<String>();在没有警告的情况下声明,也不需要强制转换,但不能声明SerializableList<String> names = new ArrayList<String>();?我想知道,因为ArrayList<E> implements List<E>, Serializable, ...- 为什么它不是一个SerializableList

\n
\n\n

您想要使用 Java 中不存在的结构/功能(“分组接口”)。现在您引入了一种SerializableList扩展其他类型的新类型:

\n\n
List    Serializable\n  \xe2\x86\x91          \xe2\x86\x91\nSerializableList\n
Run Code Online (Sandbox Code Playgroud)\n\n

ArrayList还扩展了 的两个父类型SerializableList

\n\n
List   Serializable\n  \xe2\x86\x91         \xe2\x86\x91\n   ArrayList\n
Run Code Online (Sandbox Code Playgroud)\n\n

但它们之间没有联系SerializableListArrayList。如果我们定义一个新类型:

\n\n
public class SerializableListImpl extends ArrayList implements SerializableList\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么我们有:

\n\n
   --------\xe2\x86\x92 List \xe2\x86\x90---------\n   |                       |\n   |  --\xe2\x86\x92 Serializable \xe2\x86\x90-- |\n   | |                   | |\nArrayList          SerializableList\n      \xe2\x86\x91                 \xe2\x86\x91\n      SerializableListImpl \n
Run Code Online (Sandbox Code Playgroud)\n\n

最后:

\n\n
List serializableList = new SerializableListImpl();\nSystem.out.println(serializableList instanceof List); // true\nSystem.out.println(serializableList instanceof Serializable); // true\nSystem.out.println(serializableList instanceof ArrayList); // true\nSystem.out.println(serializableList instanceof SerializableList); // true\n\nList arrayList = new ArrayList();\nSystem.out.println(arrayList instanceof List); // true\nSystem.out.println(arrayList instanceof Serializable); // true\nSystem.out.println(arrayList instanceof ArrayList); // true\nSystem.out.println(arrayList instanceof SerializableList); // false \xe2\x86\x90 not in the hierarchy\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

如何以 S1948 和其他规则都不会发出警告的方式声明名称,但我仍然可以自由使用任何类型的名称ListSerializable例如ArrayList,...)并且不需要显式强制转换。

\n
\n\n

你不能。并非每个List接口的实现都必须如此Serializable。任何人都可以定义一个新类型:

\n\n
public class MyList implements List {\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

分配给该names字段,然后:

\n\n
List myList = new MyList();\nSystem.out.println(serializableList instanceof List); // true\nSystem.out.println(serializableList instanceof Serializable); // false \xe2\x86\x90 not in the hierarchy\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如我在顶部所写的“分组界面”这样的功能:

\n\n
SerializableList == List<String>&&Serializable\n
Run Code Online (Sandbox Code Playgroud)\n\n

不存在,因此您必须将问题标记为Won\'t Fix

\n