目录
首先我要恭喜你刷到我啦,一起来通篇学习继承吧!
1.继承概述
继承是面向对象编程的三大特征之一。继承让我们更加容易实现类的扩展。实现代码的重用,不用再重新发明轮子(don’t reinvent wheels)。
继承有两个主要作用:
- 代码复用,更加容易实现类的扩展
- 方便建模
2.继承的实现
上图中的动物就好比我们java中的Object类,如果一个类没有明确继承另一个类的时候,那么它就是Object类的子类。它属于java.lang包中的类,而我们lang包的东西在每次编写java代码程序的时候都会默认导入到每个程序中,所以在java中关于形如(类名 extends Object)的写法就可以省略不写。
3.进入实操
3.1认识一开始的继承
public class TestExtends {
public static void main(String[] args) {
new ChildClass();
}
}
//定义父类方法
class FatherClass extends Object{
//Object是java中所有子类的父类,此处的继承是系统默认的,可省略
String name;
int age;
public FatherClass(){
super();
name = "李华";
age = 30;
System.out.println("Father的age是:"+age);
System.out.println("Father的name是:"+name);
}
}
定义子类方法
class ChildClass extends FatherClass{
String name;
int age;
public ChildClass(){
super();
System.out.println("child的name是:"+name);
System.out.println("child的age是:"+age);
}
}
那对于这段代码的执行顺序会是什么呢?
首先:程序会进入含有main()函数的程序入口,发现直接new了一个新的子类对象进行输出
而子类ChildClass继承了父类的方法和属性:
(1)方法体的第一句调用了super();语句。该语句介绍如下:
①可以看作直接父类对象的引入。我们可以通过super来访问被子类覆盖的方法和属性。
②通过super调用普通方法和属性没有访问权限可以随便调用。
③预先创建一个子类对象,我们一定会在此之前创建出来一个父类的对象,因为在继承过程中我们一定会首先加载父类信息的。
到这里运行结果就出来了:
那么问题来了:我们为什么要在子类中重新再定义name属性的变量呢?它不是可以继承父类的那name吗?
其实这就是我们所说的继承了,当我们注释掉重新定义的name时,name就会自动继承父类的属性值进行输出。
3.2instanceof方法
instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。比如:
【示例】使用instanceof运算符进行类型判断
public class TestInstanceof {
public static void main(String[] args) {
System.out.println(cc instanceof FatherClass);
System.out.println(cc instanceof Object);
}
}
class FatherClass extends Object{
public FatherClass(){
System.out.println("父类");
}
}
class ChildClass extends FatherClass{
public ChildClass(){
super();
System.out.println("子类");
}
}
运行结果:
4. 继承使用要点
- 父类也称作超类、基类。 子类:派生类等。
- Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
- Java中类没有多继承,接口有多继承。
- 子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
- 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。
5. 重写(Override)
public class TestOverride {
public static void main(String[] args) {
Child c = new Child();
Child2 c2 = new Child2();
c.run();
c2.run();
}
}
class Father{
public void run(){
System.out.println("我将要被重写!");
}
}
class Child extends Father{
public void run(){
super.run();
System.out.println("我被重写了!");
System.out.println("------------");
}
}
class Child2 extends Father{
@Override
public void run() {
System.out.println("我被第二次重写!");
}
}
运行结果:
子类重写父类的方法,可以用自身行为替换父类行为。重写是实现多态的必要条件。
5.1方法重写需要符合下面的三个要点:
= =
:方法名、形参列表相同。≤
:返回值类型和声明异常类型,子类小于等于父类。≥
:访问权限,子类大于等于父类。
6. 继承中的final关键字
6.1final关键字的作用:
-
修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
final int MAX_SPEED = 120;
-
修饰方法:该方法不可被子类重写。但是可以被重载!
final void study(){}
-
修饰类: 修饰的类不能被继承。比如:Math、String等。
final class A {}
final修饰类如图所示。
7.继承与组合
7.1初始代码演示
package com.Extends;
public class ExtendsCombine {
public static void main(String[] args) {
Person p = new Person();
p.age = 18;
p.name = "码子哥";
Student s = new Student(p,"程序员");
s.print();
}
}
class Person{
String name;
int age;
public void rest(){
System.out.println("是人都需要休息!");
}
}
class Student{
Person person;
String major;
public Student(Person person, String major) {
/*
* 在此处我们的参数直接调用了一个Person的对象
* 相当于构造函数:
* public Student(String name,int age,String major)
* */
this.person = person;
this.major = major;
}
public void print(){
System.out.println("这个学生的名字是:"+this.person.name+"\n芳龄是:"+this.person.age+"\n职业是:"+major);
}
}
当我们在Student中初始化新对象的时候,Students就已经可以调用Person中的属性了,其实这也不难理解,我们初始化了一个对象,这个对象中的属性当然就能被我们随意调用啦。这样的调用被我们称之为组合,组合弥补了继承中很大一部分代码复用中没有补全的问题。
组合比较灵活。继承只能有一个父类,但是组合可以有多个属性。所以,有人声称“组合优于继承,开发中可以不用继承”,但是,不建议大家走极端。
对于is -a
关系建议使用继承,has-a
关系建议使用组合。
比如:上面的例子,Student is a Person这个逻辑没问题,但是:Student has a Person就有问题了。这时候,显然继承关系比较合适。
再比如:笔记本和芯片的关系显然是has-a
关系,使用组合更好。
8.toString方法
在这里我们还需要了解Object中toString的方法:那就跳转我另一篇文章吧!
toString()方法的概念、应用、重写toString方法_程序员不需要码子的博客-CSDN博客
那么到这里我们继承涉及到的内容就这么多啦!
后续我会持续更新java学习中几乎所有我们用到的知识点,如果对我的内容存在疑问就评论告诉我,我会第一时间回复。
满意的话请关注点赞支持!有任何需要私下解决的问题还请私信我!
本内容通篇原创,盗用必究!