代码检查(1)

这个系列,结合IDEA的Inspection和我自己的理解编写。

抽象问题

1. 把实例造型(cast)成具体的类型

这个问题的含义是,当得到一个实例时,把它cast到一个更加具体的类型使用。这个问题存在于以下场景:
  • 出于个人原因,比如只熟悉这个具体的类型、不动脑筋的编码。
这是新手常见的问题。比如可能程序员只熟悉ArrayList,并不知道其上的更加抽象的接口;或者个人感觉ArrayList更加“好用”。这是不应该出现的问题,有经验的程序员应该指导初学者,避免犯错。
  • 需要的方法不在更抽象的类型中,只在具体类型中才有定义。
这个问题更多的表示了设计层面考虑的不充分。比如组织本身的代码(非外来代码),接口定义的类型不能满足接口实现者的具体需求;返回值的类型过于泛化;本地变量(Local variable)定义的类型过于泛化等等。这些问题一般意味着在设计上考虑不周,导致了对象交互过程中的“对接不顺利”,这是设计上的不一致,需要对设计进行仔细评估。以下是几个这样的例子:

public Collection aMethod(Collection c) {
  List list = (List)c;
  Object o = list.get(0); // Collection中没有get方法。导致实现者必须cast。
  ...
}

public void test() {
  // 返回值必须cast才能使用更加具体的方法。
  List alist = (List)aMethod(Arrays.asList(new String[]{"1", "2"}));
  Object obj = alist.get(0);
  ...
}

public someMethod() {
  MyInterface mi = new MyImplementation();
  ...
  // 大部分时间调用MyInterface中的方法,但忽然发现有某个地方需要调用特定的非接口实现:
  int count = ((MyImplementation)mi).specialMethod();
  ...
}

最后这个例子,可能是方法的实现本身的问题,比如完全可以直接使用MyImplementation来定义变量mi;也可能是抽象问题,即没有把本来具有普遍性的方法放到接口中,而是放到了具体实现中。
  • 受环境约束,必须安全的使用造型。
上面谈到的设计问题,是指的组织内部的设计。在很多时候,需要使用外部的接口和实现,这些接口因为考虑了更加广泛的使用环境而采用了更加泛化的接口。这就需要顺应已经存在的设计来实现,不得不使用cast。但同时也要注意,在不得不cast的时候,一定要安全的使用cast,比如安全检查或者安全的类型转换,下面是示例:

public boolean equals(Object o) {
  if (o == null) return false;
  if (o instanceof MyClass) { // 安全检查!
    MyClass mc = (MyClass)o;
    // 调用MyClass中的特定方法。
    ...
}

public method() {
  Collection c = aMethodReturnsCollection();
  List list = new ArrayList(c); //安全的类型转换,把Collection转换成List。
  ...
}


Coding, issue, abstract, cast

你可能感兴趣的:(代码检查(1))