LJ的Blog

学海无涯苦做舟

0%

第二话--再探多态

写在前面

Java回炉系列也有十多天没更了,虽然心里一直没怎么放下,但是奈何有心无力。项目成堆问题在那,还好中秋得空,出去逛了一下午心情大好~好了,正文开始

多态是啥,能吃吗?

学Java一般都会听说“面向对象三大特征”:封装、继承、多态。封装是将一个事物抽象成为一个类,这个类有自己的属性和方法,某些属性和功能的实现不会对外公开,只暴露一些可供获取数据的方法。继承很容易理解,就是一个类继承另一类,这个类被称为子类,而另一个自然就是父类了。当然在有的书上也将父类称为基类,将子类称为导出类,看你个人喜好了,在我这统一称为父、子类。好了,前面说了封装和继承,现在自然是要说多态了。多态应当是一种设计的思想,然后才体现在语言的具体实现。多态的核心思想是消除类型之间的耦合关系,可能你和我一样,刚看到这句话的时候有点懵逼,没关系举个小例子:
举个栗子

现在我有个数据集,因为增删操作做的比较多,行吗,了解数据结构的你一定想到了链表。那好就用链表来搞起:

1
LinkedList<Bean> list = new LinkedList<Bean>();

可是过了一段时间,你们老大给你说需求改了,现在是查询操作做的比较多。一向对于代码效率严格要求的你一定能想到链表查起来效率有点低,好啊,改成ArryList也算是能接受了。

1
ArrayList<Bean> list = new ArrayList<Bean>();

刚改完发现ide里一片红叉叉,好吧,原来是以前的方法也没用泛型参数,还得自己一个一个的去改掉。恩,改完没两天你们老大又来……

以上只是个带点玩笑性质的表述,在实际的操作中一般你都会这么写:

1
List<Bean> list = new ArrayList<Bean>();

恩,= 右边只要是个List接口的实现类就可以了,这就是解耦了。当你采用这种写法时好处也是显而易见的:涉及到这个数据集的方法,你只要传入一个List的形参就可以了,之后管你用啥实现(当然了,要符合多态的规则哦),这代码还是照常跑。

如果你是个上手Java没多久的新人,可能会有些惊讶于这种“接口实例化”的写法。但事实上只是Java多态的一种表现:** Java允许父类引用指向子类对象 ** 当然了,这句话里把父类换成接口,子类对象换成实现对象,也是可以的。

一些思考

写到这乐于思考的你一定能想到一些问题:上面说了在相应的方法里只要传入父类就行了,那也就是说那个方法并不知道他原来的类是啥,那么他在调用对象的方法时只会调用父类的方法了?直接上代码看看:
首先是父类

1
2
3
4
5
public class Parent {
public void print(){
System.out.println("I am Parent's method");
}
}

子类

1
2
3
4
5
public class Son extends Parent{
public void print(){
System.out.println("I am Son's method");
}
}

跑起来

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {
Parent p = new Son();
Hello(p);
}

private static void Hello(Parent p) {
p.print();
}
}

运行结果

结果

对于这个结果我只想问一声,凭啥啊?明明只有一个父类参数被传进去,他为毛能知道子类的方法啊?这是因为Java实现多态采用了一种被称作“动态绑定”或者“后期绑定”的牛x套路。编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,并加以调用。关于这个机制,现在暂时没有必要太去深究。经过以上一番探查,现在终于对Java的多态放了心,那么请开开心心的使用多态编写你的代码吧!

关于多态还有方法重载和方法覆盖,我的上一篇文章第一话–从头再来是有提到的,可以去看看。

接口与抽象类

待更新…有点累了,先休息了,反正这文写给自己看的,任性点,明天再更完。
//开更干活!
首先是语法,接口是interface,抽象是abstract。

平时在抽取基类的时候少不了用一下抽象类,你可以指定几个抽象方法,让你子类去实现这些抽象方法。当然了你的子类也可以是一个抽象类,那么可以不实现这些抽象方法。当然了,包含抽象方法的一定是抽象类, 但是不包含抽象方法的你也可以指定他是抽象类,可以有效的阻止这个类生成对象。

那么接口又是啥呢?接口是一个包含一个或者多个方法的东西,有的时候实现了这个接口的类就拥有了这个接口的“特性”,而在Java中接口有的时候也被用于回调。一般的来说接口是优于抽象类的,因为接口比抽象类更抽象,完全解除了类之间的耦合。但是这东西还是看实际情况的,有的时候接口满天飞感觉也不是很好。再者抽象类要比接口的定制性要好,毕竟抽象类完全可以当成一个普通的类来写,只不过在合适的地方加上合适的抽象方法,然后让子类去实现它。所以究竟采用哪个区实现你的多态,还是看你的需求和实现的。

接口很多时候会被用于“回调”,比如在Android中的MVP模式就少不了回调。对于回调的理解我有写过一篇简单的文章,感兴趣可以自己去看一下。对于回调,我认为在实质上回调就是想要在对的地方调对的方法,然后把对的数据、状态传递出去,让实现的类知道这个数据、状态然后加以处理。以上是我认为的回调的实质,之后不同的语言用什么方案解决,是函数指针还是接口,那都不是我所关心的东西了。

这一期暂时就到这了,本来还想加个内部类上来的,后来想想还是先缓缓。这类复习类的文,代码贴的比较少,大多是自己的一些总结性的话语……如果有人看到了,觉得不爽……只能说见谅了……