解析JavaSE的继承和多态

目录
  • 1.继承
    • 1.子类继承了父类,获得父类的全部Field和方法。
    • 2.子类继承了父类,额外增加新的Field和方法
    • 3.子类继承了父类,重写父类中的方法
    • 4.super限定,在子类调用父类中被覆盖的方法
  • 2.多态
  • 3.引用变量的强制类型转换
  • 4.面试题
    • 1、Java中实现多态的机制是什么?
    • 2、谈谈你对多态的理解?
  • 总结

1. 继承

1. 子类继承了父类,获得父类的全部Field和方法。

子类Student类继承父类,将可以获得父类的全部Field和方法

public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public static void main(String[] args) {
        Student student = new Student();
        student.name = "张三";
        student.age=18;
        // 调用父类中的show()方法
        student.show();
    }
}

2. 子类继承了父类,额外增加新的Field和方法

继承了父类中的属性和方法,同时新增一个show1()方法

public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public static void show1(){
        System.out.println("调用了子类中的show1()方法");
    }
    public static void main(String[] args) {
        Student student = new Student();
        // 调用父类中的show()方法
        student.show();
        // 调用子类中的show1()方法
        student.show1();
    }
}

3. 子类继承了父类,重写父类中的方法

1、这种子类包含与父类同名方法的现象被称为方法重写,也被称为方法覆盖(Override)。可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法。

public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public void show(){
        System.out.println("调用了子类中的show()方法");
    }
    public static void main(String[] args) {
        Student student = new Student();
        // 调用了子类中的show()方法
        student.show();
    }
}

2、注意:方法的重写要遵循“两同两小一大”规则

(1) “两同”即方法名相同、形参列表相同;

(2) “两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;

(3) “一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等;

(4) 尤其需要指出的是,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法;

 public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    // 编译报错,因为父类中的show()方法不是static修饰的,子类就不能使用static修饰
    public static void show(){
        System.out.println("调用了子类中的show()方法");
    }
}

3、注意:如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法,也就是无法重写该方法。

如果子类中定义了一个与父类private方法具有相同的方法名、相同的形参列表、相同的返回值类型的方法,依然不是重写,只是在子类中重新定义了一个新方法。

public class Person {
    public int age;
    private void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    // show()方法是private方法,子类不可以访问该方法,因此可以添加static关键字
    public static void show(){
        System.out.println("调用了子类中的show()方法");
    }
}

4、注意:当子类覆盖了父类方法后,访问的便是子类中被覆盖的方法,将无法访问父类中被覆盖的方法。

4. super限定,在子类调用父类中被覆盖的方法

1、如果需要在子类方法中调用父类被覆盖的实例方法,则可使用super限定来调用父类被覆盖的实例方法。

public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public void show(){
        System.out.println("调用了子类中的show()方法");
    }
    public void test(){
        // 调用了父类中的show()方法
        super.show();
    }
    public static void main(String[] args) {
        Student student = new Student();
        student.test();
    }
}

2、如果需要在子类方法中调用父类被覆盖的类方法,则可使用super限定来调用父类被覆盖的类方法。

public class Person {
    public int age;
    public static void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public static void show(){
        System.out.println("调用了子类中的show()方法");
    }
    public void test(){
        // 调用了父类中的show()方法
        Person.show();
    }
    public static void main(String[] args) {
        Student student = new Student();
        student.test();
    }
}

3、super是Java提供的一个关键字,super用于限定该对象调用它从父类继承得到的Field或实例方法。

正如this不能出现在static修饰的方法中一样,super也不能出现在static修饰的方法中。static修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象,因而super限定也就失去了意义。

public class Person {
    public int age;
    public void show(){
        System.out.println("调用了父类中的show()方法");
    }
}
public class Student extends Person {
    public void show(){
        System.out.println("调用了子类中的show()方法");
    }
    public void test(){
        // 调用了父类中的show()方法
        super.show();
    }
    public static void main(String[] args) {
        Student student = new Student();
        student.test();
        // 编译报错,因为super不能出现在static修饰的方法中
        super.show();
    }
}

4、如果子类定义了和父类同名的Field,则会发生子类Field隐藏父类Field的情形。

在正常情况下,子类里定义的方法默认会访问到子类中定义的Field,无法访问到父类中被隐藏的Field,在子类定义的实例方法中可以通过super来访问父类中被隐藏的Field

public class Person {
    public int age=5;
}
public class Student extends Person {
    private int age = 10;
    public void getOwner(){
        System.out.println(age);
    }
    public void getBase(){
        System.out.println(super.age);
    }
    public static void main(String[] args) {
        Student student = new Student();
        // 10
        student.getOwner();
        // 5
        student.getBase();
    }
}

如果在某个方法中访问名为age的Field,但没有显式指定调用者,则系统查找a的顺序为:

(1) 查找该方法中是否有名为age的局部变量;

(2) 查找当前类中是否包含名为age的Field;

(3) 查找age的直接父类中是否包含名为age的Field,依次上溯age的所有父类,直到java.lang.Object类,如果最终不能找到名为age的Field,则系统出现编译错误。

5、子类不会获得父类的构造器,但子类构造器里可以调用父类构造器的初始化代码

(1) 在一个构造器中调用另一个重载的构造器使用this调用来完成,在子类构造器中调用父类构造器使用super调用来完成;

(2) 如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的Field,而不是该类自己定义的Field;

public class Person {
    public String name;
    public int age;
    public Person(String name){
        this.name = name;
    }
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
}
public class Student extends Person {
    private String color;
    // super调用的是其父类的构造器,而this调用的是同一个类中重载的构造器
    // 使用super调用父类构造器也必须出现在子类构造器执行体的第一行,所以this调用和super调用不会同时出现
    public Student(String name,int age){
        super(name);
        this.age = age;
    }
    public Student(String name,int age,String color){
        // 通过super调用父类构造器完成初始化过程
        this(name,age);
        this.color = color;
    }
    public static void main(String[] args) {
        Student student = new Student("张三",18,"红色");
    }
}

2. 多态

Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

public class Parent {
    public int book=10;
    public void test(){
        System.out.println("父类中的test()方法");
    }
    public void parent(){
        System.out.println("父类中的parent()方法");
    }
}
public class Sun extends Parent {
    public String book = "这是一本好书";
    public void test(){
        System.out.println("子类中的test方法");
    }
    public void sun(){
        System.out.println("子类中的sun方法");
    }
    public static void main(String[] args) {
        // 编译时类型和运行时类型一致,不存在多态
        Parent parent = new Parent();
        // 10
        System.out.println(parent.book);
        // 父类中的test()方法
        parent.test();
        // 父类中的parent()方法
        parent.parent();
        // 编译时类型和运行时类型一致,不存在多态
        Sun sun = new Sun();
        // 这是一本好书
        System.out.println(sun.book);
        // 子类中的test方法
        sun.test();
        // 子类中的sun方法
        sun.sun();
        // 编译时类型和运行时类型不一致,存在多态
        // p变量的编译时类型是Parent,而运行时类型是Sun
        Parent p = new Sun();
        // 对象的Field则不具备多态性
        // 10
        System.out.println(p.book);
        // 子类中的test方法
        p.test();
        // 父类中的parent()方法
        p.parent();
        // Parent类中没有sun()方法,编译报错
        p.sun();
    }
}

当把一个子类对象直接赋给父类引用变量时,例如上面的Parent p = new Sun();,这个p引用变量的编译时类型是Parent,而运行时类型是sun :

(1) Java允许把一个子类对象直接赋给一个父类引用变量,无须任何类型转换,这种被称为向上转型,向上转型由系统自动完成;

(2) 当调用该引用变量的test方法时,实际执行的是Sun类中覆盖后的test方法,这就是多态;当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就可能出现:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态。

(3) 与方法不同的是,对象的Field则不具备多态性,通过引用变量来访问其包含的实例Field时,系统总是试图访问它编译时类型所定义的Field,而不是它运行时类型所定义的Field;

3. 引用变量的强制类型转换

编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,如果需要让这个引用变量调用它运行时类型的方法,则必须把它强制类型转换成运行时类型。

(1) 基本类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括整数型、字符型和浮点型。但数值类型和布尔类型之间不能进行类型转换。

(2) 引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。

考虑到进行强制类型转换时可能出现异常,因此进行类型转换之前应先通过instanceof运算符来判断是否可以成功转换。

(1) instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类或者接口,它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false;

(2) 在使用instanceof运算符时需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误;

(3) instanceof运算符的作用是:在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,从而保证代码更加健壮;

(4) instanceof和(type)是Java提供的两个相关的运算符,通常先用instanceof判断一个对象是否可以强制类型转换,然后再使用(type)运算符进行强制类型转换,从而保证程序不会出现错误;

public class Main {
    public static void main(String[] args) {
        Object object = "hello";
        if(object instanceof String){
            String s = (String) object;
        }
    }
}

4. 面试题

1、Java中实现多态的机制是什么?

Java中的多态靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

2、谈谈你对多态的理解?

多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。

因为在程序运行时才确定具体的类,这样,不用修改源代码,就可以让引用变量绑定到各种不同的对象上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • java继承学习之super的用法解析

    继承supersuper关键字的用法和this关键字的用法相似this:代表本类对象的引用super:代表父类存储空间的标识(可以理解为父类对象引用) package com.ithema_20; /*   测试类   继承   super   super关键字的用法和this关键字的用法相似   this:代表本类对象的引用   super:代表父类存储空间的标识(可以理解为父类对象引用)  */ public class Demo {     public static void main(

  • Java面向对象之类的继承介绍

    目录 继承的作用 如果没有继承机制是怎么样的? 使用继承机制后的示例? 类的继承是什么? 子类和父类的继承机制 Java单继承 Java继承的顶级父类:Object 对象的类型转换 对象向上转型 对象向下转型 总结 继承的作用 如果没有继承机制是怎么样的? 有以下两个类,分别是Student.Teacher,它们的实现类如下: /** * 老师类 封装了姓名.年龄 * * @author Administrator * */ public class Teacher { private Stri

  • Java继承与多态的正确打开方式

    目录 一.概述 二.继承 2.1 继承的概述 2.2 继承机制 2.3 类中属性,方法的继承与覆盖 1.属性的继承与覆盖 2.方法的继承与覆盖 2.4 super 关键字 三. 多态 总结 一.概述 面向对象程序设计的三大原则是封装性,继承性和多态性.继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的.继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用.而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消

  • JAVA面向对象之继承 super入门解析

    目录 1 继承 1.1概念 1.2 特点 1.3 练习:继承入门案例 2 super 3 继承的用法 3.1 练习:super之继承中成员变量使用 3.2 练习:super之继承中构造方法的使用 4 方法重写Override 4.1 练习:继承中成员方法的使用 5 拓展 5.1 继承的好处与坏处 5.2 this与super的区别 5.3 重载Overload与重写Override的区别 1 继承 1.1概念 继承是面向对象最显著的一个特征 继承是从已有的类中派生出新的类,新类能吸收已有类的数据

  • Java中的接口多继承机制

    目录 问题原因 一个接口可以同时继承多个接口 接口不能实现任何接口 一个类可以实现多个接口 一个类只能继承一个父类 总结: 问题原因 今天在看集合源码的时候,突然看到接口继承接口,觉得有点差异,以前写代码也就是类继承一个类,实现接口.这样写的多了,突然看到接口继承接口就有点诧异了,以为哪里不对.就测试,查阅了一些资料 一个接口可以同时继承多个接口 书写接口测试 public interface Jiekou extends Jiekou1,Jiekou2{ void jiekou(); } pu

  • 浅谈Java封装、继承、多态特性

    目录 1.封装 2.继承 3.多态 4.上代码,效果运行放在最后 1.封装 什么是封装,谈谈自己对封装的理解,封装就是将类的信息(比如说类的属性)隐藏在类的内部,不允许外部程序直接访问.此时就要提到一个关键字private,他是一个权限修饰符,可以用来修饰成员(变量和方法),保护成员不被其他别的类来使用,如果需要被其他类来使用,那么需要提供对应的操作:a.提供get变量名()方法,用于获取成员变量的值 b.提供set变量名(参数),用于设置成员变量的值,同样也和get方法一样,都是用public

  • Java由浅入深刨析继承

    目录 继承 继承的介绍 生活中的继承 继承的好处 继承的格式 继承的demo 子类不能继承的内容 super与this关键字 构造器不能被继承 final修饰的类不能被继承 方法重写 介绍 使用场景与案例 @Override重写注解 注意事项 完结 茫茫人海千千万万,感谢这一秒你看到这里.希望我的面试题系列能对你的有所帮助!共勉! 愿你在未来的日子,保持热爱,奔赴山海! Java基础知识(继承) 继承 继承的介绍 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类.描述的是事

  • 详解Java的继承

    目录 继承: 继承的好处: 继承的坏处: 继承的特点: 继承和成员变量之间的关系: this关键字和super关键字的区别 方法的重写: 总结 继承: 把多个类相同的内容提取到另外一个类中,然后使用关键字extends来实现继承 继承的好处: 1.提高了代码的复用性 2.提高了代码的维护性 只需要修改父类的内容 3.让类与类之间产生了继承关系,为了后面的多态做铺垫,要有继承才能做多态 继承的坏处: 1.类的耦合性增强了,一个父类改变了,子类也跟着改变 2.只可以单个继承,不可以多个继承,可以多层

  • java面向对象继承与多态介绍

    目录 一.概述 二.继承 2.1 继承的概述 2.2 继承机制 2.3 类中属性,方法的继承与覆盖 2.4 super 关键字 三. 多态 总结 一.概述 面向对象程序设计的三大原则是封装性,继承性和多态性.继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的.继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用.而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消息主要是对类成员函数的调用,而不同的行为是指

  • 解析JavaSE的继承和多态

    目录 1.继承 1.子类继承了父类,获得父类的全部Field和方法. 2.子类继承了父类,额外增加新的Field和方法 3.子类继承了父类,重写父类中的方法 4.super限定,在子类调用父类中被覆盖的方法 2.多态 3.引用变量的强制类型转换 4.面试题 1.Java中实现多态的机制是什么? 2.谈谈你对多态的理解? 总结 1. 继承 1. 子类继承了父类,获得父类的全部Field和方法. 子类Student类继承父类,将可以获得父类的全部Field和方法 public class Perso

  • Python类继承和多态原理解析

    这篇文章主要介绍了python类继承和多态原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 现在属于是老年人的脑子,东西写着写着就忘了,东西记着记着就不知道了.之前学C++的时候就把类.对象这块弄得乱七八糟,现在是因为很想玩python,所以就看看python的类和对象. 就像说的,类有三个特征:封装.继承.多态. 1.封装:类封装了一些方法,可通过一定的规则约定方法进行访问权限. C++中的成员变量有public.private.pto

  • Java面向对象编程之继承和多态以及包的解析与使用范例

    目录 1.继承 1.1继承的基本使用 1.2 protected 关键字 1.3 final 关键字 2.多态 2.1向上转型 2.2动态绑定 2.3方法重写 2.4向下转型 2.5super 关键字 2.5.1 super 关键字的基本用法 2.5.2 this和super的区别 3.包的使用 3.1导入包中的类 3.2常见系统包 1.继承 为什么要有继承? 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中, 那么多个类无需再定义这些属性和行为,只要继承那个类即可. 此处的多个类称为

  • javascript 面向对象全新理练之继承与多态

    1 又是几个基本概念 为什么要说又呢? 在讨论继承时,我们已经列出了一些基本概念了,那些概念是跟封装密切相关的概念,今天我们要讨论的基本概念,主要是跟继承与多态相关的,但是它们跟封装也有一些联系. 1.1 定义和赋值 变量定义是指用 var a; 这种形式来声明变量. 函数定义是指用 function a(...) {...} 这种形式来声明函数. var a = 1; 是两个过程.第一个过程是定义变量 a,第二个过程是给变量 a 赋值. 同样 var a = function(...) {};

  • C语言实现C++继承和多态的代码分享

    这个问题主要考察的是C和C++的区别,以及C++中继承和多态的概念. C和C++的区别 C语言是面向过程的语言,而C++是面向对象的过程. 什么是面向对象和面向过程? 面向过程就是分析解决问题的步骤,然后用函数把这些步骤一步一步的进行实现,在使用的时候进行一一调用就行了,注重的是对于过程的分析.面向对象则是把构成问题的事进行分成各个对象,建立对象的目的也不仅仅是完成这一个个步骤,而是描述各个问题在解决的过程中所发生的行为. 面向对象和面向过程的区别? 面向过程的设计方法采用函数来描述数据的操作,

  • C++中继承与多态的基础虚函数类详解

    前言 本文主要给大家介绍了关于C++中继承与多态的基础虚函数类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 虚函数类 继承中我们经常提到虚拟继承,现在我们来探究这种的虚函数,虚函数类的成员函数前面加virtual关键字,则这个成员函数称为虚函数,不要小看这个虚函数,他可以解决继承中许多棘手的问题,而对于多态那他更重要了,没有它就没有多态,所以这个知识点非常重要,以及后面介绍的虚函数表都极其重要,一定要认真的理解~ 现在开始概念虚函数就又引出一个概念,那就是重写(覆

  • C语言模拟实现C++的继承与多态示例

    一.面向过程编程与面向对象编程的区别 众所周知,C语言是一种典型的面向过程编程语言,而C++确实在它的基础上改进的一款面向对象编程语言,那么,面向过程与面向对象到底有什么样的区别呢? [从设计方法角度看] 面向过程程序设计方法采用函数(或过程)来描述对数据的操作,但又将函数与其操作的数据分离开来. 面向对象程序设计方法是将数据和对象的操作封装在一起,作为一个整体来处理. [从维护角度看] 面向过程程序设计以过程为中心,难于维护. 面向对象程序设计以数据为中心,数据相对功能而言,有较强的稳定性,因

  • java 中继承和多态详细介绍

    继承和多态 一.this super关键字 1.this: 可以在构造器中的第一代码中调用本类中的其他构造器.this(参数) 非类方法参数中隐式传入的参数,表示调用当前方法的对象. 2.super: 可以在构造器的第一句代码调用父类的构造器.super(参数). 非静态方法中表示继承的父类对象,可以调用父类方法和属性. 二.方法的覆写: 子类重新实现了和父类一样的方法.访问修饰和异常都必须至少和父类的相同或者更大的范围. 三.方法的重载: 相同的方法的名字不同的参数列表. 四.多态: java

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

    面向对象有封装.继承.多态这三个特性,面向对象编程按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成任务.这种编程方法提供了非常强大的多样性,大大增加了代码的重用机会,增加了程序开发的速度,将具备独立性特制的程序代码包装起来,修改部分程序代码时不至于会影响到程序的其他部分. 1.封装 每个对象都包含它进行操作所需要的所有信息,封装只公开代码单元的对外接口,而隐藏其具体实现,尽量不对外公开代码.使用封装有很多好处,从设计角度来讲,封装可以对外屏蔽一些

  • Java 继承与多态的深入理解

    Java 继承与多态的深入理解 1.  什么是继承,继承的特点? 子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类更具体.父类具有更一般的特征和行为,而子类除了具有父类的特征和行为,还具有一些自己特殊的特征和行为. 在继承关系中.父类和子类需要满足is-a的关系.子类是父类. 表示父类和子类的术语:父类和子类.超类和子类.基类和派生类,他们表示的是同一个意思. 2.  为什么需要继承?什么时候应该

随机推荐