最近看java突然有一个基础的问题迷惑我很久,于是就引深一下也不知道分析是否正确和大家分享不对之处还望多多指教:
1.子类调用父类是引用吗?
2.多个子类引用的是同一个父类吗?
3.如果子类修改了父类的属性值, 对其他子类有影响的吗?
4.假如一个父类 有 3个不同的子类,那么编译完成后,实际上有几个父类的对象在jvm中(换句话,是一个子类对应一个父类,还是多个子类对应一个父类)
回答以上问题:
1. 在java中, 除了基本数据类型,其余的都是引用, 所以这里子类调用父类肯定是引用了!
2.多个子类调用的是同一个父类, 我们在java代码中可以,计算出来父类的hashcode值, 会发现是一样的!
3. 如果子类修改了父类的对象的属性或者方法, 肯定不会对其他子类有影响了;
第三个解释一下:
子类修改了父类类方法:知道java 的都知道有覆盖 这个特性, 这就是典型的覆盖, 如果有影响, 那这就不是java 的特性了,就是java 的bug 了;
子类修改了父类的属性:其实我们可以参考方法,去理解
4. 如果有多个子类那么在编译完成后,会生成和子类一样多的父类的实例,因为每一个子类是编译的时候,都会有自己的一个父类引用!
这里还会牵扯到一个引用问题: 那就是我们在写代码的时候,我们只写了一个父类, 在子类继承父类的时候, 我们有多个子类的时候, 继承的同一个父类吗? 上边已经回答过是同一个,那么不同子类修改了父类的属性值,应该会影响到其他子类才对,这里引用《java编程思想》中的一句话:
为了方便理解,所以多引用些 :
由于这儿涉及到两个类——基础类及衍生类,而不再是以前的一个,所以在想象衍生类的结果对象时,可能
会产生一些迷惑。从外部看,似乎新类拥有与基础类相同的接口,而且可包含一些额外的方法和字段。但继
承并非仅仅简单地复制基础类的接口了事。创建衍生类的一个对象时,它在其中包含了基础类的一个“子对
象”。这个子对象就象我们根据基础类本身创建了它的一个对象。从外部看,基础类的子对象已封装到衍生
类的对象里了。
当然,基础类子对象应该正确地初始化,而且只有一种方法能保证这一点:在构建器中执行初始化,通过调
用基础类构建器,后者有足够的能力和权限来执行对基础类的初始化。在衍生类的构建器中,Java 会自动插
入对基础类构建器的调用
对于以上这句话可以比较理解可能更容易些:
我们更具java可以想想,如果要在一个类中引用其他的类中的属性和方法应该怎么做, 正常我们使用的是“组合”(即在这个类中new 出其他类型的 属性)
public class Cat2 { public Animal animal = new Animal(); public void print() { System.out.println("super:" + this.getClass().getSuperclass().getName().hashCode()); animal.print(); // System.out.println("name hashcode:" + name.hashCode()); animal.age = 10; animal.name = "mimi"; System.out.println("name hashcode:" + animal.name.hashCode()); animal.print(); } } public class Animal { public String name; public int age; public void print() { System.out.println("name:" + name + "\tage:" + age); } }
我们也可以采用 继承的方式:
public class Cat extends Animal { public void print() { System.out.println("super:" + this.getClass().getSuperclass().getName().hashCode()); super.print(); //System.out.println("name hashcode:" + name.hashCode()); age = 10; name = "mimi"; System.out.println("name hashcode:" + name.hashCode()); super.print(); } }
测试代码:
我们在理解组合的时候比较容易理解,在jvm编译cat2 这个类的时候, 我们肯定知道,animal 作为cat2 的属性引用被编译的cat2 中了(即: Fields_count 中), 那么继承在编译的时候是怎么找到这个animal 呢, 在编译cat的时候, 他会首先找到 看 animal是否被编译,编译之后就会cat中包含一个基础类的”子对象“,(即:Supper_class 中);
进过上述说明:我们可以理解,其实不管是组合还是继承, “子类对象”都拥有了“父类对象的一个实例的引用”所以如果你有多个子类的话, jvm 在编译的时候,就会编译出来多个父类实例, 而不是我们在写java 代码的时候,我们写了一个父类, 看来是jvm帮我们把重复的事情做了!
相关推荐
"浅谈java继承中是否创建父类对象" 在 Java 中,继承是一个非常重要的概念,它允许子类继承父类的属性和方法。但是,一个常见的问题是, Java 中的继承是否创建父类对象?在这篇文章中,我们将深入探讨这个问题,并...
- **父类(SuperClass)和子类(SubClass)的关系**:子类继承父类的属性和方法,并可以扩展或重写它们。 **7.3 多态(Polymorphism)** - **方法的覆盖(Overriding)**:子类重写父类的方法。 - **多态的分类**...
- 子类可以继承父类的属性和方法。 - 使用`extends`关键字指定继承关系。 - super关键字引用父类构造器或方法。 - **多态(Polymorphism)**: - 同一个接口被不同类以不同方式实现。 - 方法重写(Overriding...
- 继承:子类继承父类的属性和方法。 - 多态:同一方法在不同类中有不同的实现方式。 - **Java的内存分配**: - 堆:存放所有对象实例。 - 栈:存放局部变量。 - 方法区:存放类的信息、常量池等数据。 - **...
- **继承**:子类继承父类的属性和方法,提高代码复用性。 - **特点**:Java只支持单一继承。 - **关系**:子类可以扩展父类的功能,同时保持兼容性。 - **多态**:同一方法在不同类中有不同实现方式,提高灵活性...
当一个子类继承自父类时,子类对象会包含父类的所有属性和方法,这部分数据会存储在堆内存中。 1. **构造器与super关键字**:在子类的构造器中,可以通过`super()`语句来调用父类的构造器,确保父类的状态在子类...
- **定义**:允许子类继承父类的属性和方法。 - **语法**:通过关键字 `extends` 来实现继承。 - **用途**:复用代码,提高代码的可扩展性。 #### 4. 多态 - **定义**:指同一操作作用于不同的对象,可以有不同的...
- 继承:子类继承父类的属性和方法。 - 封装:隐藏对象的具体实现细节。 - 多态性:子类可以重写父类的方法,实现多态行为。 3. **异常处理** - 异常的概念。 - try-catch-finally语句块。 - 自定义异常类。 ...
- 类的执行顺序通常按照继承层次进行,首先执行父类构造器,然后是子类构造器。 12. **内部类的实现方式?** - 成员内部类:定义在一个类内部的类。 - 局部内部类:定义在一个方法内部的类。 - 匿名内部类:没有...
- **堆内存与栈内存**:对象的属性存放在堆内存中,而方法则保存在全局代码区。栈内存主要用于存储局部变量和方法调用的信息。 - **构造方法**:构造方法用于初始化对象的状态,其名称与类名相同且没有返回类型。...
- 继承是面向对象编程的一个核心概念,允许一个类(子类)继承另一个类(父类)的属性和方法。 - 在Java中,继承通过关键字`extends`实现。 - **1.2.3 接口** - 接口定义了对象之间的协议,它包含方法声明但没有方法...
- **继承**:子类可以继承父类的属性和方法,同时还可以扩展或覆盖父类的行为。 - **多态**:允许子类对象替代父类对象,实现方法重写和接口实现等。 #### 5. 高级特性 - **自动装箱与拆箱**:Java 5.0引入的新...
- **继承**:一个类可以继承另一个类的所有非私有的属性和方法。 - **接口**:一种抽象类型,定义了一组行为的规范,多个类可以通过实现同一个接口共享行为。 9. **访问修饰符** - **public**:公开,任何地方...
堆是Java虚拟机(JVM)管理的一部分内存区域,用于存放所有的Java对象实例。 - **2.2.2 特殊情况:主类型**:Java中的一些基本数据类型(如int、double等)不属于对象,而是基本类型。不过,Java也为这些基本类型提供...
- **继承**: 继承允许子类继承父类的属性和行为,从而实现代码重用。 - **异常处理**: 异常处理是 Java 中的重要特性,用于处理运行时错误。主要包括: - **检查异常**: 必须显式捕获或声明抛出的异常。 - **非...
- 类初始化按照继承层次结构从父类到子类依次进行。 - 静态成员先于实例成员初始化。 **普通代码块、静态代码块、构造代码块的区别** - 普通代码块在构造函数调用时执行。 - 静态代码块只执行一次,在类加载时执行...