面向对象综述

封装

封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫接口

有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者;而外部调用者也可以知道自己不可以碰哪里。

这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

封装成员方法来间接操作类里面的成员变量

使用成员属性来间接访问类里面的成员变量

访问修饰符

private 私有的 只能在该类中访问
protected 受保护的 只能在该类和它的子类中访问
public 公有的 在任何地方都可以访问

继承和多态

什么是继承?

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

继承有什么好处?

继承可以把父类的所有功能都直接拿过来,这样就不必重零做起(比如object类实现了 ToString()方法,则继承自object的子类就无需再次实现该方法,直接调用)

子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;

继承的第二个好处需要我们对代码做一点改进。当子类和父类都存在相同的Speak()方法时,我们说,子类的Speak()覆盖了父类的Speak(),在代码运行的时候,总是会调用子类的Speak()。这样,我们就获得了继承的另一个好处:多态。

有了继承,才能有多态。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;

理解多态之前首先要对面向对象的里氏替换原则和开放封闭原则有所了解。

里氏替换原则(Liskov Substitution Principle):派生类(子类)对象能够替换其基类(超类)对象被使用。通俗一点的理解就是“子类是父类”,举个例子,

“男人是人,人不一定是男人”,当需要一个父类类型的对象的时候可以给一个子类类型的对象;当需要一个子类类型对象的时候给一个父类类型对象是不可以的!

开放封闭原则(Open Closed Principle):封装变化、降低耦合,软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。

因此,开放封闭原则主要体现在两个方面:对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

对这两个原则有一定了解之后就能更好的理解多态。

任何时候,如果没有合适的类可以继承,就继承自object类。

Person
package cn.cnki.test;

public class Person {

    public void Speak() {
System.out.println("人可以说话");
}
}
Chinese 
package cn.cnki.test;

public class Chinese extends Person{
public void Speak() {
System.out.println("中国人说中国话");
}
}
Japan
package cn.cnki.test;

public class Japan extends Person{
public void Speak() {
System.out.println("日本人说日本话");
}
}

Test

@Test
public void FunctionTest()
{
Person p1=new Chinese();
p1.Speak();
Person p2=new Japan();
p2.Speak();
}

结果

一句话总结:多态就是父类类型的变量可以指向子类类型的对象,调用方法的时候调用的是子类的实现(父变量指向子对象,调用子实现

为什么需要多态?多态的好处?如果没有多态会怎样?

继续上面的代码,如果此时我们新增一个子类American,只需新增一个American类继承自Person并重写Speak()方法即可,而父类是无需任何修改的。

至此,该程序的扩展性得到了提升,而又不需要查看源代码是如何实现的就可以扩展新功能。这就是多态带来的好处。

public class American extends Person{
public void Speak() {
System.out.println("美国人说美国话");
}
}

对于一个变量,我们只需要知道它是Person类型,无需确切地知道它的子类型,就可以放心地调用Speak()方法,而具体调用的Speak()方法是

作用在Chinese、Japan还是American对象上由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,

而当我们新增一种Person的子类时,只要确保Speak()方法编写正确,不用管原来的代码是如何调用的。

这就是著名的“开闭”原则

对扩展开放:允许新增Person子类;

对修改封闭:不需要修改依赖Person类型的Speak()函数。

多态的本质作用就是把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

虚方法(virtual)

Java普通方法就是虚方法

抽象类和抽象方法

还是刚才的例子,我们发现Person这个父类,我们根本不需要使用它创建的对象,它存在的意义就是供子类来继承。所以我们可以用抽象类来优化它。

public abstract class Person {
public abstract void Speak();
}

其他代码不变,输出结果依然相同。

由此可见,我们选择使用虚方法实现多态还是抽象类抽象方法实现多态,取决于我们是否需要使用基类实例化的对象.

Person类作为基类,Chinese,Japan类继承American,我们需要使用的是Chinese和Japan创建的对象,根本不需要使用Person创建的对象,所以在这里Person完全可以写成抽象类。

总而言之,是使用虚方法,或者抽象类抽象方法实现多态,视情况而定,什么情况?以上我说的两点~

接口

为什么需要接口?

我们知道少林寺的武僧会武术,歌剧院的演员会舞蹈,虽然所有人都可以Speak,但并非所有的人都会武术都会舞蹈吧,

此时如果我们在父类Person里面新增武术方法和舞蹈方法,然后让所有的子类都去实现这两个方法是否有所不妥呢?

你要是非要这样做,功能完全可以实现,可是这样违背了面向对象开放封闭原则。下次我要再扩展一个戏曲演员唱京剧方法,

我还要去源代码中看下是怎么实现的,然后在戏曲演员类中再次添加唱京剧方法,相同的功能,重复的代码,这样是不合理的,程序也不便于扩展;

接来下我们看接口是如何解决以上问题的

新增武术接口

public interface IWuShu {
void WuShu();//武术
}

新增跳舞接口

public interface ITiaoWu {
void Tiaowu();//跳舞
}

新增武僧类

public class WuSeng extends Person implements IWuShu {
public void Speak() {
System.out.println("武僧会念经");
}
@Override
public void WuShu() {
System.out.println("武僧会武术");
}
}

新增演员类

public class YanYuan extends Person implements ITiaoWu {
public void Speak() {
System.out.println("演员会唱歌");
}
@Override
public void Tiaowu() {
System.out.println("演员会跳舞");
}
}

可以看出实现了IWuShu接口的武僧可以会武术,实现了ITiaoWu接口的演员可以会跳舞。我们想要哪类人拥有哪项技能只需定义一个接口让其去实现即可。

实现了就具备该项技能,反之则不具备。

接口实现多态程序的扩展性得到了大大提升,以后不管是再扩展一个京剧演员,还是篮球运动员,创建一个类,实现这个接口,在主函数中添加该对象就可以了。

也不需要查看源代码是如何实现的,体现了开放封闭原则!

什么时候使用接口,什么时候使用抽象类

如果你想拥有一些方法,并且这些方法有默认实现,那么久使用抽象类

如果你想实现多继承,那么就是用接口吧,java不支持多继承,但是可以实现多个接口

小结

  优先选用接口

  在既要定义子类的行为,又要为子类提供公共的功能时,应选择抽象类。

虚方法(virtual)和抽象方法(abstract)

相同点:

虚方法(virtual)和抽象方法(abstract)都可以被派生类重写

不同点:
1.虚方法(virtual)有方法实体,抽象方法(abstract)没有方法实体【类似接口】

virtual void SayWord()
{
//代码
}
abstract void SayWord();

2.虚方法(virtual)在派生类中可以不重写,抽象方法(abstract)派生类中必须重写【类似接口】

abstract class Person
{
abstract void SayName();
}
class Man:Person
{
override void SayName()
{
//方法实体
}
}

3.抽象方法(abstract)必须声明在抽象类中,抽象方法结合抽象类实现多态

Java入门系列(三)面向对象三大特性之封装、继承、多态的更多相关文章

  1. Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

    Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 ​ 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...

  2. JAVA基础——面向对象三大特性:封装、继承、多态

    JAVA面向对象三大特性详解 一.封装 1.概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: 只能通过规定的方法访问数据. ...

  3. Javascript面向对象三大特性(封装性、继承性、多态性)详解及创建对象的各种方法

    Javascript基于对象的三大特征和C++,Java面向对象的三大特征一样,都是封装(encapsulation).继承(inheritance )和多态(polymorphism ).只不过实现 ...

  4. java面向对象三大特性:封装、继承、多态

    一.封装 封装也称信息隐藏,是指利用抽象数据类型把数据和基于数据的操作封装起来,使其成为一个不可分割的整体,数据隐藏在抽象数据内部,尽可能的隐藏数据细节,只保留一些接口使其与外界发生联系.也就是说用户 ...

  5. Java中面向对象三大特性之——封装

    概述 面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改. 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问.要访问该类的数据,必须通 ...

  6. C# 面向对象三大特性:封装、继承、多态

    面向对象有封装.继承.多态这三个特性,面向对象编程按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成任务.这种编程方法提供了非常强大的多样性,大大增加了 ...

  7. python面向对象三大特性之一封装

    一.什么是封装 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其 含义是其他程序无法调用. 要了解封装,离不开“私有化”,就是将类或者 ...

  8. C#面向对象三大特性:封装

    什么是封装 定义:把一个或多个项目封闭在一个物理的或者逻辑的包中.在面向对象程序设计方法论中,封装是为了防止对实现细节的访问. 封装的优点 1. 隔离性,安全性.被封装后的对象(这里的对象是泛指代码的 ...

  9. Objective-C----MRC内存管理 、 自动释放池 、 面向对象三大特性及封装 、 继承 、 组合与聚合

    1 MRC练习 1.1 问题 引用计数是Objective-C语言采用的一种内存管理技术,当一个对象被创建在堆上后,该对象的引用计数就自动设置为1,如果在其它对象中的对象成员需要持有这个对象时,则该对 ...

随机推荐

  1. Ubuntu下tensorboard的使用

    1. 找到运行程序的事件输出路径   找到路径并进入,例如我的是在路径/home/ly/codes下: 2. 打开tensorboard服务器   在终端输入(--logdir=自己所存的路径): t ...

  2. [并查集] 1118. Birds in Forest (25)

    1118. Birds in Forest (25) Some scientists took pictures of thousands of birds in a forest. Assume t ...

  3. Robot Framework 教程 (7) - 使用For循环

    在自动化测试过程中,使用For循环来对某个动作进行重复操作是很普遍的行为.在Robot Framework中,各种测试库中均提供了多种方式的For循环结构,在其中覆盖了大部分类型的循环类型.而Robo ...

  4. git bash使用(markdown版)

    前言 我是通过这个来学习的.个人愚笨,琢磨了半天,终于搞通了,醉了醉了,以前一直使用svn,用git确实有点水土不服.本文以如何使用git为主来展开,不涉及太多理论. git是分布式的版本管理.什么叫 ...

  5. 《编写高质量代码改善JavaScript程序的188个建议》读书笔记

    逗号运算符比较怪异.如    var a =(1,2,3,4);alert(a);// 4      var a = 1,2,3,4;//报错 注意a++和++a的差别,变量在参与运算中不断地变化.v ...

  6. BZOJ3462 DZY Loves Math II(动态规划+组合数学)

    容易发现这是一个有各种玄妙性质的完全背包计数. 对于每个质数,将其选取个数写成ax+b的形式,其中x=S/pi,0<b<x.那么可以枚举b的部分提供了多少贡献,多重背包计算,a的部分直接组 ...

  7. 一千个不用Null的理由

    原文链接:http://www.importnew.com/27378.html 原文出处: xrzs 港真,Null 貌似在哪里都是个头疼的问题,比如 Java 里让人头疼的 NullPointer ...

  8. MT【152】不患寡而患不均

    ((清华2017.4.29标准学术能力测试1) $a_1,a_2,\cdots,a_9$ 是数字$1$到$9$ 的一个排列,则 $a_1a_2a_3+a_4a_5a_6+a_7a_8a_9$ 的最小值 ...

  9. BZOJ 4520: [Cqoi2016]K远点对

    4520: [Cqoi2016]K远点对 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 638  Solved: 340[Submit][Status ...

  10. BZOJ4732. [清华集训2016]数据交互(树链剖分+线段树+multiset)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4732 题解 首先,一个比较显然的结论是:对于一棵有根树上的两条链 \((x_1, y_1 ...