javaSE ---OOP总结

面向对象编程(Object Oriented Programming,OOP)是当前最主流的编程范式之一,Java是一门纯面向对象的编程语言。我们常说C++是一门面向对象的编程语言,C++是C语言的一个超集,它在C语言的基础上突破性的添加了类的概念,增加了面向对象的特点。

         首先,C++是一门非常强大的语言,它几乎可以做到其他编程语言所能做到的所有事情,但是由于其繁杂的语法等等原因导致C++的学习成本过高,在这样地背景下,Java逐渐取代并且成为了一门主流的编程语言。而理解面向对象,首先要理解基本的类与对象的概念。

一、类与对象

    众所周知,类型是人类意识形态进化过程中重要的一环,分类思想最早有亚里斯多德提出。所谓分类,即将事物通过某些区别将具有相同特点的事物划分为一类,换句话说,类型,即是具有相同特点的事物。OOP面向对象的核心之一就是类,我们需要设计一个类(这里使用类型可能更好理解一些),用以概括具有相同特点的事物,而对象就是具体的某一个满足这些特点的东西。

    我们列举一个example,水壶是一个类型,水壶有都有各自的颜色。设计一个水壶的类,那么红色的水壶就是这个类的一个对象。 笔者认为,面向对象思想借鉴了中最重要的一点就是借鉴了“类型”的概念。

image

我们在分析设计类的时候,总是思考该类的属性以及行为,来设计该类的成员变量和成员方法.并且通过“行为”的设计来模拟现实世界事物的关系。比如,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---继承和多态:

在理解的基本的类与对象之后,先不需要急着明白继承是什么,接着按照“分类”理解,请看下图:

image

初见该图,貌不惊人,但是如果使用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篇博客。有什么错误欢迎指正。

posted @ 2015-11-24 16:45  bug你奏凯  阅读(394)  评论(0编辑  收藏  举报