有什么方法可以解释对象是如何创建并存在于堆上的?以及如何计算运行时堆上有多少对象?
为了进一步澄清......我现在有第一个问题的答案,但我需要知道一种在运行时计算堆中活动对象的方法......天气工具或模式或算法......如何我知道运行时堆上的活动对象的数量
有什么方法可以解释对象是如何创建并存在于堆上的?以及如何计算运行时堆上有多少对象?
为了进一步澄清......我现在有第一个问题的答案,但我需要知道一种在运行时计算堆中活动对象的方法......天气工具或模式或算法......如何我知道运行时堆上的活动对象的数量
作为关于这个广泛主题的初步陈述可以是:
来源:http ://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html
关于你的第二个问题
在我为 OCP Java 6 Programmer 学习的课程中,归功于 Kathy Sierra 和 Bert Bates,以及学习指南“SCJP 6”
继承、堆栈和堆部分(在第 2 章):
1- IT MUST NOT HAVE A RETURN
2- IT MUST MATCH THE CLASS NAME EXACTLY
3- THE DEFAULT CONSTRUCTOR HAS THE SAME ACCESS MODIFIER AS THE CLASS
1- when calling a constructor throw the "new" keyword, the constructor calls
(invokes) all the super classes constructors throw the IMPLICIT "super()" till
the Object class (it's at the top of the inheritence hirarchy of any class in
Java), unless you have an overloaded constructor in one of the superclasses,
containing arguements, which should be called from it's sub with the
super(arg1, arg2, ...) alike the constructor
2- the first constructor up the inheritence tree starts to run in the JVM,
at this point you are at the top of the STACK...
initializing all it's initial variables by giving them there explicit values
(initialized previosly by the classes creator), then the next constructor,
till the one calles
3- the constructors are all called, given there explicit values (if mentioned in
there constructors called), then every object finishes it's job, it's caller
is removed from the stack, untill all objects created, given values, and
reachable throw the "main()" stack frame, so all destroyed except the method
running now which is the "main()" in this case
public class Object {/*implicitly inherited by any class in Java*/}
public class Zoo {
private static int animalsInTheZoo;
public Zoo(){
super(); //implicit by the compiler
getInstancesCreated();
System.out.println("animals in the zoo now : " + animalsInTheZoo);}
private int getInstancesCreated(){
return ++animalsInTheZoo;}
public int getAnimalsInTheZoo(){
return this.animalsInTheZoo;}
}
public class AddAnimal extends Zoo{
private String animalName;
public AddAnimal(String name){
super(); //implicit by the compiler
this.animalName = name;
System.out.println("the new Animal name is : "+ this.animalName);}
public static void main (String [] arg){
AddAnimal tom = new AddAnimal("Tom"); // step 1
//AddAnimal jerry = new AddAnimal("Jerry");} // step 2
}
result :
--------
animals in the zoo now : 1
the new Animal name is : Tom
1) main 方法在线程栈帧的底部加载,它的局部变量 (tom)
THE STACK
|---------------------------------|
| | ------> this is called "Stack Frame"
|---------------------------------|
| |
|---------------------------------|
| |
|---------------------------------|
| 1-main()calls {AddName tom} |
|---------------------------------|
2)变量“tom”指的是对象“AddName”的构造函数导致两件事:1-在堆上创建对象“AddName”的实例抛出重载的构造函数“AddName(String name);” 2-向它的参数添加对String对象的引用,抛出持有
值“tom”的litrals(这意味着现在可以在堆的永久Gen上访问“String”对象)
|---------------------------------|
| |
|---------------------------------|
| |
|---------------------------------|
| 2-AddName("Tom") {super()} |
|---------------------------------|
| 1-main()calls {AddName tom} |
|---------------------------------|
3) "AddName" 的构造函数和它的 "super()" 调用 Super Class no-arg 的构造函数 "Zoo();",它在堆上创建对象 "Zoo" 的新实例
|---------------------------------|
| |
|---------------------------------|
| 3-Zoo(){super();} |
|---------------------------------|
| 2-AddName("Tom") {super();} |
|---------------------------------|
| 1-main()calls {String tom;} |
|---------------------------------|
4)“Zoo”的构造函数用它的“super()”调用超类无参数的构造函数“Object();”,这对于任何不继承其他类的类都是隐式的,因此它隐式继承了“Object " 类,在堆上创建“对象”类的实例
|---------------------------------|
| 4-Object(){} |
|---------------------------------|
| 3-Zoo(){super();} |
|---------------------------------|
| 2-AddName("Tom") {super();} |
|---------------------------------|
| 1-main()calls {String tom;} |
|---------------------------------|
5) Object() 完成它的工作并从堆栈中删除
|---------------------------------|
| |
|---------------------------------|
| 3-Zoo(){super();} |
|---------------------------------|
| 2-AddName("Tom") {super();} |
|---------------------------------|
| 1-main()calls {String tom;} |
|---------------------------------|
6)Zoo完成了它的工作,现在静态int“animalsInTheZoo”增加了“1”(*),控制台打印“现在动物园里的动物:1”,当Zoo构造函数到达它的大括号“}”,它从堆栈中移除;
|---------------------------------|
| |
|---------------------------------|
| |
|---------------------------------|
| 2-AddName("Tom") {super();} |
|---------------------------------|
| 1-main()calls {String tom;} |
|---------------------------------|
7) 现在,当超类完成工作时,返回到我们调用的构造函数,它具有新的和实际需要的值,它开始工作,给变量“animalName”赋予值“Tom”,并打印出“新的动物名称” is : Tom",然后堆栈找不到要调用的方法或构造函数,因此程序流程停止
**提示:重要的是要知道调用任何方法,为此方法创建一个新的堆栈帧,直到它完成然后堆栈帧被销毁,这发生在步骤(6)中,当我们调用“Zoo()”的构造函数时", 里面有一个方法被调用, 所以栈用这个方法创建了一个栈帧, 完成了, 然后销毁了方法的栈帧, 然后销毁了Zoo()栈帧, 记住"super();" call 类似于“method();” 调用但略有不同,堆栈为两者创建一个新的堆栈框架
对于 JVM,当您创建对象的实例(例如 AddAnimal)时,它会为该对象及其所有超类腾出空间,直到您到达 MEGA-SUPER 类,即“对象”,例如,考虑一下在这样的堆上:
___________________________ ______________________________________
| THREAD / STACK | | GARBAGE COLLECTABLE AREA ON THE HEAP |
|_\_\_\_\_\_\_\_\_\_\_\_\_\| |_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\__|
| | | ______________________ |
|--------------------------| | | AddAnimal | |
| | | | ________________ | |
|--------------------------| | | | Zoo | | |
| Object(){} | | | | ______ | | |
|--------------------------| | | | | | | | |
| Zoo(){super();} | | | | |Object| | | |
|--------------------------| | | | |______| | | |
| AddAnimal(){super();} | | | | | | |
|--------------------------| | | |________________| | |
| main(){new AddAnimal();} | | |______________________| |
|__________________________| |______________________________________|
对于堆栈,每个堆栈帧完成它的调用,它被清空但是对于堆,任何“可达对象”都会抛出堆栈或在其上抛出创建的对象,它保持活动状态,这就是堆栈将破坏调用堆栈帧的原因“super()” 或超类构造函数,而对象将在堆上保持活动状态,类似于图中所示,原因是
“AddAnimal”类可以随时访问它的超类的任何方法,因此它们是可访问的,即使当前方法调用(在堆栈上)没有使用它们
1- 使用任何访问修饰符
2-匹配类名
3- 不能有返回类型
4- 合法但愚蠢地创建一个与类同名的方法......但必须有一个返回类型。
5-即使你没有看到它,默认的 NO-ARG 构造函数也会自动生成
6- 自己键入一个 NO-ARG 构造函数将取消默认的未见过的构造函数
7-构造函数的第一条语句必须是对重载构造函数“this()”的调用或对超类构造函数“super()”的调用,并且 this 可以由编译器隐式插入 - 如果构造函数从指向另一个构造函数的语句“this()”开始,编译器将知道 this 不是此类中的最终构造函数,并且下一个(如果是最终构造函数)必须包含“super()”关键字,如果不是,编译器将隐式放置一个 NO-ARG “super()”
8-“super()”可以是一个 NO-ARG 调用,或者可以根据持有参数的超类构造函数将参数传递给它
9- 在超级构造函数运行之前,你不能调用 ANY THING 的实例
10- 只有静态变量或方法可以作为参数传递给 this(x) 或 super(x)..like: super(superClassStaticVariable) 或 this(subClassStaticVariable)
11-抽象类构造函数在具体子类被实例化时被调用
12-接口没有构造函数,因为它们不在对象继承树中
13- 调用构造函数的唯一方法是在另一个构造函数中(例如 this() 和 super())
14-你可以创建多个重载的构造函数,每个构造函数都可以是最后一个实例化的,换句话说,你可以有7个重载的构造函数,它们都有,第一行代码是“super();”,你没有要让构造函数在进入超类构造函数之前相互调用,可以将构造函数设为final(抛出“super();”调用),也可以让它们相互调用(抛出“this();”调用)之前到达持有“super();”的最终构造函数 打电话..这取决于你的设计
注意:如果同一个类中的 2 个构造函数相互调用(以“this()”开头),编译器不会发现问题,但是当它传递给 JVM 时,会发生 STACK OVERFLOW 异常