面向对象编程(Object Oriented Programming,OOP)是当前最主流的编程范式之一,Java是一门纯面向对象的编程语言。我们常说C++是一门面向对象的编程语言,C++是C语言的一个超集,它在C语言的基础上突破性的添加了类的概念,增加了面向对象的特点。
首先,C++是一门非常强大的语言,它几乎可以做到其他编程语言所能做到的所有事情,但是由于其繁杂的语法等等原因导致C++的学习成本过高,在这样地背景下,Java逐渐取代并且成为了一门主流的编程语言。而理解面向对象,首先要理解基本的类与对象的概念。
一、类与对象
众所周知,类型是人类意识形态进化过程中重要的一环,分类思想最早有亚里斯多德提出。所谓分类,即将事物通过某些区别将具有相同特点的事物划分为一类,换句话说,类型,即是具有相同特点的事物。OOP面向对象的核心之一就是类,我们需要设计一个类(这里使用类型可能更好理解一些),用以概括具有相同特点的事物,而对象就是具体的某一个满足这些特点的东西。
我们列举一个example,水壶是一个类型,水壶有都有各自的颜色。设计一个水壶的类,那么红色的水壶就是这个类的一个对象。 笔者认为,面向对象思想借鉴了中最重要的一点就是借鉴了“类型”的概念。
我们在分析设计类的时候,总是思考该类的属性以及行为,来设计该类的成员变量和成员方法.并且通过“行为”的设计来模拟现实世界事物的关系。比如,Person有一个touch()方法。它的方法签名如下:
public void touch(LiftButton liftButton);
这个方法很好的模拟了“人按下电梯键”这个行为。通过使用这种方法以及Java简练的语法极大地简化了开发的难度。
值得一提的是,我们通常在对象后面加“.”用以访问对象的成员。如:
Person p = new Person();
p.age;
Example code:
class Person { int age; double height; double weight; public void touch(LiftButton liftButton) { //... } }
二、深入OOP---继承和多态:
在理解的基本的类与对象之后,先不需要急着明白继承是什么,接着按照“分类”理解,请看下图:
初见该图,貌不惊人,但是如果使用OOP设计跑车类呢?
换而言之,它具有作为交通工具,作为一辆车的所有特点?具有所有的属性和行为?答案显而易见。思考一下,作为一辆跑车,是否首先是一辆交通工具,然后是否一定是一辆车?如果我们将“车”划分为“跑车”和“卡车”等等,将更加抽象的事物划分为更具体的事物,我们就称他们为父类和子类。
我们将这句话中的属性和行为用成员变量和成员方法置换,就成了“子类具有父类所有的成员变量和成员方法”。
这就是所谓“继承”,子类继承父类所有的属性和行为。在Java中,用extends关键字表示。
Example code:
class Animal { private int age; Animal(int age) { this.age = age; } public void shout() { System.out.println("I'm shout"); } } class Dog extends Animal { Dog(int age) { super(age); } }
而“多态”建立在“继承”的基础上,多态,字面源于希腊文字,polymorphism,它所有的意思可以归结为:父类类型的对象可以引用子类类型的对象(常见的两种方式),可以参考实例代码。
那怎么理解多态呢?
每个圆都是一个几何对象,但并非每个几何对象都是圆。
每个子类的对象必定是其父类的对象,因此给子类对象可以是父类声明。
class Demo1{ //父类 } class Demo2 extends Demo1 { //子类 } public class Demo{ public static void main(String[] args){ Demo1 d1 = new Demo2();//第一种方式 Demo2 d2 = new Demo2(); //第二种方式 test(d2); //往test方法传一个Demo2对象 } public static void test(Demo1 d){ //由于Demo1是Demo2的父类,因此在接收参数时可以接收Demo2类的对象 } }
而多态还有一个必须要get的点-----动态绑定机制!
若一个对象使用父类类型声明,只能调用父类中存在的方法,若子类的方法覆盖了父类的方法,则调用子类中的方法。直接上代码:
class Person{ public void say(){ System.out.println(“I’m a person”); } } class Boy extends Person { public void say(){ System.out.println(“I’m a Boy”); } public void do(){ } } public class Demo{ public static void main(String[] args){ Person p = new Boy(); p.say(); //调用的是Boy类的say()方法。 p.do();//编译错误 } }
首先要明确一个定义:当子类中存在与父类的方法方法签名相同的方法时,父类的方法将被隐藏,这一过程称为覆盖。
若一个对象使用父类类型声明,调用该对象的方法时,若存在子类的方法覆盖父类的方法,将调用子类的方法。
而且必须需要注意,由于使用的是父类的声明,因此只能调用父类中有声明过的方法,如图中代码p.do();do()只存在于子类中,因此会出现编译错误。
三、简化的多继承:单继承+接口(interface)
曾有一位朋友戏称多继承“100年用不到1次”,大多数情况下,使用单继承即可解决实际问题。因此笔者认为Java单继承+接口是更加实用的解决方式。学习接口之前,我们有必要了解一下何为“抽象类”。
抽象类代表拥有抽象方法的类,而抽象方法指的就是”在子类中必须要实现的方法”。使用关键字abstract实现。抽象类的存在有什么作用?
For example,每个几何对象都有自己的面积,那么必有一个成员方法,该方法可以返回它面积。但是每一种几何图形的计算方法都不一样,这时我们必须要有一个抽象方法,强制该类的子类实现该方法,同时由于该方法无法确定,几何图形类不得实例化。
abstract class GeometricObject { public abstract double getArea(); } class Circle extends GeometricObject { private double r; Circle(int r){ this.r = r; } public double getArea() { return Math.PI * r * r; } } public class Demo { public static void main(String[] args) { GeometricObject c = new Circle(3); c.getArea();//基于动态绑定,返回9*PI } }
接口与抽象类十分类似,这是从两个方面上来说的。
1.接口中的方法都为抽象方法,实现该接口的类必须实现接口中包含的方法。
2.接口定义了一种新的类型,且不得实例化。
作为多继承的替代品,接口所代表的实际意义是用来定义具有某些特定行为的类型。
它定义了一种新类型!正是因为它定义了一种新的类型,才能与继承配合达到多继承的效果!
观察下以下代码:
interface Sortable{ void sort(); } class Stack implements Sortable{ //,,, public void sort() { //... } } class Queue implements Sortable { //,,, public void sort() { //... } } public class Algorithms { public static void main(String[] args) { Sortable s1 = new Stack(); Sortable s2 = new Queue(); sort(s1); sort(s2); } public static void sort(Sortable s) { s.sort(); } }
由于Stack和Queue类都实现了Sortable接口,因此Sortable是他们的父类型,可以使用Sortable声明,并且可以传入类型为Sortable的方法。值得一提的是,就像前面动态绑定机制提到的,由于声明类型为Sortable,只能调用Sortable声明过的方法。
java自带的库中存在着一种接口,这种接口不存在任何方法,我们称之为标记接口,比如Cloneable接口,有些朋友会有些奇怪,既然没有方法,那么有什么作用?
但是我们不要忘了接口定义了一种新的类型,只要实现了某个接口,我们就可以判断出它是否是该接口类型!只需使用instanceof关键字即可判断!
比如前面的代码可以改一下:
interface Sortable{ void sort(); } class Stack implements Sortable{ //,,, public void sort() { //... } } class Queue implements Sortable { //,,, public void sort() { //... } } public class Algorithms { public static void main(String[] args) { Sortable s1 = new Stack(); Sortable s2 = new Queue(); sort(s1); sort(s2); } public static void sort(Object o) { if(o instanceof Sortable) { Sortable s = (Sortable)o; s.sort(); } } }
PS:博客刚开,心情有点小激动,估计每星期会有1-2篇博客。有什么错误欢迎指正。