【Java】继承1

简介: 【Java】继承

1.为什么需要继承

说起继承大家会想起什么,想到子女继承了父母的哪些优秀品质。那就说明子女和父母一样拥有这些品质。


Java中的类是对现实事物的描述,通过对类的实例化就会产生对象。世间事物千千万万,那么有些事物一定会存在一定的联系。


比如有一个狗类,有一个猫类:


//狗类
class Dog {
    public String name;
    public int age;
    public void dogCall() {
        System.out.println(name+"汪汪汪");
    }
    public void eat() {
        System.out.println(name+"吃饭饭");
    }
}
//猫类
class Cat {
    public String name;
    public int age;
    public void catCall() {
        System.out.println(name+"喵喵喵");
    }
    public void eat() {
        System.out.println(name+"吃饭饭");
    }
}

通过观察上述的狗类和猫类,我们可以发现它们有许多相同的成员变量和成员方法


为了避免大量的重复:面向对象思想中提出了继承的概念,继承就是专门用来共性抽取,实现代码复用


2.继承的概念

继承机制:是面向对象程序设计使代码达到复用的最重要手段,它允许类在保持原有的特性上加以扩展,增加新功能,这样产生的新类就叫做派生类。


去.png


将 Dog 类 和 Cat类 的相同的成员放入一个类中 ,那么这个类就是动物类因为动物都有这些特征,狗和猫也都是动物。动物类在保持原有的特性上加以扩展,增加 Dog 的新功能,就有了 Dog 类,那么 Dog类需要继承动物类,这样 Dog 类才能继承动物类的一些成员,也就达到了代码的复用。Cat 类也是同样的道理。


Dog类 和 Cat类 都继承了 Animal类

Animal类 就称为父类 / 基类 / 超类

Dog类 和 Cat类 就称为子类 / 派生类

继承之后子类可以复用父类的成员,子类在实现时只需关心自己新增加的成员

继承:共性的抽取,实现代码复用


3.继承的语法

子类只有继承了父类,才可以复用父类的成员,那么子类应该如何继承父类呢?


通常借助 extends 关键字,来实现类之间的继承


class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public void dogCall() {
        System.out.println(name+"汪汪汪");
    }
}

这样 Dog类 也就成功继承了 Animal类


我们知道实例化一个类的时候,实例化而成的对象在堆上存放的是成员变量


当我们执行这句代码时:


Dog dog = new Dog();

实例化出来的 dog 对象在堆上存放的又该是什么咧?

请.png



我们可以通过这个解析图可以理解,当我们实例化一个 Dog 类是,dog 对象在堆里面不仅会存放自己的成员变量,还会存放继承父类的成员变量


子类会将父类中的成员变量或成员方法继承到子类中了

子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承

4.父类成员访问

子类将父类的成员继承了下来,那么子类是否可以访问继承下来的父类成员


4.1子类中访问父类的成员变量

①访问父类中与子类不同名的成员变量:直接访问


class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public String colour;
    public void dogCall() {
        name = "阿黄";
        System.out.println(name+"汪汪汪");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.dogCall();
    }
}

子类如果访问父类不同名的成员变量可以直接访问


注:


当父类的成员变量为 private 修饰时,我们知道 private 修饰的成员变量只能在同一个包中同一个文件中同一个类中使用,那么此时子类如何访问父类的成员变量了?


其.png


因为 age 成员变量是 private 修饰的,所以 age 只能在 Animal 类中使用。即使 Dog 继承了Animal 类,也不能使用


private 修饰的成员变量可以继承,但不能访问


如果想要使用 private 修饰 age 成员变量,可以在 Animal 里面写一个返回 age 的成员方法:


class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(name+"吃饭");
    }
    public int setAge(int age) {
        this.age = age;
        return this.age;
    }
}
class Dog extends Animal {
    public String colour;
    public void dogCall() {
        name = "阿黄";
        System.out.println(name+setAge(1)+"汪汪汪");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.dogCall();
    }
}


写一个返回 age 的成员方法,我们便可以使用 age 里面的值了


②访问父类中与子类同名的成员变量


class Animal {
    public String name = "阿黄";
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public String name = "阿福";
    public void dogCall() {
        System.out.println(name+"汪汪汪");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.dogCall();
    }
}

打印结果:


前.png


上述代码中父类有一个 name 成员变量,子类也有一个 name 成员变量,且它们的类型都相同。我们通过子类中的成员方法打印可以发现,打印的是子类中的 name 成员变量的值


在子类成员方法中或者通过子类对象访问成员变量时:


如果访问的成员变量子类中有,优先访问子类自己的成员变量

如果访问的成员变量子类中没有,就访问父类继承下来的成员变量。如果父类也没有,则编译报错

如果访问的成员变量与父类的成员变量同名,则优先访问子类自己的成员变量

注:成员变量的访问遵循就近原则,自己有则优先访问自己的,如果没有则向父类中找


4.2子类中访问父类的成员方法

①访问父类中与子类不同名的成员方法


class Animal {
    public String name = "阿黄";
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public String name = "阿福";
    public void dogCall() {
        eat();
        System.out.println(name+"汪汪汪");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.dogCall();
    }
}


运行结果:

我.png



当通过 子类的成员方法 或者 通过子类的对象 访问父类中与子类不同名的成员方法,则直接访问


②访问父类中与子类同名的成员方法


class Animal {
    public String name = "阿黄";
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public String name = "阿福";
    public void eat() {
        System.out.println(name+"吃狗粮");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}


运行结果:

为.png



当通过 子类的成员方法 或者 通过子类的对象 访问父类中与子类同名的成员方法,则会优先访问子类的成员方法


通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。

通过子类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法传递的参数选择合适的方法访问,如果没有则报错

那么现在就有这样一个问题了:


如果子类和父类的成员变量或成员方法相同,我们如何通过子类的成员方法,去访问与父类中与子类相同的成员变量或者成员方法呢?


5.super关键字

上面我们留下了这样一个问题,当子类与父类的成员相同时,我们如果通过子类的方法去访问,一定会访问子类的成员。 那么我们应当如何通过子类的方法去访问父类与子类相同的成员呢?


我们可以通过 super 关键字去访问父类的成员不论与子类相不相同,都可以用 super 去访问


super关键字主要作用:在子类方法中访问父类的成员


如果我们在子类中看到了 super 关键字,那么它一定是在访问父类中的成员


class Animal {
    public String name = "阿黄";
    public void eat() {
        System.out.println(name+"吃饭");
    }
}
class Dog extends Animal {
    public String name = "阿福";
    public void eat() {
        System.out.println(super.name+"吃狗粮");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}

运行结果:

五.png



我们可以看到上述的代码中在 Dog 类中的 eat 方法里面,我们打印的时候用来 super.name。那么打印的时候一定用的是父类中的 name,通过运行结果我们也可以看出来的确打印的是父类中的 name


super 关键字只能在非静态方法中使用

super 关键字在子类方法中,访问父类的成员变量和方法


相关文章
|
5月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
2月前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
126 1
|
3月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
41 3
|
3月前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
67 2
|
3月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
45 2
|
3月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
51 1
|
4月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
3月前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第4天】Java零基础教学篇,手把手实践教学!
52 2
|
3月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
36 5
|
3月前
|
Java
java继承和多态详解
java继承和多态详解
54 5