解析JavaSE的继承和多态
作者:小小茶花女 发布时间:2023-11-24 16:13:48
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、谈谈你对多态的理解?
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。
因为在程序运行时才确定具体的类,这样,不用修改源代码,就可以让引用变量绑定到各种不同的对象上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
来源:https://hengheng.blog.csdn.net/article/details/122671929
猜你喜欢
- 背景分析在项目的开发中,不管是对底层的数据逻辑操作过程,还是业务逻辑的处理过程,还是控制逻辑的处理过程,都不可避免会遇到各种可预知的、不可预
- Visual Studio 2022 默认.net framework4.8,而4.6~4.7版本的.net framework可以通过方法
- 一、链表的介绍什么是链表链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结
- 刚开始我以为熔断和降级是一体的,以为他们必须配合使用; 只不过名字不一样而已,但是当我经过思考过后,发现他们其实不是一个东西;降级什么是服务
- .c 源程序 ----- 编译 ----- 链接 ---- exe ----运行 -------->程序翻译环境和执行环境翻译环境:源
- 具体代码如下所示:***web.xml***<?xml version="1.0" encoding="
- 本文实例为大家分享了Android实现双曲线折线图的具体代码,供大家参考,具体内容如下先看一下效果图1.先下载jar包 mpandroidc
- 最近有一个java实验,要求用java使用数据库,于是本人新手小白,在idea上卡了好半天希望看到这个博客的人能解决问题,跳过一些坑首先,我
- 前言:mybatisplus 可以说是对mybatis更好的拓展,一些简单的增删改查的操作已经被作者实现,我们只需引用即可。1.数据库建表这
- 这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。使用QT的网络套接字需要.pro文件中加
- 最近碰到个需求,是希望在Unity有一个按钮,打开后直接跳转淘宝app,打开商品页面。百度了下没有相关的文章,于是我在此分享下。之前开发游戏
- Spring JPA 增加字段执行异常用Spring jpa Entity里面增加了几个字段,但启动报错,提示column Unable t
- hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们
- 本文实例讲述了java生成XML的方法。分享给大家供大家参考,具体如下:下拉框的生成,我是通过javascript读取xml文件生成的。Xm
- 本文实例为大家分享了Java实现颜色渐变效果的具体代码,供大家参考,具体内容如下RGB色彩,在自然界中肉眼所能看到的任何色彩都可以由红(R)
- 图像滤波在opencv中可以有多种实现形式自定义滤波如使用3×3的掩模:对图像进行处理.使用函数filter2D()实现#include&l
- synchronized原理在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。当我们调用某对象的synchr
- 实现功能:模拟简单登录功能,登录成功跳转新页面,登录失败在原登录界面提示登录失败信息开发环境:eclipseTomcat-8.0预备知识:H
- 命令仓库 Ctrl + Shift + A 可以搜集对应命令快捷键1、基础快捷键1.1、无处不在的跳转项目之间的跳转1.1.1、项目项目之间
- 一、interrupt的使用特点我们先看2个线程打断的示例首先是可打断的情况:@Testpublic void interruptedTes