`
tianlihu
  • 浏览: 314008 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

java 类的初始化顺序和多态

阅读更多
  类的初始化顺序是老生长谈的问题。但是它仍然是面试中常见的,也可以说是不可缺少的题目。因为在项目开发过程中,经常会因为这个出现BUG,且这样的BUG一般很难查。

  从C语言转用java语言的人常常会这样写代码:
public class Sample {

	private String str = null; // str = "";

	private boolean flag = false;

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	
	// Other code
	// ........
}

  他们总是喜欢在声明的时候初始化,我在学java之初,也有人告诉我这样写,说这是好习惯。后面的工作中,发现这是很大的错误,我们的项目中,因为这种写法,出现了很多BUG。看一下下面这个简单的例子:
class A {

	public A() {
		initAttrs();
	}

	public void initAttrs() {
		System.out.println("initAttrs in A");
	}
}

class B extends A {

	public String s = null;

	public B() {
		super();
	}

	public void initAttrs() {
		s = "aaa";
	}
}

public class InheritProblem {

	public static void main(String[] args) {
		B b = new B();
		System.out.println(b.s);
	}
}

  在这段代码,其实是一个小的框架思想,initAttrs方法是用来初始化成员属性用的,为什么不用B类的构造方法去做呢?因为如果有很多初始化的事情要做,全部都放在构造器中做,就会显得很复杂,不利于维护。团队开发时,也不太方便。且如果放在构造器中来写,子类继承时,将不能重写其代码。写成这样,子类仅需要关注自己要初始化的东西就好了。
  这段代码运行的结果出乎一般人的意料。大多数人会回答结果是:
  aaa
 
  但是结果却是:
  null

  为什么会这样呢?这就需要细说一下类的初始化顺序和方法的重写了。
  先从简单的讲起。方法的多态有两种,一种是重载,一种是重写。重载没有什么好说的,两个方法有一样的名字,参数和返回值有些差异(其实这里面有点小小的问题,我会在别的文章再说)。重写就不一样了,重写是方法的参数必须是一样的,但返回值可以不一样,子类方法的返回值要和父类方法返回值一样或是其子类,重写必须存在于父类和子类之间,子类重写父类的方法。这时,用子类对象去访问该方法,永远调用到的是子类的方法,即使是强行转化为父类的引用,就像父类的方法不存在一样。看下面的例子:
class A {
	public String str;
	
	public A() {
		str = "a";
	}

	public String getAStr() {
		return str;
	}

	public String print() {
		return "A Print";
	}
}

class B extends A {
	public String str;

	public B() {
		str = "b";
	}
	
	public String getBStr() {
		return str;
	}

	public String print() {
		return "B Print";
	}
}

public class InheritProblem {

	public static void main(String[] args) {
		A a = new B();
		System.out.println("a.str=" + a.str);
		System.out.println("a.getAStr()=" + a.getAStr());
		System.out.println("a.print()=" + a.print());
		System.out.println("--------------------------------");
		B b = new B();
		System.out.println("b.str=" + b.str);
		System.out.println("b.getAStr()=" + b.getAStr());
		System.out.println("b.getBStr()=" + b.getBStr());
		System.out.println("b.print()=" + b.print());
		System.out.println("--------------------------------");
		A c = b;
		System.out.println("c.str=" + c.str);
		System.out.println("c.getAStr()=" + c.getAStr());
		System.out.println("c.print()=" + c.print());
		System.out.println("--------------------------------");
	}
}

未完,待续
0
0
分享到:
评论

相关推荐

    成员的初始化顺序和多态性

    在Java编程语言中,理解成员变量的初始化顺序对于正确地设计和实现类结构至关重要。通过本实验,我们将深入了解成员变量的初始化顺序,以及如何通过实际代码示例来验证这些概念。 #### 实验步骤解析 ##### 步骤一...

    java类中元素初始化顺序详解

    Java 类的初始化顺序是一个关键的编程概念,尤其对于理解和避免潜在的运行时错误至关重要。在 Java 中,类的元素初始化顺序遵循以下规则: 1. **静态变量与静态初始化块**: 首先,Java 解释器会执行类中的静态...

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf

    "子类--构造器"); } public static void main(String[] args) { new SubClass(); } } 当我们运行这段代码时,会看到以下输出...所以,对于Java程序员和工程师来说,掌握类的初始化顺序是非常基础且重要的知识点。

    java 多态 经典讲解

    多态在构造方法中的体现较少,但重要的是理解,尽管构造方法不能被重写,它们可以被子类覆盖以初始化特定状态,从而支持更复杂的构造逻辑。 #### 六、利用继承设计:纯粹继承与扩展 继承不仅是代码重用的一种手段...

    Java基础入门教程 第4章 继承和多态(共36页).ppt

    子类构造方法是一个特殊的方法,用于初始化新创建的对象。在创建子类对象时,会先调用父类的构造方法,然后执行子类的构造方法。这可以通过使用`super`关键字来完成,`super()`或者`super(参数列表)`用于调用父类的...

    继承和多态笔记.docx

    ### 继承与多态知识点总结 ...总结而言,接口和抽象类都是为了提高代码的可重用性和可扩展性而设计的,它们共同支撑起了Java面向对象编程中的多态特性。正确理解和使用这些概念对于开发高质量的Java应用程序至关重要。

    Java中构造器内部的多态方法的行为实例分析

    因为构造器是在对象初始化时被调用的,所以构造器内部的多态方法的行为可以影响对象的初始化和行为。例如,在基类的构造器内部调用某个动态绑定的方法,该方法是被导出类覆盖的,那么这便可能产生难以预料的后果,...

    Java类的基本运行顺序

    4. **成员变量初始化**:尽管在类声明时已经初始化了`name`和`age`,但在构造器中`age`被重新赋值。 5. **静态方法执行**:返回到`main`方法,在第9行,打印出`name`和`age`的值。 6. **输出结果**:最终输出为`Java...

    Java封装、继承、多态[归类].pdf

    此外,`super`还可以在子类构造方法中调用父类的构造方法,确保初始化顺序正确。 总的来说,封装、继承和多态是Java面向对象编程的基石,它们帮助我们构建模块化、可扩展和易于维护的代码。通过封装,我们可以保护...

    java 多态重载 PPT

    这意味着一个类可以有多个构造函数,每个构造函数用于初始化对象的不同方式。 7. 编译时多态与运行时多态 编译时多态主要是通过方法的重载实现,Java在编译期间就能确定调用哪个重载方法。而运行时多态体现在方法...

    JAVA基础第4章继承与多态-练习题.pdf

    这些问题展示了Java中继承与多态的基本概念,包括类的继承、构造器的调用顺序、方法的重写、访问控制和静态关键字的使用等。了解这些基础知识对于编写健壮的Java程序至关重要。在实际开发中,我们需要熟练运用这些...

    java程序设计-第5章-继承、多态、重载与接口

    子类构造器可以通过`super`关键字调用父类的构造函数,确保初始化过程正确进行。 6. **内部类与匿名类** 内部类是定义在另一个类内部的类,可以是静态的或非静态的。非静态内部类可以访问外部类的所有成员,包括...

    JAVA面试题解惑系列合集

    它包括了从类的初始化顺序、String对象的创建数量、变量的覆盖、final关键字、传值和传引用的区别、字符串的处理、日期和时间的处理、基本类型的细节、继承和多态、多线程以及运算符相关的面试题目。下面将详细解析...

    Java相关知识的学习(关键字)(多态)

    - 3.3 构造方法:构造方法不参与多态,构造过程遵循“先父后子”的顺序,先执行父类构造器,然后执行子类构造器的其他代码,完成子类成员变量的初始化。 - 3.4 静态成员:静态成员属于类,不参与多态,多态调用时...

    深入剖析java类的构造方式

    总的来说,Java类的构造方式是一个涉及内存分配、初始化、继承和多态的重要主题。理解和掌握这一过程对于编写高效、可靠的Java代码至关重要。通过实例和字节码分析,程序员能够更好地理解类实例是如何被构建和初始化...

    黑马程序员:轻松精通Java学习路线基础篇!JAVA语言

    Java 学习路线基础篇!...5. 抽象类和接口:了解什么是抽象类和接口,掌握抽象类和接口的定义格式、静态初始化、动态初始化。 通过掌握这些基础知识,你将轻松精通 Java,拥有基础牢固的编程能力。

    Java 基础核心总结 +经典算法大全.rar

    类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象类接口 抽象类异常 认 识 Exception 什么是 ...

    Java对象内存管理机制.docx

    - **初始化顺序**:Java对象的初始化有三种方式:构造器、初始化块(实例初始化块和静态初始化块)以及定义变量时的初始值。初始化顺序遵循以下规则: - 首先执行静态初始化块,只在类第一次加载时运行一次。 - ...

    继承与多态及其他方法的使用

    `static`关键字用于修饰成员变量和方法,使其成为类变量和类方法,不依赖于实例即可访问。静态代码块只在类加载时执行一次,常用于初始化静态变量。 `final`关键字用于声明常量或防止修改,它可以修饰类、方法、...

Global site tag (gtag.js) - Google Analytics