【面向对象编程】继承

2024-09-24 13:32:49 浏览数 (2)

1.为什么需要继承

在编程中,继承可以实现代码的复用,减少重复编写代码的工作量。通过继承,子类可以继承父类的属性和方法,并且可以根据需要进行扩展和修改,提高了代码的可维护性和可扩展性。再例如现实世界的复杂性,但事物之间存在某种共性,那么程序设计就需要考虑

例如

代码语言:javascript复制
public class test1 {
    public static void main(String[] args) {
        Dog dog=new Dog();
        dog.eat();
        dog.run();
        Cat cat=new Cat();
        cat.eat();
        cat.sleep();
    }
}
class Dog{
    public void eat(){
        System.out.println("吃饭");
    }
    public void run(){
        System.out.println("狗狗正在跑");
    }
}
class Cat{
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("猫猫正在睡觉");
    }
}

在狗和猫之间有共性即吃饭,如果共性很多时候,我们每个类都要加入对应的方法,所以我们就可以设置一个类来存储共性,让猫和狗继承它就会使的代码更简便。

2.继承的概念

继承允许创建一个新的类(称为子类派生类),它允许保持原有的特性的基础上进行扩展,增加新功能。该类基于另一个已存在的类(称为父类基类或超类)。子类继承了父类的属性(数据成员)和方法(成员函数)。这意味着子类无需重新定义父类中已有的属性和方法,就可以直接使用它们。解决问题:共性的抽取,实现代码复用。

3.继承的语法

如果子类要继承父类,那么就要加关键词extends。

代码如下:

代码语言:javascript复制
class Animal{
    public void eat(){
        System.out.println("吃饭");
    }
}
class Dog extends Animal{
    public void run(){
        System.out.println("狗狗正在跑");
    }
}

当将共性写在父类时,代码就显得更加简洁。

注意:如果子类继承父类之后,不添加自己的特有成员(成员变量,成员方法),与基类相同,就没有必要继承了。

4.成员访问

1.子类与父类不存在同名的时候:在子类中可以使用父类指定的成员,或者自己的。

代码如下:

代码语言:javascript复制
class son extends father{
    int a;
    public void sum(){
        a=1;
        b=2;
    }
}
class father{
    int b;
}

子类没有b的变量,但是继承后就任然使用。

2.子类与父类的成员同名的时候:如果访问的变量在子类中存在,就访问子类的成员变量,如果没有,就在父类里面找,如果还是没有编译器就报错。

代码语言:javascript复制
  public static void main(String[] args) {
        son s=new son();
        System.out.println(s.b);
        s.a();
    }
}
class son extends father{
    String b="这是子类的成员变量";
    public void a(){
        System.out.println("这是子类的成员方法");
    }
}
class father{
    String b="这是父类的成员变量";
    public void a(){
        System.out.println("这是父类的成员方法");
    }
}

代码输出:这是子类的成员变量                   这是子类的成员方法

5.super关键字

在上述中代码中,当子类与父类的成员变量,或者成员方法名一样时,如何使用父类的呢?

这里就要用super关键字。

super关键字的作用:在子类或者父类存在成员名相同时,可以使用super在子类中访问父类的成员变量,或者成员方法。

代码语言:javascript复制
class son extends father{
    String b="这是子类的成员变量";
    public void a(){
        System.out.println("这是子类的成员方法");
    }
    public void b(){
        System.out.println(super.b);
        super.a();
    }

}
class father{
    String b="这是父类的成员变量";
    public void a(){
        System.out.println("这是父类的成员方法");
    }
}

输出结果:这是子类的成员变量                   这是子类的成员方法                   这是父类的成员变量                   这是父类的成员方法

注意:super只能在非静态方法中使用。 

6.子类构造方法

子类对象构造时,先调用父类的构造方法,在执行子类的构造方

代码语言:javascript复制
public class test3 {
    public static void main(String[] args) {
        Son son=new Son();
    }
}
class Son extends Father{
    public Son(){
        System.out.println("子类的构造方法");
    }
}
class Father{
    public Father(){
        System.out.println("父类的构造方法");
    }
}

输出结果: 父类的构造方法 子类的构造方法

 在子类构造方法中没有写父类的构造的代码,但是在构造子类的对象时,会自动执行父类的构造方法,然后执行子类的构造方法。

注意:

1.在父类构造默认或者无参的构造方法的时候,在子类的构造方法的第一行会默认加super().

2.如果父类时带有参数的构造函数,那么子类需要显示定义构造方法。

代码语言:javascript复制
public class test4 {
    public static void main(String[] args) {
            Sub sub = new Sub(2,3);
            System.out.println(sub.calculate());
        }
    }
class Base {
    private int x;
    public Base(int x) {
        this.x = x;
    }
    public int getX() {
        return x;
    }
}
class Sub extends Base {
    private int z;
    public Sub(int x, int z) {
        super(x);
        this.z = z;
    }
    public int calculate() {
        return super.getX()*z;
    }

}

7.super和this

相同:

都只能在非静态方法中使用,用来访问非静态成员防范和变量。

必须是构造方法中的第一条语句,并且不能同时存在。

不同点:

this是当前对象的引用,super是子类对象中对父类继承下来的引用。

this用来访问本类的方法和属性,super是访问的是父类继承下来的方法和属性。

在构造方法中,this用于调用本类的构造方法,super用来调用父类的构造方法,且两者不能同时出现构造方法中。

8.再谈初始化

静态代码块先执行,并且只执行一次,在类加载阶段执行。

当对象创建时,才执行实例代码块,实例代码块执行完成后才执行构造方法。

代码语言:javascript复制
public class test3 {
    public static void main(String[] args) {
        testDemo t=new testDemo();
        System.out.println("----------------");
        testDemo t1=new testDemo();
    }
}
class testDemo{
    public testDemo(){
        System.out.println("这是构造方法");
    }
    {
        System.out.println("这是实例代码块");
    }
    static {
        System.out.println("这是静态代码块");
    }
}

输出: 这是静态代码块 这是实例代码块 这是构造方法 ---------------- 这是实例代码块 这是构造方法

 如图所示,静态代码块执行完一次后就不执行了。

并且存在子类继承父类时,父类的静态代码块最先执行,然后是子类的静态代码块,父类的实例代码块和构造方法再执行,最后是子类的实例代码块和构造方法。

9.protect关键字

protect关键字可用于,同一包中的同一类和不同类,以及不同包中的子类。

如图所示,protect只能用于同一包中,和不同包中的子类,由于小编在这里无法展示,不同包的情况,请见谅。

10.继承方式

单继承:

class A<------class B

多层继承:

class A<------class B<-----class C

不同类继承同一个类:

 class A<------class B class A<------class C

 多继承

class A<------class B class C<------class B(注意:在java中不支持多继承)

11.final关键字 

1. 修饰变量: 当 final 修饰基本数据类型的变量时,该变量的值一旦被初始化就不能被修改。 当 final 修饰引用数据类型的变量时,该变量所引用的对象地址不能被改变,但对象的内容可以改变。 2. 修饰方法: 被 final 修饰的方法不能被重写,这确保了方法在继承体系中的行为是固定的。 3. 修饰类: 被 final 修饰的类不能被继承,意味着这个类的功能是完整且不可扩展的。

在修饰变量时:

final int a=10; a=20;//编译报错

在修饰时类时:

final class A{ } class B extends A{} //编译报错,

 final修饰类时,表示该类不应被继承;

在修饰方法时:

代码语言:javascript复制
class A extends B{
    public void func(){
       //报错,不能被重写。
    }
}
class B{
   public final void func(){
       
   }
}

该方法不能被重写;

12.总结

限于小编能力有限,可能总结不是很到位,希望各位uu给出宝贵意见。

如果觉得小编写的还不错的话,麻烦给小编一个小小的赞吧

0 人点赞