Java基础——继承

Wesley13
• 阅读 715

extends

在java中使用extends关键字来表示继承关系。

当创建一个类时,总是在继承,如果在类中声明中没有extends关键字,就总是隐式地从java.lang.Object类继承而来的,所以Object是所有类的元类,

class 子类名称 extends 父类名称

例如:

class Person {
    public Person() {
    }
}
class Man extends Person {
    public Man() {
    }
}

(1)只允许单继承 不可以多继承
(2)允许多层继承
(3)除了Object外,所有类实际上都会存在一个父类。

super

调用父类的方法或者成员

## 修饰符

privite修饰的字段无法被子类访问

protected修饰的字段可以被子类访问

成员变量

当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量。涉及到成员变量的修饰符,具体的原则如下:

(1). 能够继承父类的public和protected成员变量;不能够继承父类的private成员变量;

(2). 对于缺省修饰符的成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

(3). 对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。

方法

(1) 能够继承父类的public和protected成员方法;不能够继承父类的private成员方法;

(2) 对于缺省修饰符的成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;

(3) 对于子类可以继承的父类成员方法,如果在子类中出现了方法名称相同的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。

(4)子类访问权限必须大于等于父类。

(5)类方法static是隐藏父类的方法。

构造器

(1)子类是不能够继承父类的构造器,但是要注意的是,如果父类的构造器都是带有参数的,则必须在子类的构造器中显示地通过super关键字调用父类的构造器并配以适当的参数列表。

如果父类有无参构造器,则在子类的构造器中用super关键字调用父类构造器不是必须的,如果没有使用super关键字,编译器会自动调用父类的无参构造器。

访问权限

Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。

可以对类或类中的成员(字段以及方法)加上访问修饰符。

  • 类可见表示其它类可以用这个类创建实例对象。
  • 成员可见表示其它类可以用这个类的实例对象访问到该成员;

protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。

设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。

如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。

字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。例如下面的例子中,AccessExample 拥有 id 公有字段,如果在某个时刻,我们想要使用 int 存储 id 字段,那么就需要修改所有的客户端代码。

public class AccessExample {

   public String id;

}

可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。

public class AccessExample {

   private int id;

   public String getId() {

       return id + "";

   }

   public void setId(String id) {

       this.id = Integer.valueOf(id);

   }

}

但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。

public class AccessWithInnerClassExample {

   private class InnerClass {

       int x;

   }

   private InnerClass innerClass;

   public AccessWithInnerClassExample() {

       innerClass = new InnerClass();

   }

   public int getValue() {

       return innerClass.x;  // 直接访问

   }

}

抽象类

1. 抽象类

抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。

抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。

super

  • 访问父类的构造函数:可以使用 super()  函数访问父类的构造函数,从而委托父类完成一些初始化的工作。应该注意到,子类一定会调用父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果子类需要调用父类其它构造函数,那么就可以使用  super 函数。
  • 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。

重写与重载

1. 重写(Override)

存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。

为了满足里式替换原则,重写有以下三个限制:

  • 子类方法的访问权限必须大于等于父类方法;
  • 子类方法的返回类型必须是父类方法返回类型或为其子类型。
  • 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。

使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。

下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:

  • 子类方法访问权限为 public,大于父类的 protected。
  • 子类的返回类型为 ArrayList,是父类返回类型 List 的子类。
  • 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
  • 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。

class SuperClass {

   protected List<Integer> func() throws Throwable {

       return new ArrayList<>();

   }

}

class SubClass extends SuperClass {

   @Override

   public ArrayList<Integer> func() throws Exception {

       return new ArrayList<>();

   }

}

在调用一个方法时,先从本类中查找看是否有对应的方法,如果没有查找到再到父类中查看,看是否有继承来的方法。否则就要对参数进行转型,转成父类之后看是否有对应的方法。总的来说,方法调用的优先级为:

  • this.func(this)
  • super.func(this)
  • this.func(super)
  • super.func(super)

/*

A

|

B

|

C

|

D

*/

class A {

   public void show(A obj) {

       System.out.println("A.show(A)");

   }

   public void show(C obj) {

       System.out.println("A.show(C)");

   }

}

class B extends A {

   @Override

   public void show(A obj) {

       System.out.println("B.show(A)");

   }

}

class C extends B {

}

class D extends C {

}

public static void main(String[] args) {

   A a = new A();

   B b = new B();

   C c = new C();

   D d = new D();

   // 在 A 中存在 show(A obj),直接调用

   a.show(a); // A.show(A)

   // 在 A 中不存在 show(B obj),将 B 转型成其父类 A

   a.show(b); // A.show(A)

   // 在 B 中存在从 A 继承来的 show(C obj),直接调用

   b.show(c); // A.show(C)

   // 在 B 中不存在 show(D obj),但是存在从 A 继承来的 show(C obj),将 D 转型成其父类 C

   b.show(d); // A.show(C)

   // 引用的还是 B 对象,所以 ba 和 b 的调用结果一样

   A ba = new B();

   ba.show(c); // A.show(C)

   ba.show(d); // A.show(C)

}

2. 重载(Overload)

存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。

应该注意的是,返回值不同,其它都相同不算是重载。

接口

Java只能单继承,无法多继承,但是实际开发中可能存在继承的问题,Java中的接口可以变相实现多重继承。

接口定义

interface接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。

从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。

接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。

接口的字段默认都是 static 和 final 的。

接口的实现

(1)接口只能继承接口 不能继承类,而且是单继承,不能继承多个接口

接口和和抽象类的对比

相同点:

(1)主要都是被其他类继承,不能创建对象 不能实例化

(2)都可以定义抽象方法 子类都必须覆写抽象方法

不同点:

(1)接口没有构造方法

(2)Java8之前接口只能有抽象方法

(3)子类只能继承一个抽象类 但是可以支持多个接口。

t

本文同步分享在 博客“羊羽”(other)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
你不可不知的JS面试题(第二期)
1、什么是继承?子类可以使用父类的所有功能,并且对功能进行扩展。新增方法改用方法(1)、ES6使用extends子类继承父类的方法。// 父类    class A        constructor(name)            this.name name;                getNa
Bill78 Bill78
3年前
Python的新式类和旧式类
概述:Python中支持多继承,也就是一个子类可以继承多个父类/基类。当一个调用一个自身没有定义的属性时,它是按照何种顺序去父类中寻找的呢?尤其是当众多父类中都包含有同名的属性,这就涉及到新式类和经典类的区别。多继承:classFood(object):23def__init__(self,name,col
Wesley13 Wesley13
3年前
Java的类继承
知识点1、继承作用:提高代码的重用性,继承之后子类可以继承父类中的属性和方法减少重复代码条件:子类和父类要满足isa的逻辑关系,才能使用继承。如:苹果isa水果语法:使用extends连接子类和父类。子类extends父类Java是单继承,一个类只能继承一个父类。子类不能继承父类私有的属性,但是可以
Stella981 Stella981
3年前
ES6中class类的extends继承
在ES6中,class之间可以通过extends进行继承:我们先定义一个父类Point:classPoint{constructor(color){this.colorcolor;}}之后再定义一个子类,让
Wesley13 Wesley13
3年前
Java基础学习总结(7)——Object类
一、Object类介绍  Object类在JAVA里面是一个比较特殊的类,JAVA只支持单继承,子类只能从一个父类来继承,如果父类又是从另外一个父类继承过来,那他也只能有一个父类,父类再有父类,那也只能有一个,JAVA为了组织这个类组织得比较方便,它提供了一个最根上的类,相当于所有的类都是从这个类继承,这个类就叫Object。所以
Wesley13 Wesley13
3年前
OCJP做完题后的一些总结。
1\.抽象类中不一定非得有抽象方法,就算没有抽象方法,编译也不会出错。2、interface继承interface用extends关键字。3、在泛型中E实现一个接口用extends关键字。4、枚举类型也可以作为HashMap中的key使用5、枚举类型也会被编译成class文件。命名格式和内部类相同。也可以被其他类调用,但
Wesley13 Wesley13
3年前
Java基础知识笔记
Java基础知识笔记6继承6继承继承是一种由已创建的类创建新类的机制,利用继承,我们先创建一个共有属性的一般类,根据一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加他自己新的状态和行为,由继承得到的类称为子类,被继承的称为父类。Java中,一个子类只能继承一个父类,不支持多重继承;1继承的基
小万哥 小万哥
9个月前
Java 继承与多态:代码重用与灵活性的巧妙结合
Java继承(子类和超类)在Java中,可以从一个类继承属性和方法到另一个类。我们将“继承概念”分为两类:子类(child):从另一个类继承的类超类(parent):被继承的类要从一个类继承,使用extends关键字。示例:javaclassVehicle