美文网首页深入理解Java基础Java 杂谈
【Java基本功】一文了解Java中继承、封装、多态的细节

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

作者: 程序员黄小斜 | 来源:发表于2019-01-08 19:50 被阅读3次

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

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

继承

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

  1. publicclassSonextendsFather{

  2. publicvoid go (){

  3. System.out.println("son go");

  4. }

  5. publicvoid eat (){

  6. System.out.println("son eat");

  7. }

  8. publicvoid sleep(){

  9. System.out.println("zzzzzz");

  10. }

  11. publicvoid cook(){

  12. //匿名内部类实现的多继承

  13. newMother().cook();

  14. //内部类继承第二个父类来实现多继承

  15. Mom mom =newMom();

  16. mom.cook();

  17. }

  18. privateclassMomextendsMother{

  19. @Override

  20. publicvoid cook(){

  21. System.out.println("mom cook");

  22. }

  23. }

  24. }

封装

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

类的访问范围

  1. Apublic    包内、包外,所有类中可见

  2. Bprotected包内所有类可见,包外有继承关系的子类可见

  3. (子类对象可调用)

  4. C、(default)表示默认,不仅本类访问,而且是同包可。

  5. Dprivate   仅在同一类中可见

多态

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

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

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

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

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

向上转型和向下转型:

  1. publicstaticvoid main(String[] args){

  2.    Son son =newSon();

  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 =newSon();

  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 =newFather();

  32.        Son s2 =(Son) f2;

  33.        s2.drive();

  34.        s2.smoke();

  35.        s2.play();

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

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

  38.    add(newLinkedList());

  39.    add(newArrayList());

  40.    //总结

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

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

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

  44. }

  45. publicstaticvoid add(List list){

  46.    System.out.println(list);

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

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

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

  50. }

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

编译期的静态分派

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

  1. publicstaticvoid main(String[] args){

  2.    Father father  =newSon();

  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. publicvoid smoke(Father father){

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

  16. }

  17. publicvoid play (Father father){

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

  19.    //father.drive();

  20. }

  21. publicvoid play (Son son){

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

  23.    //son.drive();

  24. }

方法重载优先级匹配

  1. publicstaticvoid 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. publicvoid eat(short i){

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

  16. }

  17. publicvoid eat(int i){

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

  19. }

  20. publicvoid eat(double i){

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

  22. }

  23. publicvoid eat(long i){

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

  25. }

  26. publicvoid eat(Character c){

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

  28. }

  29. publicvoid eat(Comparable c){

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

  31. }

  32. publicvoid 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基础 Java面试通关要点 1.面向对象的特征 封装 继承 多态 封装继承多态 2.final,final...

  • JAVA

    Java语言的特性 Java的三大特性:封装、继承、多态 封装:隐藏对象的属性和实现细节,仅对外提供公共的访问方式...

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

    本节主要介绍Java面向对象三大特性:继承 封装 多态,以及其中的原理。 本文会结合虚拟机对引用和对象的不同处理来...

  • JavaSE基础知识学习-----多态

    多态 Java面向对象编程有三大特性:封装,继承和多态封装隐藏类的内部具体实现机制,保护数据,对外界隐藏内部细节,...

  • 2020-07-08 腾讯客户端开发面试

    项目经历 java 三大特性?java 可以多继承吗?如何实现多继承?多态有哪些类型?封装,继承,多态;不可以;接...

  • Android面试

    JAVA 基础 java的特点 (OOP),封装、继承、多态 ==、equals、hashCode的作用,区别 什...

  • 面向对象三大特性

    三大特性:继承 封装 多态 继承 Java中的继承只能单继承,但是可以通过内部类继承其他类来实现多继承。 封装 封...

  • java基础系列02--面向对象

    java面向对象 封装(encapsulation) 继承(inheritance) 多态(polymorphis...

  • Java的基本特性

    关系 Java的四个基本特性分别是抽象,封装,继承,多态。概括起来可以这么理解,抽象、封装、继承是多态的基础,多态...

  • Kotlin随笔,这次坚持不太监

    Kotlin中的类与继承 Java三大特性继承、多态、封装Java学习中首先学习的是类的构建,那么必然要学习构造方...

网友评论

    本文标题:【Java基本功】一文了解Java中继承、封装、多态的细节

    本文链接:https://www.haomeiwen.com/subject/zggbrqtx.html