- 浏览: 136978 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
winney117:
您好,我的import org.apache.ibatis.i ...
couchDB初级应用实例 -
liujiawinds:
wayneyang3 写道博主你好,不知道你有没有碰到这样的问 ...
couchDB启动报错 -
wayneyang3:
博主你好,不知道你有没有碰到这样的问题:我装完couchdb后 ...
couchDB启动报错 -
liujiawinds:
quan2hua 写道差点被你误导了,substring是不会 ...
内存泄露简介 -
quan2hua:
差点被你误导了,substring是不会内存泄露的 。
内存泄露简介
想像一下你正在用java写程序,并且用下面的代码初始化类 A 和 B 的对象:
class A { int a = f(); int f() { return 1; } } class B extends A { int b = a; int f() { return 2; } } public class CtorDemo1 { public static void main(String args[]) { B bobj = new B(); System.out.println(bobj.b); } }
现在,好像很明显的当初始化完成后,bobj.b的值将是1。毕竟,类B中的b 的值是用类A中的a的值初始化的,而a 是用f 的值初始化的,而它的值为1,对吗?
实际上, bobj.b 的值是2,要知道为什么需要知道对象初始化的问题。
当一个对象被创建时,初始化是以下面的顺序完成的:
1. 设置成员的值为缺省的初始值 (0, false, null)
2. 调用对象的构造方法 (但是还没有执行构造方法体)
3. 调用父类的构造方法
4. 使用初始化程序和初始块初始化成员
5. 执行构造方法体
看看在实际中是如何一步一步完成的,看看下面的例子:
class A { A() { System.out.println("A.A called"); } } class B extends A { int i = f(); int j; { j = 37; System.out.println("initialization block executed"); } B() { System.out.println("B.B called"); } int f() { System.out.println("B.f called"); return 47; } } public class CtorDemo2 { public static void main(String args[]) { B bobj = new B(); } }
程序的输出是:
A.A called
B.f called
initialization block executed
B.B called
B 的构造方法被调用,但是最先做的事情是隐含的调用父类的构造方法。父类必须自己负责初始化它自己的状态而不是让子类来做。
然后B对象的成员被初始化,这包含一个对B.f 的调用和包围在{}中的初始块的执行。最后B的构造方法体被执行。
你可能会问“什么是对父类的构造方法的隐含调用”。这意味着如果你的构造方法的第一行不是下面内容之一:
super();
super(args);
this();
this(args);
则有下面的调用:
super();
提供给构造方法的第一行。
如果类没有构造方法呢?在这种情况下,一个缺省的构造方法(也叫"无参构造方法")由java编译器自动生成。缺省构造方法只有在类没有任何其它的构造方法时才产生。
更深入的明白这个,假设在文件A.java中有这样的代码:
public class A { public static void main(String args[]) { A aref = new A(); } }
如果你想编译然后列出A.class 中的字节码,输入下面的内容:
$ javac A.java
$ javap -c -classpath . A
输出:
Compiled from A.java
public class A extends java.lang.Object {
public A();
public static void main(java.lang.String[]);
}
Method A()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 return
Method void main(java.lang.String[])
0 new #2 <Class A>
3 dup
4 invokespecial #3 <Method A()>
7 astore_1
8 return
在main 中,注意对 A 的构造方法的调用(就是invokespecial 行),以及A的构造方法中产生的类似的对Object 构造方法的调用。
如果父类没有缺省构造方法,你必须明确使用"super(args)"调用父类的某个构造方法,例如,下面是一个错误的用法:
class A { A(int i) {} } class B extends A {}
在上面的情况下, A 没有缺省的构造方法,但是B的构造方法必须调用A的某个构造方法。
让我们来看看初始化的另一个例子:
class A { A() { System.out.println("A.A called"); } A(int i) { this(); System.out.println("A.A(int) called"); } } class B extends A { int i = f(); int j; { j = 37; System.out.println("initialization block executed"); } B() { this(10); System.out.println("B.B() called"); } B(int i) { super(i); System.out.println("B.B(int) called"); } int f() { System.out.println("B.f called"); return 47; } } public class CtorDemo3 { public static void main(String args[]) { B bobj = new B(); } }
程序的输出是:
A.A called
A.A(int) called
B.f called
initialization block executed
B.B(int) called
B.B() called
这个例子明确使用super() 和 this() 调用。this()调用是调用同一个类中的另一个构造方法;这个方法被称为“显式构造方法调用”。当那样的构造方法被调用,它将执行通常的super() 过程以及后续的操作。这意味着A.A 的方法体在A.A(int)之前执行,而这两个都在B.B(int) 和B.B 前执行。
如果返回第一个例子,你就可以回答为什么打印的是2而不是1。B 没有构造方法,因此生成一个缺省构造方法,然后它调用super(),然后调用A 产生的缺省构造方法。
然后A中的成员被初始化,成员a 被设置为方法f()的值,但是因为B 对象正被初始化,f() 返回值2。换句话说,调用的是B中的f()方法。
A产生的构造方法体被执行,然后B的成员被初始化,而b 被赋予值a,也就是2。最后,B的构造方法被执行。
最后一个例子说明了第一个例子的一个小小的变异版本:
class A { int a = f(); int f() { return 1; } } class B extends A { int b = 37; int f() { return b; } } public class CtorDemo4 { public static void main(String args[]) { B bobj = new B(); System.out.println(bobj.a); System.out.println(bobj.f()); } }
程序的输出是:
0
37
你可能会期望输出的两个值bobj.a 和bobj.f()是一样的,但是正如你看到的他们不一样。这是正确的,即使是在a是从B的f方法中初始化的并且打印的是a 和 B的 f 方法的值。
这儿的问题是当a通过对B的f方法调用而初始化,而该方法返回成员b的值,而该成员还没有被初始化。因为这个,b的值就是刚开始的初始值0。
这些例子解释了编程中重要的一点――在对象的构造阶段调用可重载的方法是不明智的。
发表评论
-
内存泄露简介
2014-01-02 15:57 22441. 什么是内存泄露? 内存泄露: 对象不再被使用,但是 ... -
Log4j配置语句解释
2013-08-07 17:10 1212log4j ... -
Asprise OCR识别图片内容
2013-07-31 10:12 2072女朋友扫雷很厉害,我昨天又败给她了。 当时我就在想,j ... -
关于try catch finally执行顺序的一点疑问
2013-06-20 08:33 1044public class TryCatchOrder { ... -
Java operator precedence
2013-04-12 17:55 891Operator Description Lev ... -
ArrayList浅析
2013-01-16 16:47 819ArrayList是线性存储结构,底层实现基于数组, 跟 ... -
Java io 解析
2012-12-13 10:20 1003简介 Reader和Writer类--- ... -
List的三种遍历方式
2012-12-12 12:39 1298第一种:不推荐 for(int i=0,len=li ... -
File里面的compareTo()方法
2012-12-12 10:30 1120public class Compare { ... -
istanceof 的作用和用法
2012-12-11 15:07 1146instanceof的作用是判断一个对象是否是后面类的实例。 ... -
Thread跟Runnable的区别
2012-12-01 18:51 1216Runnable是Thread的接口,在大多数情况下“推荐用接 ... -
事务的特性
2012-10-12 09:33 751事务(Transaction)是并发控制的单位,是用户定义的一 ... -
HashTable和HashMap的区别
2012-07-17 09:12 831转自:http://oznyang.iteye.com/ ... -
两数组求交集
2012-07-04 21:58 957import java.util.ArrayLis ... -
java.io部分API
2012-04-25 19:54 701常用 (一)、字节流 1、java.io.Input ... -
有关服务器,web 服务器,web容器的一点总结
2012-04-25 09:13 974所谓的服务器,广义上讲有很多的概念,硬件角度上说就是一台高性能 ... -
各种IO程序(适合初学者)
2012-04-23 19:33 858public class FilenameFilterTes ... -
java基础知识汇总
2012-04-21 11:34 9041、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主 ... -
Java中super的几种用法并与this的区别
2012-04-20 23:09 11151. 子类的构造函数如果要引用super的话,必须把s ... -
Java初学者都必须理解的六大问题
2012-04-19 22:36 880问题一:我声明了什么! String s = " ...
相关推荐
当父类和子类都定义了构造方法时,如果父类的构造方法初始化父类定义的成员,子类的构造方法初始化子类定义的成员,在创建子类的对象时,这两个构造方法都要执行。这种情况下,必须在子类的构造方法中使用关键字 ...
2. 调用构造方法初始化对象。 3. 返回对象引用。 在这个过程中,构造方法被自动调用,负责完成对象状态的初始化工作。 #### 总结 通过本文的学习,读者应能深刻理解Java中构造方法的作用和使用方式,掌握构造方法...
1. 创建默认的`Circle`对象`O`,然后通过用户输入的坐标和半径,调用`Circle`的构造方法初始化`O`的属性,并打印出其信息,计算并显示周长与面积。 2. 接着,再次获取用户输入,修改`O`的圆心坐标和半径,再次打印...
例如,创建一个类,使用封装来保护数据,然后通过构造方法初始化对象,同时利用this关键字进行方法调用。实验报告将要求学生阐述他们的实现过程,解释封装和构造方法的重要性,以及在实际编程中的应用。 实验过程中...
【练习题05】:定义`Person`类,包含私有属性姓名`name`和年龄`age`,并用构造方法初始化,提供显示方法`display`。在`main`中创建`Person`对象并显示信息,练习了构造方法和访问私有属性的方法。 【练习题06】:这...
Java构造方法是面向对象编程中的一个关键概念,用于初始化新创建的对象。在Java类中,构造方法是一个特殊的方法,它的名字必须与类名完全相同,没有返回类型,甚至不包括void关键字。当我们创建一个类的新实例时,...
java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...
Java第四章类与对象,介绍类与对象的使用,关系,Java是面向对象的程序设计语言。封装性、继承性、多态性
在Java编程语言中,构造方法(Constructor)是一个特殊的方法,它的主要作用是初始化新创建的对象。构造方法与类名相同,没有返回类型,也不需要在方法签名中声明void。了解和熟练使用构造方法是Java面向对象编程的...
构造方法用于初始化类的新实例,普通方法执行特定任务,静态方法与类关联而非实例,抽象方法则在接口或抽象类中定义,需由子类实现。方法的参数传递、返回值和重载也是重要的知识点,理解这些能帮助我们编写更灵活...
无参构造方法用于简单的初始化,而有参构造方法允许在创建对象时传递参数,这样可以在对象创建时设定更复杂的初始状态。 #### 四、构造方法的调用 构造方法在使用`new`关键字创建对象时被自动调用。此外,在一个类...
1. 对象初始化——构造方法 2. 对象初始化——`@PostConstruct`注解的方法 3. 对象初始化——实现了`InitializingBean`接口的`afterPropertiesSet`方法 4. 对象初始化——自定义的`init`方法 5. ---容器启动完毕后.....
动态初始化则涉及运行时的动作,比如需要函数调用或类构造函数的初始化。这些变量的初始化在main函数执行之前进行,但晚于静态初始化。这意味着如果一个全局变量依赖于其他全局变量的初始化结果,必须确保这些依赖的...
总结来说,C# 中的结构要求在调用任何方法之前进行完全初始化,也就是说,所有字段都需要有明确的初始值。这可以是通过直接为每个字段赋值,或者是通过构造函数进行初始化。不进行完全初始化可能导致编译错误或运行...
总的来说,Java中带有不同构造方法的程序内存分析涉及构造方法的选择、内存的分配(包括栈和堆)、对象的初始化以及垃圾回收机制的理解。通过深入研究这些概念,开发者可以更好地控制和优化程序的内存使用,提高程序...
【苏坤基础提高视频笔记】是...这些笔记内容提供了学习C#基础的重要指导,帮助理解类的结构、对象的生命周期、属性的封装以及如何通过构造方法初始化对象。掌握这些知识点对于进一步深入学习C#的面向对象编程至关重要。
它们可以被视为构造函数的补充,提供额外的初始化逻辑,特别是当多个构造函数需要执行相同的初始化操作时。 ```java public class InitFiledBlockStatic { int instanceVar; { // 对象初始化块中的代码 ...
* 初始化:使用 new 创建对象时,会调用构造方法初始化对象。 Java 访问实例变量和方法 通过已经创建的对象来访问成员变量和成员方法。 Java 源文件声明规则 一个源文件只能有一个 public 类,一个源文件可以有...
编写构造方法初始化其成员属性。 * Car 类:继承于 Vehicles 类,增加 int 型成员属性 seats(座位),增加成员方法 showCar(显示小汽车的信息),编写构造方法。 * Truck 类:继承于 Vehicles 类,增加 float 型...