zoukankan      html  css  js  c++  java
  • 还不清楚怎样面向对象?

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

    一、引入例子

    创建一个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,他们都会叫出声。如果买狗,则叫的是汪汪汪;如果买猫,则叫的是喵喵喵;如果买兔子,则叫的是咕咕咕。

    三、总结

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

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

    如有错误,还请指正。


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

    在这里插入图片描述


  • 相关阅读:
    websocket的理解&应用&场景
    如何设置winform程序图标
    Python简单爬虫爬取自己博客园所有文章
    分享一个自己做的SpringMVC的PPT
    2016校招薪资汇总
    2016阿里巴巴校招offer面经
    利用快排partition求前N小的元素
    几个面试经典算法题Java解答
    深入理解java垃圾回收机制
    深入理解JVM结构
  • 原文地址:https://www.cnblogs.com/xingrenguanxue/p/13124351.html
Copyright © 2011-2022 走看看