在还不清楚怎样面向对象?一文中,已经简单介绍了面向对象的基本思想和三大特性,可是不够详细。本文再来具体探究一下面向对象。java
面向过程编程(Procedure Oriented Programming,POP)是一种以过程为中心的编程思想,开发人员在解决问题时更专一于过程。编程
当咱们遇到一个问题时,只须要分析出第1步要作什么、第2步要作什么……直到解决问题,而后把这些步骤一步步地实现便可。安全
好比,我如今要编写一个面向过程的程序来模拟「我要让个人好朋友行小观去帮我买瓶水」这个问题,以下:网络
在从「给行小观钱」到「行小观把水给我」的整个过程,我和行小观都专一于完成每个步骤(事件),行小观只是一个执行我事先描述好的步骤的无思想的工具人而已。工具
若是我还有其余问题须要行小观帮忙,那么我就还得把如何完成这些问题的详细步骤全都告诉他,这么麻烦那我还找别人帮忙干什么呢?还不如我本身去作。并且有些问题我本身也不会作,那怎么办?因此行小观并非一个合格的工具人。this
与面向过程编程不一样,面向对象编程(Object Oriented Programming,OOP)是一种以对象为中心的编程思想,对象是现实世界中的一个个事物的实体。code
对象包含了用户可使用(公开)的功能部分和对用户隐藏的实现部分。jwt
在开发过程当中,咱们可使用功能部分来解决问题,可是并不关心功能是怎样实现的。对象
仍是上面的那个买水的例子,使用面向对象来实现:blog
在这个例子中,我只须要给行小观钱,而后他就能帮我买水。我相信我请行小观有「买水的能力」,他必定能帮我买到水。至于去哪买?怎么买?行小观本身知道,我并不关心他是怎么买到水的,由于个人目的很简单:「我想要一瓶水」。
若是我有其余问题须要行小观帮忙,不管这些问题我会不会作,直接告诉他就行了,他会帮我完成。
我只专一于问题自己,具体的操做我并不关心。如今行小观是一个合格的工具人了。
这里经过一个你们耳熟能详的神话——女娲造人,来讲明类和对象之间的关系。
相传女娲以泥土仿照本身抟土造人,创造并构建人类社会。
在这个神话里,「女娲」是一个蓝图、模板,「人」是依据该蓝图被创造出来的个体。
「女娲」能够看作类(Class),「人」能够看作对象(Object)。
跳出神话,来到真实世界。
咱们目能所及的事物均可以看作是「对象」,好比说你用的桌子、坐的椅子、玩的电脑、养的狗……这些一个个真实存在,你能摸到的物品都是对象。
狗有千千万……高的、矮的、胖的、瘦的、黑色的、白色的等各不相同,可是总能在这些不一样的狗之中找到相同的特性,这些不一样品种的狗咱们把它统称为「狗」。「狗」即为类,而咱们养的真实存在的狗为对象。
总结一下:
类是对一类具备共同特征的事物的抽象,是一类事物的统称,是一个抽象概念(好比“人类”这个名词)。
对象是这类事物相对应的具体存在的实体,是一个具体存在的事物(好比“行小观”这个具体的人)。
类是建立单个对象时的蓝图、模板。
当咱们说到「狗」这个类的时候,会很天然地想到和狗相关的一些特色和习性。
好比,名字、品种、颜色、年龄等,这些是属性。
还有,吠叫、看门等,这些是行为。
一个类包括了属性和行为,行为能够操纵属性。
对应到代码中,属性即为成员变量,行为即为成员方法,成员方法能够操纵成员变量。
下面是一个具体的类:
程序2-1 /** * 狗类 * @author Xing Xiaoguan */ public class Dog { //属性——成员变量 String name; int age; int legs; //行为——成员方法 //行为——吠叫 public void say() { System.out.println("我是" + name + "汪汪汪"); } //行为——看门 public void watchDoor() { System.out.println("赶走陌生人"); } }
类是一个抽象概念,而对象则是一个具体的实例。
以狗为例,咱们养的不多是「一类狗」,而是在和一只「具体的狗」玩耍,好比说哮天犬。
回到女娲(类)造人(对象)这个神话中,人是以女娲为模板被造出来的,女娲造人的过程,即由类构造对象的过程称为建立类的实例(instance)。
程序2-2 public static void main(String[] args) { Dog dog = new Dog();//建立类的实例,对象dog dog.name = "哮天犬"; dog.age = 2; dog.legs = 4; dog.say(); }
对于被建立出来的对象而言,它们都不同,每个特定的对象(实例)都有一组特定的属性值(成员变量),这些属性值的集合就是这个对象的当前状态,只要对象使用者经过行为(成员方法)向该对象发送消息,这些状态就可能被改变。
上面这句话怎么理解?
如今有两只狗(两个对象):哮天犬和哮地犬,这两个对象的名字、年龄等属性不一样,即当前状态不一样。每只狗都有一个行为:能够「每过一年,年龄增加1岁」,当经过该行为向哮天犬发送消息时,哮天犬的状态就被改变了。
能够看出,一个对象由状态(state)和行为(behavior)组成,对象在成员变量中存储状态,经过成员方法公开其行为。
研究一个对象,咱们要去关注它处于什么状态?具备哪些行为?
对象的三个主要特性:
封装(encapsulation)是Java面向对象的三大特行之一。
一个对象具备属性和行为,封装把其属性和行为组合在了一块儿,可是为何须要封装?
上文已经介绍了,一个对象由其状态和行为组成。咱们回看程序2-1
,虽然这段代码表示出了Dog
类,可是有一个很大的问题:建立出来的Dog对象的状态很容易被改变。
好比咱们能够直接修改程序2-2
中的对象的状态:
dog.name = "哮地犬"; dog.legs = 3;
你的狗的名字被不怀好意的人给改了,腿也少了一条!这种事情是危险、可怕的!
咱们但愿别人可以“知道”本身的狗叫什么名字、有几条腿等信息,可是又要防止不怀好意的人随便“伤害”本身的狗,怎么办呢?答案是封装!
将对象的状态和行为封装起来,使用该对象的用户只能经过对象自己提供的方法来访问该对象的状态。前面也说过,对象的当前状态可能会改变,可是这种改变不是对象自发的,必须经过调用对象自己提供的方法来改变。若是不经过调用方法就能改变对象状态,只能说明封装性被破坏了。
换句话说,咱们将对象的属性(状态)对外隐藏起来,这些状态可否被访问或修改,由对象本身来决定,决定的方式就是「给对象的使用者提供可调用的方法,用户经过这些方法来进行访问和修改」。
程序2-1
能够改进为:
程序3-1 /** * 封装后的狗类 * @author Xing Xiaoguan */ public class Dog { private String name; private int age; private int legs; public String getName() { return name; } public int getAge() { return age; } public int getLegs() { return legs; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } //行为——吠叫 public void say() { System.out.println("我是" + name + "汪汪汪"); } //行为——看门 public void watchDoor() { System.out.println("赶走陌生人"); } }
乍一看多了许多代码,其实就多了两个部分:
private
修饰符来修饰成员变量,将其私有化,确保只能在本类内被访问到,实现隐藏。getter
方法)和修改方法(setter
方法)。其中咱们给用户可以访问或修改的成员变量都编写上对应的setter或getter方法,如name
。用户不能访问或修改的成员变量不写setter或getter方法便可。
/** * 实例化一只小狗,并和它玩 */ public class Play { public static void main(String[] args) { Dog dog = new Dog(); dog.setName("哮天犬");; dog.setAge(2); dog.say(); dog.watchDoor(); } }
如今,用户不能直接访问或修改对象的状态,必须经过提供的方法。对象并无给legs
变量提供setter
方法,这样用户就只能访问狗有几条腿,可是不能修改。狗腿被人“偷”了的事情也不会再发生了。
并且,当咱们使用setter方法修改为员变量时,能够进行其余的操做,如错误检查。好比设置age
变量时:
//狗的平均寿命为10~15年,太大了不合理 public void setName(String name) { if (name > 0 && name < 30) this.name = name; }
如今,Dog
类就比较安全了。
由上面的代码能够看出,若是要访问或修改为员变量,须要:
封装还有一个优势就是:对外隐藏了具体实现,这样的好处就是:咱们能够修改内部实现,除了修改了该类的方法外,不会影响其余代码。
封装使对象对外变成了一个“黑箱”,用户只会使用,但不清楚内部状况。
前面买水的例子也体现了封装思想:行小观买水的方式有不少,走路去、骑车去、甚至找比人帮忙,可是他改变买水的方式并不会对我形成影响。
生活中除了狗,还有许多其余动物,好比猫、兔子……
程序3-2 /** * 猫类 * @author Xing Xiaoguan */ public class Cat { private String name; private int age; private int legs; private String owner;//主人 //getters and setters…… //行为——叫 public void say() { System.out.println("我是" + name + "喵喵喵"); } //行为——捉老鼠 public void catchMouse() { System.out.println("捉到一只老鼠"); } }
程序2-5 /** * 兔子类 * @author Xing Xiaoguan */ public class Rabbit { private String name; private int age; private int legs; private String home;//住址 //getters and setters…… //行为——叫 public void say() { System.out.println("我是" + name + "咕咕咕"); } //行为——捣药 public void makeMedicine() { System.out.println("在" + home + "捣药"); } }
写完这两个类,发现有许多属性和方法是重复的,若是须要再写100个动物的类,那得
这些动物形态万千,可是它们都被统称为“动物”,也就是说,咱们仍能在它们身上找出相同的特色,好比它们都有名字、年龄、腿、能发出声音……
前面介绍类的时候已经说了,类是对一类具备共同特征的事物的抽象,因此此时咱们还能从狗、猫、兔子这些类中再抽象出一个类——动物类。
程序3-3 /** * 动物类 * @author Xing Xiaoguan */ public class Animal { private String name; private Integer age; private Integer legs; public void say() { System.out.println("我是"+name+"发出声响"); } //setters and getters…… }
这个更抽象的类就是父类,而狗、猫、兔子类是子类。子类可使用extends
关键字继承父类的属性和方法,这意味着相同的代码只须要写一遍。
程序3-4 /** * 狗类继承父类 * @author Xing Xiaoguan */ public class Dog extends Animal{ //行为——吠叫 public void say() { System.out.println("我是" + getName() + "汪汪汪"); } //行为——看门 public void watchDoor() { System.out.println("赶走陌生人"); } }
程序3-5 /** * 猫类继承父类 * @author Xing Xiaoguan */ public class Cat extends Animal { private String owner; public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } //行为——喵喵叫 public void say() { System.out.println("我是" + getName() + "喵喵喵"); } //行为——捉老鼠 public void catchMouse() { System.out.println("捉到一只老鼠"); } }
程序3-6 /** * 兔子类继承父类 * @author Xing Xiaoguan */ public class Rabbit extends Animal { private String home; public String getHome() { return home; } public void setHome(String home) { this.home = home; } //行为——叫 public void say() { System.out.println("我是" + getName() + "咕咕咕"); } //行为——捣药 public void makeMedicine() { System.out.println("在" + home + "捣药"); } }
观察上面的子类和父类,能够发现:
使用继承的好处:
看下面一段代码,咱们来直观体验什么是多态。
程序3-7 public static void main(String[] args) { Animal dog = new Dog(); dog.setName("哮天犬"); dog.say(dog.getName()); Animal cat = new Cat(); cat.setName("加菲猫"); cat.say(); Animal rabbit = new Rabbit(); rabbit.setName("玉兔"); rabbit.say(); } 运行,输出: 我是哮天犬汪汪汪 我是加菲猫喵喵喵 我是玉兔咕咕咕
Dog
、Cat
和Rabbit
都是继承了Animal
父类。Dog
、Cat
和Rabbit
都重写了Animal
的say(String name)
方法。使用多态应当注意一下几点:Animal dog = new Dog()
在多态中,子类对象只能调用父类中定义的方法,不能调用子类中独有的方法。
好比dog
不能调用watchDoor()
方法。
在多态中,子类能够调用父类的全部方法。
在多态中,子类若是重写了父类的方法,那么子类调用该方法时,调用的是子类重写的方法。
在上面的代码中,狗、猫、兔子对象都运行了say方法,可是输出不一样。
由此看出,不一样的对象的同一行为具备不一样的表现形式,这就是多态。
在实际的本例中,咱们能够理解为:动物Animal
,他们都会叫出声。若是是狗,则叫的是汪汪汪;若是是猫,则叫的是喵喵喵;若是是兔子,则叫的是咕咕咕。
面向对象思想使咱们在编程更加贴近现实世界,类是现实世界的抽象,对象则是一个个具体的事物。
封装使一个个具体的事物更加独立,继承则使一些相似的事物之间具备联系,而多态则使事物的行为更加灵活多样。
面向对象编程提升了软件的重用性、灵活性、扩展性。
若有错误,还请指正
参考资料:
The Java Tutorials
维基百科
百度百科
Java核心技术 卷1
文章首发于公众号「行人观学」