撼地神牛
- 积分
- 390
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2013-1-15
- 最后登录
- 1970-1-1
|
声明类就是变量声明时给予它的类型。
Animal doggy = new Dog();
doggy虽然是Dog实现的,但是它的声明类型是Animal。从这之后我们只把它看作为Animal,忘记它其实是个Dog。
为什么声明类要尽量选抽象?首先,我们使用其它method时,method argument一般是最抽象的。比如一个打印某List中所有元素的method:
void printList(List<...> list) ;
它只管你给它某种List就可以打印出其中所有的元素。如果定义成void printList(ArrayList<...> list) 这就不妥,因为这就排除了其它所有种类的List,但是打印所有的元素又不需要管它具体是LinkedList还是ArrayList。
同理,如果你在写一个method接受method arguments,在选类型时最好选最抽象并能完成任务的类。你如果在写printList这个method,如果之中不需要用某种特别的List的操作,当然你就不应该限制别人放List进来应该是LinkedList还是ArrayList。
其实尽量选择抽象的声明类也是约束自己的一个方法。解决问题时尽量先用抽象的方法去解决,实在不行再用具体操作。比如Map:
Map<...> map = new TreeMap<>();
这一行之后的代码都会认定map为抽象的Map,很可能只需要用Map的基本操作。如果后来我们想把它的具体实现改成HashMap(比如要更efficient),只要把这一行的TreeMap改成HashMap就行了,并且这保证代码正确因为至少在Map支持的操作上TreeMap和HashMap的外表动作相统一。如果你声明时就用了
TreeMap<...> map = new TreeMap<>();
那之后代码每一次提到TreeMap都要改成HashMap,而且不能确定这改的会不会有bug因为你可能后面有了TreeMap某个特别操作或特征在HashMap上不适用。
abstract class和interface最大的不同是抽象思维上的区分。支持一个interface代表某类拥有这个接口所有的抽象操作,但是继承一个abstract class意思是某类的本质归纳应从这个abstract class来延伸。
这是什么意思?假如我有个接口“会跳”:
interface 会跳 {
void 跳 ();
}
那什么东西会跳?人会,动物也会,机器人也会,但是除了支持这个操作以外可能这些东西都没太大相似的地方。这就是为什么在Java中典型的接口Comparable,Cloneable,Iterable都是以抽象操作为命名的。除了支持这个操作以外对子类没有任何要求。
反之,继承abstract class对于一个子类是对他本质的归纳。Dog继承Animal,因为它本质更抽象一级就应理解为动物。虽然它也继承interface 会跳,它不应本质理解为“会跳的东西”。所以abstract class所覆盖的一般是某名词,而interface所覆盖的一般是某组动词。
最后你可能会问List,Map,Set是名词啊,为什么Java中它们都是interface。这是因为List应理解为“支持列表诸操作的某数据结构”,而不是说某类本质就是以列表实现的。如果后者成立,在Java中它们会继承AbstractList这个abstract class来代表他们本质是列表。这也是为什么我们可以这样写:
Queue<...> q = new LinkedList<...>();
LinkedList也支持Queue的所有操作,所以我们就把它当Queue来使,即使它本质是以列表来实现的。
|
|