还不清楚怎样面向对象?

二十二画程序员

本文主要介绍了面向对象的基本思想和三大特征。

一、引入例子

创建一个Dog小狗类

/**
 * 小狗类
 */
public class Dog {
    String name;
    Integer age;
    Integer legs;

    public void say(String name) {
        System.out.println("我是"+ name +",汪汪汪");
    }
    
    public void watchDoor() {
       System.out.println("赶走陌生人");
    }
}

小狗可以有名字、年龄、腿数这些属性,还可以有「叫」这个行为,这些是小狗共有的属性和行为。

从上面代码可以看出:类定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。

当我们和小狗玩耍时,并不是在和「一类狗」玩耍,而是在和「具体的狗」玩耍,比如说哮天犬。

所以只有Dog类是不能和狗玩耍的,我们需要「一只具体的狗」,这只具体的狗从何而来?在现实生活中,我们可能需要花钱去宠物店买一只具体的狗。在编程世界中,我们同样需要花「钱」去「买」,不过这里的「钱」指的是「内存」,「买」指的是「new」,「具体的狗」指的是实例化出的「对象」。

/**
 * 实例化一只小狗,并和它玩
 */
public class Play {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "哮天犬";
        dog.age = 2;
        dog.legs = 4;
        dog.say(dog.name);
        dog.watchDoor();
    }
}

运行之,输出
    我是哮天犬,汪汪汪
    赶走陌生人

现在我们花钱(内存)买(new)了一只两岁的、有四条腿的、名叫哮天犬的小狗(对象),它有具体的属性和行为,是一只「活生生的狗。

从上面的代码看出:

  • 对象是类的实例
  • 系统给对象分配内存空间,而不会给类分配内存空间。这很好理解,类是抽象的,系统不可能给抽象的东西分配空间,而对象则是具体的。

二、面向对象的三大特点

通过上面的例子,简单介绍了一下类和对象的概念和二者之间的联系。下面我们在来介绍一下面向对象的三大特点。

1. 封装

现在我们分析一下上面的小狗例子存在的问题。

  • 对于Dog类来说,该类的属性和方法全部暴露在外,即从类外面看是可见的。这样一来,小狗就没了隐私权。
  • 我们在实例化小狗时,是直接给它的属性赋值的,这就意味着可以在类外我们可以随意修改小狗的属性。这就意味着我们买小狗的时候可以随意修改它的名字、年龄甚至腿的条数(可怕)。

在上面的例子中,我们的类中的数据可以被随意访问和修改,这是大问题。

发现问题所在之后,我们就需要去解决它,而解决办法就是封装

下面对Dog类进行封装:

/**
 * 对小狗类进行封装
 */
public class Dog {
    private String name;
    private Integer age;
    private Integer legs;

    public void say(String name) {
        System.out.println("我是"+ name +",汪汪汪");
    }

    public void watchDoor() {
        System.out.println("赶走陌生人");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getLegs() {
        return legs;
    }
    
    public void setLegs(Integer legs) {
        this.legs = legs;
    }
}

我们将小狗类的属性设置为私有,对这些数据进行隐藏,只能本类才能访问。

/**
 * 实例化一只小狗,并和它玩
 */
public class Play {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("哮天犬");;
        dog.setAge(2);
        dog.setLegs(4);
        dog.say(dog.getName());
        dog.watchDoor();
    }
}

外部类只有通过settergetter方法才能修改和访问属性。这些settergetter方法是Dog类自愿暴露出来的,是外部类访问该类的属性的入口,如果Dog类不想自己的某些属性被外部类访问和修改,那么关闭这些入口即可。

封装是将数据和操作数据的方法封装起来,对数据进行隐藏,避免了外部的干扰和误用,外部代码不被允许直接访问内部的对象数据,只能通过允许的方法来访问。这样就避免了外部代码和对象内部产生不必要的关系,在重构类内部代码时,(只要「入口」的调用方式不变)我们也不用修改外部代码。

在上文中,我们根据Dog类实例化出一个具体的小狗「哮天犬」,而封装则使哮天犬这个具体的个体更加独立、自主、安全。

2. 继承

之前我们去宠物店买了一只叫哮天犬的狗,宠物店里还有其他许多种类的宠物,猫、兔子、鸟、鱼……

下面我们写出他们的类:

/**
 * 猫类
 */
public class Cat {
    private String name;
    private Integer age;
    private Integer legs;

    public void say(String name) {
        System.out.println("我叫"+name+",喵喵喵");
    }

    public void catchMouse() {
        System.out.println("捉到一只老鼠");
    }

    setters and getters
}
/**
 * 兔子类
 */
public class Rabbit {
    private String name;
    private Integer age;
    private Integer legs;
    private String home;


    public void say(String name) {
        System.out.println("我叫"+name+",咕咕咕");
    }

    public void makeMedicine() {
        System.out.println("捣药");
    }

    setters and getters
}

写完猫类和兔子类后,我们发现了问题,有许多属性和方法是重复的,但是宠物店里还有许多宠物……

发现问题所在之后,我们就需要去解决它,而解决办法就是继承

继承涉及到父类和子类,父类是对子类的进一步抽象,子类比父类更具体。子类会继承父类的属性和行为,这意味着相同的代码只需写一遍。

/**
 * 动物类,父类
 */
public class Animal {
    private String name;
    private Integer age;
    private Integer legs;

    public void say(String name) {
        System.out.println("我是"+name+"发出声响");
    }

    setters and getters
}
/**
 * 小狗类,子类。继承Animal父类
 */
public class Dog extends Animal {
    
    public void say(String name) {
        System.out.println("我是"+ name +",汪汪汪");
    }

    public void watchDoor() {
        System.out.println("赶走陌生人");
    }
}
/**
 * 猫类,子类。继承Animal父类
 */
public class Cat extends Animal {

    public void say(String name) {
        System.out.println("我是"+name+",喵喵喵");
    }

    public void catchMouse() {
        System.out.println("捉到一只老鼠");
    }
}
/**
 * 兔子类,子类。继承Animal父类
 */
public class Rabbit extends Animal{
    private String home;

    public void say(String name) {
        System.out.println("我是"+name+",咕咕咕");
    }

    public void makeMedicine() {
        System.out.println("捣药");
    }

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }
}

我们将相同的代码抽取出来,放在Animal这个更抽象的类中,称之为父类。DogCatRabbit这些更具体的、具有Animal的成员变量和方法的类不必再重复那些代码,只需使用extend关键字继承Animal类即可。

  • 子类可以拥有他自己的成员变量和方法,即扩展父类。比如Rabbit类的home成员变量和makeMedicine()方法。
  • 子类如果感觉继承自父类的方法不合适,可以重写父类的方法的实现过程,注意返回值和形参不能改变。比如void say(String name)方法。
public class Play {
    public static void main(String[] args) {
        Rabbit rabbit = new Rabbit();
        rabbit.setName("玉兔");
        rabbit.setAge(1000);
        rabbit.setLegs(4);
        rabbit.setHome("广寒宫");
        rabbit.say(rabbit.getName());
        rabbit.makeMedicine();
    }
}

运行之,输出
    我叫玉兔,咕咕咕
    捣药

通过以上的例子看出,使用继承可以:

  • 提高代码的复用性,不用再写那么多重复代码了。
  • 使代码便于维护,当我们需要修改某个公用方法时,不需要一个个类去修改,只需修改父类的该方法即可。

3. 多态

看下面一段代码,我们来直观体验什么是多态。

public static void main(String[] args) {
    Animal dog = new Dog();
    dog.setName("哮天犬");
    dog.say(dog.getName());

    Animal cat = new Cat();
    cat.setName("加菲猫");
    cat.say(cat.getName());

    Animal rabbit = new Rabbit();
    rabbit.setName("玉兔");
    rabbit.say(rabbit.getName());
}

运行之,输出
    我是哮天犬,汪汪汪
    我是加菲猫,喵喵喵
    我是玉兔,咕咕咕
  1. DogCatRabbit都是继承Animal父类。
  2. DogCatRabbit重写Animalsay(String name)方法。
  3. 在创建实例对象时,我们使用父类引用指向子类的对象

使用多态应当注意一下几点:Animal dog = new Dog()

  • 在多态中,子类对象只能调用父类中定义的方法,不能调用子类中独有的方法。

    比如dog不能调用watchDoor()方法。

  • 在多态中,子类可以调用父类的所有方法。
  • 在多态中,子类如果重写了父类的方法,那么子类调用该方法时,调用的是子类重写的方法。

在上面的代码中,狗、猫、兔子对象都运行了say方法,但是输出不同。

由此看出,不同的对象的同一行为具有不同的表现形式,这就是多态。

在实际的本例中,我们可以理解为:你去宠物店买宠物Animal,他们都会叫出声。如果买狗,则叫的是汪汪汪;如果买猫,则叫的是喵喵喵;如果买兔子,则叫的是咕咕咕。

三、总结

面向对象思想使我们在编程更加贴近现实世界,类是现实世界的抽象,对象则是一个个具体的事物。封装使一个个具体的事物更加独立,继承则使这些类似的事物具有联系,而多态则使事物的行为更加灵活多样。

面向对象编程提高了软件的重用性、灵活性、扩展性。

如有错误,还请指正。

文章首发于公众号『行人观学』。

在这里插入图片描述


阅读 209

行小观的编程之行
微信公众号『行人观学』,一起学习计算机基础、数据结构和算法、Java、Go等编程知识。
15 声望
1 粉丝
0 条评论
你知道吗?

15 声望
1 粉丝
宣传栏