本节主要介绍Java面向对象三大特性:继承 封装 多态,以及其中的原理。

本文会结合虚拟机对引用和对象的不同处理来介绍三大特性的原理。

继承

Java中的继承只能单继承,但是可以通过内部类继承其他类来实现多继承。

public class Son extends Father{public void go () {System.out.println("son go");}public void eat () {System.out.println("son eat");}public void sleep() {System.out.println("zzzzzz");}public void cook() {//匿名内部类实现的多继承new Mother().cook();//内部类继承第二个父类来实现多继承Mom mom = new Mom();mom.cook();}private class Mom extends Mother {@Overridepublic void cook() {System.out.println("mom cook");}}}

封装

封装主要是因为Java有访问权限的控制。public > protected > package = default > private。封装可以保护类中的信息,只提供想要被外界访问的信息。

类的访问范围

 A、public    包内、包外,所有类中可见B、protected 包内所有类可见,包外有继承关系的子类可见(子类对象可调用)C、(default)表示默认,不仅本类访问,而且是同包可。D、private   仅在同一类中可见 

多态

多态一般可以分为两种,一个是重写,一个是重载。

  1. 重写是由于继承关系中的子类有一个和父类同名同参数的方法,会覆盖掉父类的方法。重载是因为一个同名方法可以传入多个参数组合。

  2. 注意,同名方法如果参数相同,即使返回值不同也是不能同时存在的,编译会出错。

  3. 从jvm实现的角度来看,重写又叫运行时多态,编译时看不出子类调用的是哪个方法,但是运行时操作数栈会先根据子类的引用去子类的类信息中查找方法,找不到的话再到父类的类信息中查找方法。

  4. 而重载则是编译时多态,因为编译期就可以确定传入的参数组合,决定调用的具体方法是哪一个了。

向上转型和向下转型:

  1. public static void main(String[] args) {

  2.    Son son = new Son();

  3.    //首先先明确一点,转型指的是左侧引用的改变。

  4.    //father引用类型是Father,指向Son实例,就是向上转型,既可以使用子类的方法,也可以使用父类的方法。

  5.    //向上转型,此时运行father的方法

  6.    Father father = son;

  7.    father.smoke();

  8.    //不能使用子类独有的方法。

  9.    // father.play();编译会报错

  10.    father.drive();

  11.    //Son类型的引用指向Father的实例,所以是向下转型,不能使用子类非重写的方法,可以使用父类的方法。

  12.    //向下转型,此时运行了son的方法

  13.    Son son1 = (Son) father;

  14.    //转型后就是一个正常的Son实例

  15.    son1.play();

  16.    son1.drive();

  17.    son1.smoke();

  18.    //因为向下转型之前必须先经历向上转型。

  19.    //在向下转型过程中,分为两种情况:

  20.    //情况一:如果父类引用的对象如果引用的是指向的子类对象,

  21.    //那么在向下转型的过程中是安全的。也就是编译是不会出错误的。

  22.    //因为运行期Son实例确实有这些方法

  23.    Father f1 = new Son();

  24.    Son s1 = (Son) f1;

  25.    s1.smoke();

  26.    s1.drive();

  27.    s1.play();

  28.    //情况二:如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,

  29.    //但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。

  30.    //因为运行期Father实例并没有这些方法。

  31.        Father f2 = new Father();

  32.        Son s2 = (Son) f2;

  33.        s2.drive();

  34.        s2.smoke();

  35.        s2.play();

  36.    //向下转型和向上转型的应用,有些人觉得这个操作没意义,何必先向上转型再向下转型呢,不是多此一举么。其实可以用于方法参数中的类型聚合,然后具体操作再进行分解。

  37.    //比如add方法用List引用类型作为参数传入,传入具体类时经历了向下转型

  38.    add(new LinkedList());

  39.    add(new ArrayList());

  40.    //总结

  41.    //向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法

  42.    //并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错。

  43.    //若安全则继续执行方法。

  44. }

  45. public static void add(List list) {

  46.    System.out.println(list);

  47.    //在操作具体集合时又经历了向上转型

  48. //        ArrayList arr = (ArrayList) list;

  49. //        LinkedList link = (LinkedList) list;

  50. }

总结: 向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法。并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错,若安全则继续执行方法。

编译期的静态分派

其实就是根据引用类型来调用对应方法。

  1. public static void main(String[] args) {

  2.    Father father  = new Son();

  3.    静态分派 a= new 静态分派();

  4.    //编译期确定引用类型为Father。

  5.    //所以调用的是第一个方法。

  6.    a.play(father);

  7.    //向下转型后,引用类型为Son,此时调用第二个方法。

  8.    //所以,编译期只确定了引用,运行期再进行实例化。

  9.    a.play((Son)father);

  10.    //当没有Son引用类型的方法时,会自动向上转型调用第一个方法。

  11.    a.smoke(father);

  12.    //

  13. }

  14. public void smoke(Father father) {

  15.    System.out.println("father smoke");

  16. }

  17. public void play (Father father) {

  18.    System.out.println("father");

  19.    //father.drive();

  20. }

  21. public void play (Son son) {

  22.    System.out.println("son");

  23.    //son.drive();

  24. }

方法重载优先级匹配

  1. public static void main(String[] args) {

  2.    方法重载优先级匹配 a = new 方法重载优先级匹配();

  3.    //普通的重载一般就是同名方法不同参数。

  4.    //这里我们来讨论当同名方法只有一个参数时的情况。

  5.    //此时会调用char参数的方法。

  6.    //当没有char参数的方法。会调用int类型的方法,如果没有int就调用long

  7.    //即存在一个调用顺序char -> int -> long ->double -> ..。

  8.    //当没有基本类型对应的方法时,先自动装箱,调用包装类方法。

  9.    //如果没有包装类方法,则调用包装类实现的接口的方法。

  10.    //最后再调用持有多个参数的char...方法。

  11.    a.eat('a');

  12.    a.eat('a','c','b');

  13. }

  14. public void eat(short i) {

  15.    System.out.println("short");

  16. }

  17. public void eat(int i) {

  18.    System.out.println("int");

  19. }

  20. public void eat(double i) {

  21.    System.out.println("double");

  22. }

  23. public void eat(long i) {

  24.    System.out.println("long");

  25. }

  26. public void eat(Character c) {

  27.    System.out.println("Character");

  28. }

  29. public void eat(Comparable c) {

  30.    System.out.println("Comparable");

  31. }

  32. public void eat(char ... c) {

  33.    System.out.println(Arrays.toString(c));

  34.    System.out.println("...");

  35. }

  36. //    public void eat(char i) {

  37. //        System.out.println("char");

  38. //    }

【Java基本功】一文了解Java中继承、封装、多态的细节的更多相关文章

  1. OOP面向对象 三大特征 继承封装多态

    OOP面向对象 ----三大特征 继承封装多态 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构 ...

  2. [转]Java中继承、多态、重载和重写介绍

    什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上 ...

  3. Java面向对象理解_代码块_继承_多态_抽象_接口

    面线对象: /* 成员变量和局部变量的区别? A:在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B:在内存中的位置不同 成员变量:在堆内存 局部变量:在栈内存 C:生 ...

  4. Java类与类的关系、继承与多态、重写与重载

    Java类与类的关系 (1)is-a包括了 继承,实现关系 (2)has-a包括了 关联,聚合,组合关系 (3)use-a包括了 依赖关系 实现关系: 实现指的是一个class类实现interface ...

  5. Java面向对象笔记 • 【第3章 继承与多态】

    全部章节   >>>> 本章目录 3.1 包 3.1.1 自定义包 3.1.2 包的导入 3.1.3 包的访问权限 3.1.4 实践练习 3.2 继承 3.2.1 继承概述 3 ...

  6. python中继承和多态

    继承和多态 继承 引入继承 我们有这样一个需求 模仿英雄联盟定义两个英雄类 1.英雄要有昵称.攻击力.生命值属性 2.实例化出两个英雄对象 3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判断为死 ...

  7. C#中继承和多态

    1.继承的概念 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用已存在的类的功能. 为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总 ...

  8. c语言中继承和多态的简单实现

    C语言本身是不支持继承和多态的,但其实在 C 的世界里,有一套非常有名的面向对象的框架,用的也非常广,那就是 GObject,它是整个图形界面开发库 GTK 的基石,在IBM developerWor ...

  9. Java中继承与多态

    Java类的继承继承的语法结构:    [修饰符列表] class 子类名 extends 父类名{        类体;    }子类就是当前这个类,父类就是我们要复用的那个类java中只支持单继承 ...

  10. java中继承和多态的理解

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

随机推荐

  1. MESSAGE_TYPE_X in Badi:MB_DOCUMENT_UPDATE_BEFORE

    Note:385830 Instead of writing code in MB_DOCUMENT_BEFORE_UPDATE,write a check in user exit MBCF0002 ...

  2. python--事务操作

    #coding=utf-8 import sys import MySQLdb class TransferMoney(object): def __init__(self,conn): self.c ...

  3. 学习笔记《简明python教程》

    学习笔记<简明python教程> 体会:言简意赅,很适合新手入门 2018年3月14日21:45:59 1.global 语句 在不使用 global 语句的情况下,不可能为一个定义于函数 ...

  4. python程序编写简介

    语句和语法 # 注释 \ 转译回车,继续上一行,在一行语句较长的情况下可以使用其来切分成多行,因其可读性差所以不建议使用 : 将两个语句连接到一行,可读性差,不建议使用 : 将代码的头和体分开 语句( ...

  5. 代码之髓读后感——容器&并发

    容器 单个地址存放单个数据,但是如果有多个数据,而这些数据互相关联,则我们更希望的是将他们能够更好的在内存中组织在一起.于是便出现了容器的概念. 在不同的语言中,容器的名称不同,性质各异.比如,C 语 ...

  6. 【Mybatis】MyBatis配置文件的使用(二)

    本例在[Mybatis]MyBatis快速入门(一)基础上继续学习XML映射配置文件 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properti ...

  7. 无法解析的外部命令gethostname

    使用gethostname需要连接lib: #include  <winsock2.h> #pragma comment(lib, "WS2_32.lib")

  8. easyui中的option设置selected没有效果

    在mvc中,使用了easyUI框架,然后我点击添加新消息的时候弹窗一个新窗口,添加信息.却发现我的select一直无法设置默认状态,jq选中,还是直接在添加一条请选择的option都没办法选中,网络上 ...

  9. linux mysql 5.7.25 安裝

    1.下载 https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz 2.解压 tar ...

  10. qhfl-7 结算中心

    结算中心,即从购物车前往支付前的确认页面,这里要开始选择优惠券了 """ 前端传过来数据 course_list 课程列表 redis 中将要存放的结算数据 { sett ...