网上看到的几个有关静态方法与非静态方法的问题,有些地方我也不太懂,望高手指教.如下:
1.是不是静态方法和非静态方法都会在程序被装入内存时,载入程序段(或者说静态方法和非静态方法都有一个内存拷贝)?
2.是不是静态方法在被调用时调用相同的那段预先载入的代码,而非静态方法,在每次初始化一个实例时都会重新创建一个该方法的拷贝到程序段?
3.一个类的静态成员、静态方法、非静态成员、非静态方法在该类被装入内存时,哪些有内存分配,分别存放在哪里,各自的生命周期是怎样的?在初始化一个类时,又是什么状况呢?
4.数据段和全局区有什么区别?
问题挺多的,呵呵,俺没多少分数了,请见谅。
1.是不是静态方法和非静态方法都会在程序被装入内存时,载入程序段(或者说静态方法和非静态方法都有一个内存拷贝)?
2.是不是静态方法在被调用时调用相同的那段预先载入的代码,而非静态方法,在每次初始化一个实例时都会重新创建一个该方法的拷贝到程序段?
3.一个类的静态成员、静态方法、非静态成员、非静态方法在该类被装入内存时,哪些有内存分配,分别存放在哪里,各自的生命周期是怎样的?在初始化一个类时,又是什么状况呢?
4.数据段和全局区有什么区别?
问题挺多的,呵呵,俺没多少分数了,请见谅。
赞同,但一直不知道其具体内存分配。 当年有个同事说一个内中重要是没有应用到类的field的方法都应该static,说是方法就只有一个copy,节约内存空间。当时我说这违反面向对象原则,但是没有很好驳倒他。
在编译期就已经生成地址了,在使用时直接用[call 地址]来实现函数的调用(或者类似的指令)
由于一些非静态方法在编译期不能确定,所以就需要动态地根据对象的地址+VMT表的形式来计算出函数的地址,而后再进行call
{
System.out.println("feijingtaisuper");
}
static{
System.out.println("jingtaisuper");
}
public TT(){
System.out.println("gouzaosuper");
}
}
public class TestBlaock extends TT {
{
System.out.println("feijingtai");
}
static{
System.out.println("jingtai");
}
public TestBlaock(){
System.out.println("gaozao");
} public static void main(String[] args){
}
}
该段代码运行结果如下:
jingtaisuper
jingtai
结果说明:static块是在类加载的时候最先执行的代码块,因为static是和类相关,而不是和对象相关的,所以即使没有创建对象,只要jvm加载这个类,就一定要先去执行static块;(并且是先执行父类的,再执行子类的,如果object类中有static代码块,那么任何类一定先去执行object类中得static代码块)
下面在main函数中增加下面一段代码: new TestBlaock();
则其运行结果如下:
jingtaisuper
jingtai
feijingtaisuper
gouzaosuper
feijingtai
gaozao结果解释:因为我们这次创建了一个对象,所以非静态块,构造函数也同时执行了;
运行顺序:父类静态块,子类静态块,父类非静态块,父类构造函数,子类非静态块,子类构造函数;
问题1:为什么一旦创建了对象,非静态块才得以执行:因为非静态块没有static修饰,那么他即是和非静态成员变量一样,是和对象相关的,他属于具体的一个对象,而不是整个类,所以当没有对象时,是不会执行非静态块的;
问题2:既然静态块是先执行父类的,接着立马去执行子类的静态块,那为什么不是按照执行完父类的非静态块,接着立马去执行子类的非静态块呢,反而是执行完父类的非静态块,接着去执行父类的构造函数去了呢?
回答:因为当jvm要创建子类的一个对象时,必须要先创建父类的对象,之后才可以有子类的对象,这也符合自然法则(现有父亲,才有儿子)。而当执行完了父类的非静态块后,如果不执行父类的构造函数,却仅接着就去执行子类的非静态块的话,那么父类的对象还没有创建完成(因为父类的构造方法没有执行呢),子类的对象就不能得以创建,而子类的对象都还没有存在,当然不能去执行与子类对象相关联的子类非静态块了。