关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨

综合网上的相关帖子和我自己的调试,研究了一下关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序问题。首先看一段程序:

 

class X {
    Y b
= new Y();//7、这里是父类成员变量初始化
    static Y sb= new Y();//1、父类静态变量,输出static Y(静态代码块先初始化),2、Y

   
static{
        System.out.println(
"static X父类静态代码块");//3、执行静态代码块
        new Y();//4、这里只是输出Y,有static Y(静态代码块只执行一次)
    }
    X() {

        System.out.println("X");//8、父类成员变量初始化之后,执行父类构造器输出X
    }
}

class Y {
   
static{
        System.out.println(
"static Y");       
    }
    Y() {
//执行构造函数
       
//这里有个super()==Object()
        System.out.println("Y");
    }
}

public class Z extends X {
   
final static int mead=45;
   
final byte b=16;
   
static Y sb= new Y();//5、子类的静态变量,输出Y
    static{      
        System.out.println(
"static Z");//6、子类的静态代码块
    }
    Y y
= new Y();//9、这里是子类成员变量初始化

    Z() {
       
//这里有super()==new X()
        this.y = null;
        System.out.println(
"Z");//10、子类成员变量初始化之后,执行子类构造器输出Z
    }

   
public static void main(String[] args) {
       
new Z();

    }
}

 

执行结果:

static Y
Y
static X父类静态代码块
Y
Y
static Z
Y
X
Y
Z

 

解释:
static的东西在编译的时候就向内存要到了存取空间,他们的初始化要早于非static,顺序是先父类再子类。
初始化类,先执行super()父类的的构造函数(final和static之后),父类的构造函数先执行super()直到object super(),完了执行一般成员变量的初始化

一般成员变量初始化完毕,执行构造器里面的代码(super()之后的代码).
父类的初始化完成后(子类构造器里面super执行完毕),才轮到子类的成员变量初始化
子类成员变量初始化完毕,开始执行子类构造器里面的代码(super()之后的代码).

 

注意:

静态块和静态变量的调用顺序是按照书写顺序执行的,比如上边X类中静态块和静态变量的书写顺序颠倒如下:

class X {
  Y b = new Y();
       static{
        System.out.println("static X父类静态代码块");
        new Y();
    }
    static Y sb= new Y();
    X() {
        System.out.println("X");
    }
  
}

则执行结果为:

static X父类静态代码块
static Y
Y
Y
Y
static Z
Y
X
Y
Z

 

最后:

确定变量空间和初始化赋值是分开进行的,先一次性确定静态成员变量空间 并赋给二进制0 ,然后按照书写顺序逐一赋值

如下代码,输出结果是0.0

public class Test {
   
static int i=f();
   
static double d=0.1234;
   
public static void main(String[] args) {
       
new Test();
    }
   
static int f(){
        System.out.println(d);
       
return 3;
    }
}

 

 

<think>嗯,用户现在问的是继承抽象和实现接口分别是什么意思,还问到是不是继承成员变量并重写方法。首先,我需要回顾一下之前已经讨论过抽象和接口的区别,但用户现在更关注的是“继承”和“实现”这两个操作的具体含义。 用户可能对抽象和接口的基本概念有所了解,但可能对具体如何继承和实现,以及其中涉及的成员变量和方法处理不太清楚。需要明确说明继承抽象时,子如何处理抽象中的成员变量和方法,特别是抽象方法的实现。同时,实现接口时,需要满足哪些要求,比如必须实现接口中的抽象方法,而接口中的默认方法和静态方法如何处理。 另外,用户提到的“成员变量继承重写方法”可能存在误解。需要澄清在继承抽象时,成员变量是否会被继承,是否需要重写。而接口中的变量都是常量,不能被修改,所以在实现接口时,并不能继承这些变量作为实例变量,只是可以访问它们。 可能还需要比较两者的不同点,比如抽象可以有构造方法,而接口不能;抽象支持单继承,接口支持多实现。同时,强调设计目的的不同,抽象用于代码复用和共享状态,接口用于定义行为规范。 用户可能在实际编程中遇到了如何选择使用抽象还是接口的问题,或者对继承和实现的具体机制感到困惑。需要通过具体例子来说明两者的用法,帮助用户更好地理解。 最后,需要检查是否有遗漏的重要点,比如Java 8之后接口的默认方法,以及抽象和接口在版本演进中的变化,这些都可能影响用户的理解。确保回答结构清晰,逐步引导用户理解继承和实现的含义,以及它们在实际应用中的区别。</think>以下是关于**继承抽象**和**实现接口**的详细说明,结合代码示例帮助理解: --- ### 一、继承抽象(`extends`) #### 核心含义 **继承抽象**表示子与抽象是**"is-a"(是什么)**的父子关系,子通过`extends`关键字继承抽象的属性和方法。 #### 具体行为 1. **成员变量继承** - 子会**直接继承**抽象的**非私有成员变量**(无需重写) - 示例: ```java abstract class Animal { protected String name; // 子直接继承name变量 } class Dog extends Animal { void setName(String name) { this.name = name; // 直接使用继承的name变量 } } ``` 2. **方法实现要求** - **必须重写**抽象中的所有**抽象方法** - **可选择重写**具体方法(非强制) - 示例: ```java abstract class Shape { abstract double area(); // 必须重写 void printType() { // 可选择性重写 System.out.println("形状"); } } class Circle extends Shape { double radius; @Override double area() { // 强制实现抽象方法 return Math.PI * radius * radius; } } ``` 3. **构造方法调用** - 子构造方法中**必须调用构造方法**(通过`super()`) - 示例: ```java abstract class Vehicle { private int wheels; Vehicle(int wheels) { // 抽象构造方法 this.wheels = wheels; } } class Car extends Vehicle { Car() { super(4); // 必须调用构造方法 } } ``` --- ### 二、实现接口(`implements`) #### 核心含义 **实现接口**表示承诺具备接口定义的**"can-do"(能做什么)**能力,通过`implements`关键字实现多个接口的规范。 #### 具体行为 1. **成员变量继承** - **不继承成员变量**!接口中的变量均为`public static final`常量 - 示例: ```java interface Constants { int MAX_SPEED = 120; // 常量,实现只能读取不能修改 } class Car implements Constants { void checkSpeed() { if (speed > MAX_SPEED) { // 直接使用常量 System.out.println("超速"); } } } ``` 2. **方法实现要求** - **必须实现**接口中所有**抽象方法**(Java 8前) - **可选择使用**`default`方法(可不重写) - 示例: ```java interface Flyable { void takeOff(); // 必须实现 default void land() { // 可选不重写 System.out.println("默认着陆方式"); } } class Airplane implements Flyable { @Override public void takeOff() { // 强制实现抽象方法 System.out.println("滑行起飞"); } // 不重写land()方法,则默认使用接口的land()实现 } ``` 3. **多接口实现** - 一个可同时实现多个接口 - 示例: ```java interface Swimmable { void swim(); } class Duck implements Flyable, Swimmable { @Override public void takeOff() { ... } // 实现Flyable @Override public void swim() { ... } // 实现Swimmable } ``` --- ### 三、对比总结表 | 行为 | 继承抽象 | 实现接口 | |---------------------|-----------------------------------|----------------------------------| | 成员变量处理 | 继承非私有变量 | 仅访问常量(不继承变量) | | 方法实现要求 | 必须实现所有抽象方法 | 必须实现所有抽象方法(Java 8前) | | 构造方法关系 | 必须调用构造方法 | 无构造方法 | | 多态扩展能力 | 单继承 | 多实现 | | 典型用途 | 共享代码/状态 | 定义跨行为规范 | --- ### 四、关键区别图示 ```plaintext 继承抽象 → "是什么"关系 │ ├── 继承成员变量 ├── 必须实现抽象方法 └── 单继承限制 实现接口 → "能做什么"关系 │ ├── 不继承变量(仅访问常量) ├── 必须实现抽象方法(Java 8前) └── 支持多实现 ``` --- 通过以上对比可知:**继承抽象侧重代码复用与层次关系,实现接口侧重行为规范与能力扩展**。实际开发中常将二者结合使用(如通过抽象实现接口的部分通用方法)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值