前言

在上一篇中回顾了java的修饰符和String类,这篇就来回顾下Java的三大特性:封装、继承、多态。

封装

什么是封装

在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

简单的来说,就是将Java中的经常用到的代码进行封装起来,形成一个方法。比如,我们常用的实体类,使用private修饰变量,用于保护数据;对外提供getter和setter方法,用于调用。这就是一种典型的封装。

代码示例:

    public class packagingTest {public static void main(String[] args) {User user=new User();//这里会报错,因为id和name是私有的,用于保护该数据//      user.id=10;//      user.name="张三";user.setId(1);user.setName("张三");System.out.println(user.getId());System.out.println(user.getName());}}class User{private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

运行结果:

    1张三

使用封装的好处

  1. 良好的封装能够减少耦合。

  2. 类内部的结构可以自由修改。

  3. 可以对成员变量进行更精确的控制。

  4. 隐藏信息,实现细节。

继承

什么是继承

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承的特性

  • 子类拥有父类非private的属性,方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。

为什么使用继承

继承主要目的是为了复用代码!简单的来说,就是将重复的代码抽出来,放到父类中,然后在再由子类继承使用,子类也是可以对父类进行扩展的。所以在继承关系中,可以这么理解,父类更通用,子类更具体。

打个比方,在动物世界中,猫和狮子是属于猫科,狗和狼是属于犬科。而它们也都是动物。猫和狮子有个共同的父类猫科,猫和狗有个共同的父类动物。所以它们是符合继承关系的, 只不过它们在行为上有所区别。猫和狗都有吃和睡,不过猫可以爬树,狗不可以。
这里,我们可以使用如下代码来进行说明。

代码示例:

public class extendTest {public static void main(String[] args) {Cat cat=new Cat();Dog dog=new Dog();cat.eat();cat.sleep("cat");cat.climbTree();dog.eat("dog");dog.sleep("dog");}
}class  Animal{public void eat(String name){System.out.println(name+"正在吃东西...");}public void sleep(String name){System.out.println(name+"正在睡觉...");}
}class Cat extends Animal{private String name="Cat";public void eat(){super.eat(name);System.out.println(name+"吃完了");}public void sleep(){this.sleep(name);}public void sleep(String name){System.out.println(name+"刚刚睡觉!");}public void climbTree(){System.out.println(name+"正在爬树!");}
}class Dog extends Animal{}

运行结果:

Cat正在吃东西...
Cat吃完了
cat刚刚睡觉!
Cat正在爬树!
dog正在吃东西...
dog正在睡觉...

在上述代码中,父类Animal实现了eat和sleep的方法,子类Cat和Dog使用了extends 关键字继承了父类Animal。子类Dog继承父类Animal之后什么都没做,而子类Cat不但继承了父类Animal,而且还增加了climbTree 方法,并且也重写了父类的eat和sleep方法。
在子类Cat中,出现了两个关键字:superthis
这两个关键字的意义如下:

  • super关键字:实现对父类成员的访问,用来引用当前对象的父类。
  • this关键字:指向自己的引用。

在上述代码中,子类Cat使用super关键字调用了父类Animal的eat方法,使用this关键字调用本类中的sleep方法。

说到继承,就不得不提这几个东西: final和protected修饰符、构造器、以及向上转型!
其中final和protected修饰符在上一篇java的修饰符和String类中已经讲解了,这里就简单的描述下。

  • final:修饰的类不可以被继承。
  • protected:修饰的类仅对同一包内的类和所有子类可见。

构造器

虽然子类可以继承父类的属性和方法(private修饰的除外),但是还有一样是子类无法继承的,那就是是构造器!对于构造器而言,它只能够被调用,而不能被继承。如果子类想使用父类的构造器,那么只需使用super关键字调用即可。

注:如果父类的构造器被private所修饰,那么是无法被外部调用的,包括子类!

向上转型

将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。
之前的个例子中,猫和动物是属于继承关系,那么我们可以把猫当作动物就是向上转型!
例如:

public class extendTest {public static void main(String[] args) {Animal animal=new Cat();animal.eat("cat");animal.sleep("cat");}
}class  Animal{public void eat(String name){System.out.println(name+"正在吃东西...");}public void sleep(String name){System.out.println(name+"正在睡觉...");}
}class Cat extends Animal{
private String name="Cat";public void eat(){super.eat(name);System.out.println(name+"吃完了");}public void sleep(){this.sleep(name);}public void sleep(String name){System.out.println(name+"刚刚睡觉!");}public void climbTree(){System.out.println(name+"正在爬树!");}
}

运行结果:

cat正在吃东西...
cat刚刚睡觉!

上述代码中完成了向上转型,但是在向上转型中是存在着一些缺憾的,那就是属性和方法的丢失。例如上述代码中就丢失了Cat类中的climbTree()方法和name属性。所以慎用向上转型!

多重继承

Java的继承是单继承,但是可以实现多重继承!
虽然一个子类只能继承一个父类,但是子类的子类也可以子类。
例如C类继承B类,B类继承A类,所以按照关系就是A类是B类的父类,B类是C类的父类。

继承的缺点

虽然继承大大提升了代码的复用性,但是也提高了类之间的耦合性!父类更改,子类就必须更改!因此可以说继承破坏了封装,因为对于父类而言,它的实现细节对与子类来说都是透明的。
所以慎用继承!!!

多态

什么是多态

多态是指事物在运行过程中存在不同的状态。

多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。

使用多态的必要条件

多态存在的三个必要条件:

  1. 要有继承关系;
  2. 子类要重写父类的方法;
  3. 父类引用指向子类对象,也就是向上转型。

多态使用的简单示例

在上面的继承讲解中,我们用到了猫和动物这两个之间的关系,这里我们也可以使用这,只需要稍微改下代码,就可以实现多态。

代码示例:

public class Test {public static void main(String[] args) {Animal animal=new Cat();animal.eat();}
}class  Animal{private String name="Animal";public void eat(){System.out.println(name+"正在吃东西...");sleep();}public void sleep(){System.out.println(name+"正在睡觉...");}
}class Cat extends Animal{private String name="Cat";public void eat(String name){System.out.println(name+"吃完了");sleep();}public void sleep(){System.out.println(name+"正在睡觉");}
}

输出结果:

Animal正在吃东西...
Cat正在睡觉

看到了运行结果之后,如果不熟悉多态的话,是不是感觉有些奇怪呢?
打印的第一句应该好理解,为什么打印的第二句不是Animal的方法,而是Cat中的方法呢?

我们知道多态是指事物在运行过程中存在不同的状态。而这里,我们用到了继承、重写以及向上转型。
在这里顺便提一下:

在向上转型中,一个父类的引用是可以指向多种子类对象,那么在运行时对于同一个消息是由实际的被引用的对象的类型来决定。

根据上述这段理解,我们再来看刚刚的那个示例。
在Cat类中,重写了父类Animal的sleep方法,并重载了eat方法。重载之后的eat(String name)方法和父类Animal的eat()方法不是同一个方法,因为是会在向上转型丢失的。而Cat子类重写了sleep方法,因此在向上转型的时候是不会丢失的,并且因为指定对对象的引用类型是Cat,所以Animal在调用eat()方法的时候,先是调用本类中eat()方法,然后在调用子类中的sleep()方法!

结论:

当父类引用指向子类方法时,必须调用那些父类中存在的方法,如果子类中对该方法进行了重写,那么在运行时就会动态调用子类中的方法,这就是多态。

使用多态的优点

摘自:https://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html

  1. 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
  2. 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
  3. 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
  4. 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
  5. 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

在对多态有一定的认识之后,可以尝试看看如下代码。
这是一个经典的多态问题,摘自:
http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx

代码示例:

    public class extendsTest {  public static void main(String[] args) {  A a1 = new A();  A a2 = new B();  B b = new B();  C c = new C();  D d = new D();  System.out.println("1--" + a1.show(b));  System.out.println("2--" + a1.show(c));  System.out.println("3--" + a1.show(d));   System.out.println("4--" + a2.show(b));   System.out.println("5--" + a2.show(c));  System.out.println("6--" + a2.show(d));  System.out.println("7--" + b.show(b));System.out.println("8--" + b.show(c));System.out.println("9--" + b.show(d));}  } class A {  public String show(D obj) {  return ("A and D");  }  public String show(A obj) {  return ("A and A");  }   }  class B extends A{  public String show(B obj){  return ("B and B");  }  public String show(A obj){  return ("B and A");  }   }  class C extends B{  }  class D extends B{  }  

运行结果:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

分析

①②③比较好理解,一般不会出错。④⑤就有点糊涂了,为什么输出的不是”B and B”呢?!!先来回顾一下多态性。

运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。

方法的重写Overriding和重载Overloading是Java多态性的不同表现。

重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。

当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。(但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)

好了,先温习到这里,言归正传!实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。让我们来看看它是怎么工作的。

比如④,a2.show(b),a2是一个引用变量,类型为A,则this为a2,b是B的一个实例,于是它到类A里面找show(B obj)方法,没有找到,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(Aobj),输出为”B and A”。

再比如⑧,b.show(c),b是一个引用变量,类型为B,则this为b,c是C的一个实例,于是它到类B找show(C obj)方法,没有找到,转而到B的超类A里面找,A里面也没有,因此也转到第三优先级this.show((super)O),this为b,O为C,(super)O即(super)C即B,因此它到B里面找show(Bobj)方法,找到了,由于b引用的是类B的一个对象,因此直接锁定到类B的show(B obj),输出为”B and B”。

按照上面的方法,可以正确得到其他的结果。
问题还要继续,现在我们再来看上面的分析过程是怎么体现出蓝色字体那句话的内涵的。它说:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还是拿a2.show(b)来说吧。

a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出”B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!问题在于我们不要忽略了蓝色字体的后半部分,那里特别指明:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。

B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(Aobj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(Aobj)(由于B继承A,虽然没有覆盖这个方法,但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在。

其它

参考:
http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx
https://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html
https://blog.csdn.net/chenssy/article/details/12786385

到此,本文就结束了,谢谢阅读!欢迎留言和点赞,你的支持是我写作最大的动力!
版权声明:
作者:虚无境
博客园出处:http://www.cnblogs.com/xuwujing
CSDN出处:http://blog.csdn.net/qazwsxpcm    
个人博客出处:http://www.panchengming.com

Java基础知识回顾之三 ----- 封装、继承和多态相关推荐

  1. Java基础知识回顾之七 ----- 总结篇

    前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...

  2. 【Java基础知识回顾篇】之打怪升级Day001

    Java基础知识回顾篇之打怪升级Day001 目录 Java基础知识回顾篇之打怪升级Day001 简介 一.为什么现在主流的是Java8和Java11? 二.简单尝试编写java程序 1.编写一个He ...

  3. Java基础知识融合(Arraylist集合,多态,继承,封装,包装类,循环嵌套,if嵌套等等)

    目录 1.项目大纲 1.项目前提 2.项目说明 3.项目内容 3.该软件完成以下功能: 2.软件设计 1.结构 2.类设计 3. 部分代码展示 心得: 1.项目大纲 1.项目前提 掌握java基本语法 ...

  4. Java基础知识回顾之四 ----- 集合List、Map和Set

    前言 在上一篇中回顾了Java的三大特性:封装.继承和多态.本篇则来介绍下集合. 集合介绍 我们在进行Java程序开发的时候,除了最常用的基础数据类型和String对象外,也经常会用到集合相关类. 集 ...

  5. Java基础知识回顾之一 ----- 基本数据类型

    前言 在开始工作至今,学习各种各样的技术之中发现自己的很多Java的基础知识都忘了⊙﹏⊙b汗... 而且越是学习越是发现Java基础的重要性,所以准备单独抽一下时间进行Java基础的重新学习.在重新学 ...

  6. Java基础知识回顾之六 ----- IO流

    前言 在上一篇文章中,回顾了Java的多线程.而在本篇文章中主要介绍Java IO的相关知识. IO的介绍 什么是IO? IO的名称又来是Input与Output的缩写,也就是输入流和输出流.输入流用 ...

  7. Java基础知识回顾

    1.Java集合 (1).几种集合(List.Set和Map)的区别          JAVA中几种集合(List.Set和Map)的区别   java常用集合总结 Java集合类: Set.Lis ...

  8. java基础知识回顾之javaIO类总结

    java IO体系图 IO流的操作规律总结: 1,明确体系: 数据源:InputStream ,Reader 数据汇:OutputStream,Writer 2,明确数据:因为数据分两种:字节,字符. ...

  9. java基础知识回顾之javaIO类---FileInputStream和FileOutputStream字节流复制图片

    package com.lp.ecjtu;import java.io.FileInputStream; import java.io.FileNotFoundException; import ja ...

最新文章

  1. 基于Spring boot 2.1 使用redisson实现分布式锁
  2. Vue2.0通过二级路由实现页面切换
  3. python 读取csv文件
  4. C++算法学习(回溯算法)
  5. EditText控件(圆角处理)
  6. 3.10 Spark RDD编程案例
  7. HTML5 WebSocket
  8. 20200519每日一句
  9. Python功能实现:为pdf电子书籍生成书签目录
  10. 谷歌浏览器翻译显示服务器失败,谷歌浏览器翻译失败怎么办
  11. 仿百思不得其姐项目开发(粗略笔记,后期规范排版和更新)
  12. 计算机应用基础的重点知识,《计算机应用基础知识》重点总结
  13. c语言中的less函数,less的使用-基本语法-编译
  14. for in遍历对象时break,continue,return尝试
  15. HAUTOJ 1262 魔法宝石
  16. u盘恢复数据|U盘打不开提示格式化怎么恢复数据?
  17. python 编程4,和7 幸运数字
  18. 微信软件服务器在那个国家,安道尔究竟是什么地方?为什么2000万中国人微信地址都选在安道尔...
  19. 串口硬盘GHOST死机
  20. 基于循环神经网络的主题模型

热门文章

  1. TouchDesigner 学习 Chop Noise
  2. Windows ICS 服务无法启动问题解决方法
  3. 使用 Velocity 实现客户端和服务器端模板
  4. com.aspose.cells使用ICustomFunction自定义函数
  5. 中职计算机教育 论文题目,比较好写的中职计算机教育论文题目 中职计算机教育专业论文题目怎样拟...
  6. python网络编程攻略-Python四大主流网络编程框架
  7. hdf heg 批量拼接_HEG安装教程(windows平台)
  8. ubuntu 飞信客户端安装
  9. maya mentray_maya平台的三款渲染器arnold ,mentalray,vray,各自特点,及发展史,和发展趋势?...
  10. 自荐信当计算机课代表,北京邮电大学自主招生考生自荐信范文