【一步一步了解Java系列】:子类继承以及代码块的初始化

简介: 【一步一步了解Java系列】:子类继承以及代码块的初始化

看到这句话的时候证明:此刻你我都在努力

加油陌生人

2.png

继承的概念以及继承存在的意义

Java中的继承是一种面向对象编程(OOP)的基本概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。继承提供了一种机制,使得子类可以扩展或修改父类的行为。

意义:

首先,继承是面向对象编程的核心特性之一,它体现了面向对象设计的原则,如封装、抽象、继承和多态。其次继承可以提高代码的复用率,让子类继承运用到父类的一些数据和方法。还可以实现多态,使一个接口呈现不同的功能实现。还有实现程序的扩展性可以在一个代码的基础上进行扩展等等功能。当然继承还有好多意义,这里使列举不完的。

子类继承

讲到继承我们首先还是先了解子类,那么子类和父类如何分辨,还有如何继承,接下来都会讲到,我们先看一下下面的代码:

在这段代码中Animal为父类,Dog是子类,首先我们在生活中的逻辑上就是狗一定是动物,而动物不一定是狗,这就说明动物的范围更大,所以Animal是父类,Dog是子类。然后再从语法上分析,首先我们看到extends这个关键字,那么这个就代表继承,那么我们看到一个类使用了这个关键字就说明它就是这个关键字后面那个类的子类,extends后面的就是父类。比如: ** class Dog extends Animal{}**,那么Dog就为子类,Animal就是父类。

public class Animal {
    String type;
    int age;


    public void eat(){
        System.out.println("吃食物");
    }

    public void speak(){
        System.out.println("发出叫声");
    }

}


class Dog extends Animal{
   String name;
   public Dog(String name){
       type="狗";

       this.name=name;
       System.out.println("他是一只"+type+" 它的名字为:"+name);

   }

    public static void main(String[] args) {
        Dog dog=new Dog("旺财");
        dog.speak();
        dog.eat();

    }

        }

然后我们从上面的代码中也是发现子类能够使用父类的成员变量或给其赋值,也可以调用父类的成员方法


然后我们进入到第二个知识点:如果父类中包含构造方法时,子类要不要也定义一个构造方法,如何构造?那会不会与父类的构造方法冲突呢?我们接下来往下看:

public class Animal {
    String type;
    int age;
public Animal(String type,int age){

    this.type=type;
    this.age=age;

}

    public void eat(){
        System.out.println("吃食物");
    }

    public void speak(){
        System.out.println("发出叫声");
    }

}


class Dog extends Animal{
    String name;

    public Dog(String type, int age, String name) {
        super(type, age);
        this.name = name;
    }

    public static void main(String[] args) {

        Dog dog=new Dog("狗",2,"旺财");
        System.out.println("他是一只"+dog.type+" 它的名字为:"+dog.name);
        dog.speak();
        dog.eat();

    }

}


如上:我们这次在父类加上构造方法,那么我们就必须在子类里先完成父类的构造方法,否则编译器会报错

那么该如何正确的定义子类的构造方法呢?

那就是像上面的代码一样使用super关键字。

那么接下来我们就来了解一下super关键字。

super

super关键字,在我现学的阶段有两个作用

  1. 访问父类成员:当你在子类中重写了父类的方法或访问了父类的属性时,你可以使用super来明确地调用父类中的版本。例如:
复制
class Parent {
    void show() {
        System.out.println("Parent's show()");
    }
}

class Child extends Parent {
    void show() {
        super.show(); // 调用父类的show()方法
        System.out.println("Child's show()");
    }
}
  1. 调用父类的构造方法:在子类的构造方法中,你可以使用super()来调用父类的构造方法。这通常在构造方法的第一行进行,以确保在子类对象的初始化过程中,父类的状态也被正确地初始化。
class Parent {
    Parent() {
        System.out.println("Parent's constructor");
    }
}

class Child extends Parent {
    Child() {
        super(); // 调用父类的构造方法
        System.out.println("Child's constructor");
    }
}


第二点就是我所说的可以调用父类构造方法,注意super的调用必须在第一位。

然后现在回过头来是不是就发现上面的代码就可以理解了


super和this的对比

相同点:

  1. 都是Java中的关键字。
  2. 都只能在类的非静态方法里使用,用来访问类的非静态成员方法或成员变量。
  3. 他们都要放在方法的第一句,这就注定他们不能同时出现在一个方法里。

不同点:

this关键字

  • this指的是当前对象的引用。
  • 它用于当前对象的方法或构造方法中,来引用当前对象的成员(属性、方法)。
  • this可以用来调用当前类的其他构造方法(使用this()语法)。
  • this可以用来区分成员变量和局部变量,当它们具有相同的名称时。

示例:

class Example {
    int value;
    
    Example(int value) {
        this.value = value; // 使用this来引用当前对象的成员变量
    }
    
    void setValue(int value) {
        this.value = value; // 使用this来明确区分成员变量和参数
    }
}

super关键字

  • super指的是当前对象的直接父类对象的引用。
  • 它用于访问父类的成员,特别是当子类重写了父类的方法或变量时。
  • super用于调用父类的构造方法(使用super()语法)。
  • super可以用来引用父类的类型,这在泛型和继承中特别有用。

示例:

class Parent {
    void show() {
        System.out.println("Parent's show()");
    }
}

class Child extends Parent {
    void show() {
        super.show(); // 调用父类的方法
    }
    
    Child() {
        super(); // 调用父类的构造方法
    }
}

总结区别:

  • this是指向当前对象的引用。
  • super是指向当前对象的父类对象的引用。
  • this用于引用当前类的成员或调用其他构造方法。
  • super用于引用父类的成员或调用父类的构造方法。
  • this通常用于当前类的作用域内。
  • super通常用于子类中,与父类交互。


代码块的初始化与构造方法实现的先后顺序

那么现在我们了解一下代码块。代码块分为静态代码块和示例代码块,总所周知代码块和构造方法都可以给对象的成员赋值,那么他们赋值的顺序我们真的了解吗?接下来我们就可以来探索一下。

静态代码块

说到静态那么我们肯定要有static关键字了,我们来看一下这段代码:

中间的static的花括号里的就是静态代码块。

实例代码块

这样一个单独的花括号,或者没有花括号都算是实例代码块。


然后构造方法大家都是知道的。

public Test(){

    System.out.println("执行了构造方法");


}

那么他们执行的顺序是什么呢?我们继续往下看代码:

public class Test {
    String name="haha";
    int age=18;

    static{
        System.out.println("执行了静态代码块");

    }


public Test(){

    System.out.println("执行了构造方法");


}


    {
        System.out.println("执行了实例代码块");

    }
    
    
}

class Main{

    public static void main(String[] args) {
        Test test=new Test();
    }

}


如上我们得出结论:在一个类中我们的初始化顺序是: 静态代码块---->实例代码块---->构造方法

那么我们又联想到,子类在实例化的时候会先实现父类的构造方法,那么如果在子类中实例化的顺序又是怎样呢?

public class Test {
    String name="haha";
    int age=18;

    static{
        System.out.println("执行了父类的静态代码块");

    }


public Test(){

    System.out.println("执行了父类的构造方法");


}


    {
        System.out.println("执行了父类实例代码块");

    }


}


class Test1 extends Test{

String type="狗";

static{
    System.out.println("执行了子类的静态代码块");
}


public Test1(){

    System.out.println("执行了子类的构造方法");

}



    {
        System.out.println("执行了子类的实例代码块");
    }

}



class Main{

    public static void main(String[] args) {
        Test test1=new Test1();
    }

}


又如上面代码又得出一个结论:

子类的初始化顺序为:父类静态代码块---->子类的静态代码块---->父类的实例代码块---->父类的构造方法


---->子类的实例代码块---->子类的构造方法

文章已到末尾,喜欢的话可以点个赞哦!

目录
相关文章
|
10天前
|
Java
Java 静态变量的初始化顺序
【10月更文挑战第15天】了解 Java 静态变量的初始化顺序对于正确编写和维护代码至关重要。通过深入理解初始化顺序的原理和细节,我们可以更好地避免潜在的问题,并提高代码的质量和可靠性。
|
15天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
13 3
|
15天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
27 2
|
15天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
27 2
|
15天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
26 1
|
26天前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第4天】Java零基础教学篇,手把手实践教学!
29 2
|
23天前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第6天】Java零基础教学篇,手把手实践教学!
19 0
|
Java
Java子类实例化的过程
//继承 class Work{ public Work(){ System.out.println("父类中的方法"); } } class Worker extends Work{ public Worker(){ System.out.println("子类中的方法"); } } class HelloWorld{ public static void main(String[] args){ Worker wo = new Worker(); } } 代码实例知道,输出结果是先调用父类中的构造方法,再调用子类中的构造方法。
792 0
|
9天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
4天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####