关于Java 继 承的概念及用法

本文详细介绍了Java中的继承概念,包括子类继承父类的基本语法,访问权限修饰符的作用,方法覆盖的条件,对象创建的过程,super关键字的使用,以及单继承的规则。通过示例代码阐述了如何在子类中调用父类的方法和属性,以及构造方法的调用顺序。
摘要由CSDN通过智能技术生成

1 继 承

1.1 继承的基本概念

在编程中我们通常把继承读作“子类”继承“父类”,比如说这个世界生物包括人,动物等,那么生物就是就是人、动物的父类,人和动物的属性都有生物特征的共性。

1.2 继承的基本语法

从语法上说,继承使用关键字:extends。在定义子类的时候,可以用 extends 关键字说明这个类的父类是哪一个类。代码如下:

class Animal{
    int age;
    boolean sex;
    public void eat(){
        System.out.println("Animal eat");
}
    public void sleep(){
        System.out.println("sleep 8 hours");
    }
}
class Dog extends Animal{
    public void lookAfterHouse(){
        System.out.println("look after house");

    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("catch mouse");
    }
}
public class TestDog {
    public static void main(String args[]){
        Dog d = new Dog();
        d.sex = true;
        d.age = 3;
        d.eat();
        d.lookAfterHouse();
}

我们可以看到,在代码中,使用 extends 关键字,来表明 Cat 类和 Dog 类继承自 Animal。
由于共性在父类 Animal 中,因此,在 Cat 和 Dog 中,Animal 类中已经有的代码,没有必要进行重复。

父类中的属性和方法,被子类继承之后,相当于子类中也有了相应的属性和方法。同时,子类也能够写一些子类的特性,这样,就在父类的基础上增加一些功能,体现了面向对象的可扩展性。

1.3 什么能被继承?

父类中,无法被子类访问的属性和方法,不能被继承。只有子类能够访问的属性和方法,才能够被子类继承。

1.4 访问权限修饰符

public 这个修饰符不再赘述。
private:在本类内部访问且不能被继承
protected :用 protected 修饰符修饰的属性和方法,能够被本类内部、同包的类以及非同包的子类访问。也就是能被所有的子类继承。
default :不加任何的访问修饰符(默认)如 private、public、protected,则访问权限是 default 权限。只能被本类或者同包的其他类访问。

class Student{
    int age;//default 不加任何的访问修饰符
}
四个修饰符
修饰符
访问范围

是否能被子类继承
private本类内部不能被继承
(default )本类内部+同包的其他类能被同包的子类继承
protected本类内部+同包的其他类+非同包的子类能被继承
public公开,能被所有类访问能被继承

1.5 方法覆盖

 子类中用一个特殊实现,来替换从父类中继承到的一般实现,这种语法叫做“方法覆盖”。

从语法上说,方法覆盖对方法声明的五个部分都有要求。具体来说:
1. 访问修饰符相同或更宽。如父类的方法如果是 protected 方法,子类如果想要覆盖这个方法,则修饰符至少是 protected,也可以是 public,但是不能是 default 或者 private 的。
2. 返回值类型相同。如果返回值类型不同,则会产生一个编译错误。
3. 方法名相同。这是必然的,如果方法名不同,则谈不到覆盖。
4. 参数表相同。注意的是如果不满足参数表不同,编译不出错,但是不构成方法覆盖。
5. 方法覆盖还对包括 static 修饰符的要求、对抛出的异常的要求,等等。

1.6 对象创建的过程

在有了继承关系之后,对象创建过程如下:
1. 分配空间。要注意的是,分配空间不光是指分配子类的空间,子类对象中包含的父类对象所需要的空间,一样在这一步统一分配。在分配空间的时候,会把所有的属性值都设为默认值。
2. 递归的构造父类对象。这一过程我们会在下面进一步介绍
3. 初始化本类属性。
4. 调用本类的构造方法。

结合一个具体的例子来介绍对象创建的过程。
假设有如下代码:

class A{
    int valueA = 100;
    public A(){ valueA=150; }
    }
class B extends A{
    int valueB = 200;
    public B(){ valueB=250; }
    }
class C extends B{
    int valueC = 300;
    public C(){ valueC=350; }
    }
public class TestInherit{
    public static void main(String args[]){
        C c = new C();
        
    }
}

总结一下:创建 C 对象的步骤一共有 7 步:
1. 分配空间
2. 初始化 A 类的属性
3. 调用 A 类的构造方法
4. 初始化 B 类的属性
5. 调用 B 类的构造方法
6. 初始化 C 类的属性
7. 调用 C 类的构造方法

1.7 super 关键字

在介绍对象创建的过程时,我们介绍了在创建对象时,会创建该对象的父类对象。而在创建父类对象的时候,很显然会调用父类的构造方法。但是,如果父类有多个构造方法,会调用哪一个呢?
例如下面的代码:

class Parent{
    public Parent(){
        System.out.println("Parent()");
    }
    public Parent(String str){
        System.out.println("Parent(String)");
    }
}
class Child extends Parent{
    public Child(String str){
        System.out.println("Child(String)");
    }
}
public class TestInheritConstructor{
    public static void main(String args[]){
        Child c = new Child("Hello");
    }
}

在默认情况下,创建子类对象时,都会调用父类的无参构造方法。
结果:
Parent()
Child(String)

在父类中我们定义好了带字符串参数的构造方法,要求 Java 在创建 Parent对象时,调用父类带字符串参数的构造方法。下面为大家介绍 super 关键字。super 关键字有两种不同的用法。

super 关键字用法一:super 用在构造方法上

加上一个语句:super(str):调用父类中带字符串参数的构造方法。

class Parent{
    public Parent(){
        System.out.println("Parent()");
    }
    public Parent(String str){
        System.out.println("Parent(String)");
    }
}
class Child extends Parent{
    public Child(String str){
        super(str);
        System.out.println("Child(String)");
    }
}
public class TestInheritConstructor{
    public static void main(String args[]){
        Child c = new Child("Hello");

        结果为:
                Parent(String)
                Child(String)
    }
}

要注意的是:

class Child extends Parent{
    public Child(int n){
        System.out.println("Child(int)");
    }
    public Child(String str){
        this(10);
        super(str);//编译出错
        System.out.println("Child(String)");
    }
}

1.super (参数) 指明调用父类哪个构造方法
对 super 的调用必须是构造方法中的第一个语句。 
如果第一句既不是 this(参数),也不是 super(参数),编译器会自动在这个构造方法中增加一个语句:“super();” 
this()和 super(),在构造方法中不能同时使用。

2. this (参数) 指明调用本类哪个构造方法
对 this()来说,这个语句也只能作为构造方法的第一个句。

掌握了在构造方法中如何使用 super 关键字之后,看下面这个例子。
 

class Super{
}
class Sub extends Super{
    public Sub(){}
    public Sub(String str){
        super(str);
    }//编译错误 找不到一个 Super 类中,带字符串参数的构造方法
}

如下当我们为 Super 类增加了一个字符串参数的构造方法后,编译器就不会自动生成这个无参构造方法,因此就会产生找不到 Super 类无参构造方法的错误。 

class Super{
    public Super(String str){}
}
class Sub extends Super{
    public Sub(){}//编译出错位置
    public Sub(String str){
    super(str);
    }
}

因此,如果想要让代码编译通过,必须为 Super 类增加两个构造方法。

class Super{
    public Super(String str){}
    public Super(){}
}
class Sub extends Super{
    public Sub(){}//编译通过
    public Sub(String str){
    super(str);
    }
}

super 关键字用法二:super 用作引用

super 关键字的第二种用法,就是把 super 当做是一个引用,这个引用指向父类对象。

例如创建一个 B 对象时,B 对象内部,会包含一个父类对象:A 对象。同时,B 对象内部
会有两个引用:this 和 super。其中 this 引用指向当前的 B 对象,而 super,则指向 B 对象内
部的 A 对象。内存中示意图如下:

class A{
    public void m (){

    }
}
class B extends A{
    public void m1 (){
        this.m();//this引用指向当前的B对象
    }
    public void m2(){
        super.m();//super指向B对象内部的A对象
    }
}

详细代码如下:

class Parent{
    public void m(){
        System.out.println(“m in Parent”);
    }
}
class Child extends Parent{
    public void m (){

        System.out.println(“m in Child”);
    }
    public void m1 (){
        this.m();
    }
    public void m2(){
        super.m();
    }
}
public class TestSuper{
    public static void main(String args[]){
        Child c = new Child();
        c.m1();
        c.m2();
    }    
}
输出结果为:
    m in Child
    m in Parent

super 可以调用父类被覆盖的方法,降低了代码的可读性以及可重用性。

例如,有一个 Server 类,这个类代表一个服务器。

class Server{
    public void startService(){

    }
}
class MyServer extends Server{
    public void startService(){
        super.startService();
        //保存日志的功能
    }
}

super 关键字除了可以用来调用方法之外,也可以用来指向属性。

class Parent{
    int value = 100;
}
class Child extends Parent{
        int value = 200;
    public void print(){
        int value = 300;
        System.out.println(value);//直接打印 value 变量,则局部变量优先
        System.out.println(this.value);//打印Child中的value属性
        System.out.println(super.value);//打印Parent中的value属性
    }
}
public class TestParent{
    public static void main(String args[]){
        Child c = new Child();
        c.print();
    }
}

1.8 单继承

Java 语言规定,每一个类只能有一个直接父类。这就是 Java 语言的“单继承”规则。

class A{}
class B{}
class C extends A,B{} // 编译出错,一个类不能同时有两个直接父类

对于多继承来说,一个典型的类继承关系如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江山与紫云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值