Java之内存分析 和后文程序执行分析差不多讲的
栈(自动分配连续的空间,后进先出):放置局部变量
堆:存放new出来的对象(不连续)
方法区(也是堆):存放类的代码信息、static变量、常量池(字符串常量等)
虚拟机JVM有一个类加载器Calss Loader加载类,然后方法区中就有了类的信息。
程序执行分析:
首先找main方法,注意哈,主方法虽然放在类里面,但是逻辑上与类并无关系,只是从代码上看main方法从属于类。
然后执行main方法中的操作。
例子如下:
JVM)(虚拟机)程序运行到第一行,Student s1=new Student(); 虚拟机在方法区中查找有没有Student.class文件 ,如果JVM虚拟机没有识别到Student,则通过JVM里的类加载器Class Loader加载类Student。对象名为s1的对象通过new操作符调用构造器创建对象,对象存于堆中,对象名为局部变量存于栈中(只要是方法里面的变量都是局部变量)。
方法区中加载了Student类的代码信息(属性(成员变量)和方法)。
第二句:s1.name="高琪";
因为String类型就是一个类创造的对象,不是基本数据类型
然后这里注意一点 常量池中的字符串都是一个对象,而且是String对象,且String对象是不可变的,也是垃圾回收机制不会回收的、下面具体解释一下:
因为运行时实例创建的全局字符串常量池中有一个表,总是为池中每一个字符串对象维护着一个引用,这是意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
所以在内存分析中name的值是一个地址,因为它是引用对象不是值,其地址指向方法区中的常量池中的“”高琪“”。
第三行:s1.study();方法是重复的,指向方法区中的方法即可。
第四行:s1.sayhello("马士兵");
注意:java中进行方法的调用过程中,传递参数时,遵循着值传递的规则:基本数据类型传递的是该数据值本身,引用类型传递的是对对象的引用,而不是对象本身,Java中只有值传递。
所以这里传的是地址,而不是对象本身。然后是通过一个栈帧来实现的。这里不做说明
然后该方法也是指向地方法区中相应的位置。
其余代码同上解释
但注意,第二次查找Student类时不用加载,因为加载过一次之后已经放在方法区里面了。
这里讲一下打印对象:
java中所有的类都继承自Object类。Object类中有toString()方法。方法如下:
由上可知会打印出类名@哈希码(对象的哈希码)
String类中重写了toString()方法。返回的是字符串本身。
上面说到打印对象,为什么可以打印对象,因为你在写打印对象的时候,
实际上输出对象的toString()方法的返回值,也就是这面代码效果相同
System.out.println(p);
System.out.println(p.toString());
toString()方法是一个非常特殊的方法,是一个“自我描述”方法,该方法通常用于实现当程序员直接打印该对象时,系统将会输出该对象的“自我描述”信息,用以告诉外界该对象具有的状态信息。
Object类提供的toString()方法总是返回该对象实现类的”类名[email protected]+hashCode”值,这个返回值不能真正实现“自我描述”功能,因此我们可以重写object的toString()方法。