黑马程序员技术交流社区

标题: 内存加载 [打印本页]

作者: hmr8    时间: 2013-4-29 17:12
标题: 内存加载
有多个类,里面有静态、非静态的成员,在编译时怎么加载到内存的?
作者: 杨同旺    时间: 2013-4-29 21:02
类以及类里的成员,在编译时,由编译器加载到内存并编译成字节码文件.

类以及类的成员的字节码文件,由虚拟机的类加载器加载到内存并运行.


作者: 芦玉明    时间: 2013-4-29 21:06
1,栈区:各种原始数据类型的局部变量都是在栈上创建的,当程序退出该变量的作用范围的时候,这个变量的内存会被自动释放。
2,堆区:对象(包括数组)都是在堆中创建的。程序在运行的时候用new关键字来创建对象,对象创建时会在堆中为其分配内存。
3,方法区:内存在程序编译时就分配好了,比如静态变量。
作者: 伊廷文    时间: 2013-4-29 21:17
通过类加载器啊
作者: Sword    时间: 2013-4-30 01:49
数据成员可以分静态变量、非静态变量两种.
静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于内存,所以非静态成员可以直接访问类中静态的成员.

非成静态员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成员的生存期决定于该类的生存期..而静态成员则不存在生存期的概念,因为静态成员始终驻留在内存中..

类所有内容加载顺序和内存中的存放位置:
利用语句进行分析。
1.Person p=new Person("zhangsan",20);
该句话所做的事情:
1.在栈内存中,开辟main函数的空间,建立main函数的变量 p。
2.加载类文件:因为new要用到Person.class,所以要先从硬盘中找到Person.class类文件,并加载到内存中。
加载类文件时,除了非静态成员变量(对象的特有属性)不会被加载,其它的都会被加载。
记住:加载,是将类文件中的一行行内容存放到了内存当中,并不会执行任何语句。---->加载时期,即使有输出语句也不会执行。
静态成员变量(类变量)  ----->方法区的静态部分
静态方法              
----->方法区的静态部分
非静态方法(包括构造函数)  ----->方法区的非静态部分
静态代码块 ----->方法区的静态部分
构造代码块 ----->方法区的静态部分

注意:在Person.class文件加载时,静态方法和非静态方法都会加载到方法区中,只不过要调用到非静态方法时需要先实例化一个对象
,对象才能调用非静态方法。如果让类中所有的非静态方法都随着对象的实例化而建立一次,那么会大量消耗内存资源,
所以才会让所有对象共享这些非静态方法,然后用this关键字指向调用非静态方法的对象。
作者: 符立波    时间: 2013-4-30 10:15
本帖最后由 符立波 于 2013-5-1 07:35 编辑

类的加载--->将类的class文件读入内存中,并为之创建一个Class对象,也就是说,当程序使用任何类时,系统都会为之建立一个Class对象
类的连接--->负责把类的二进制数据合并到JRE中,这又分为三个阶段:验证,准备,解析
验证:用于检测被加载的类是否有正确的内部结构,并和其他类协调一致(语法验证)
准备:为类的静态Field分配内存,并设置默认初始化值
解析:将类的二进制数据中的符号引用替换成直接引用

类的初始化--->主要是对静态Field进行初始化(①声明静态Field时指定初始化    ②使用静态代码块为静态Field指定初始化值)



作者: 黄玉昆    时间: 2013-4-30 23:28
符立波 发表于 2013-4-30 10:15
好好看下视频吧......

在提醒一下,如果不针对楼主的问题解答,将删帖,谢谢配合
作者: 火之意志    时间: 2013-5-23 12:10
首先在jvm中对于内存分为这样几个部分,栈内存,堆内存,方法区,本地方法区,寄存器,后两者是计算机底层的是有关C\C++的知识就不说了,内存加载过程中,对于多个类中,有静态、非静态的成员,在编译时是这样加载到内存中的:静态成员变量(类变量)和静态方法都是由static修饰,在加载类的时候优先于非静态的成员(变量和方法)加载,而非静态的成员什么时候加载呢?在创建该类的实例(即对象)的时候才会加载到内存,静态成员存在于方法区中的静态区中,创建的对象(即调用关键字new出来的)存在于堆内存中,栈内存是加载方法的,栈内存中包含方法内存定义的局部变量,调用哪个方法,哪个方法就会被加载到栈内存。总之,对于静态成员和非静态成员有加载的先后顺序,先加载的静态成员不能访问后加载的非静态成员,编译时会报错,后加载的可以访问先加载的。
作者: First    时间: 2013-5-26 17:59
   对象初始化顺序为:
* 1.为成员变量开辟空间并赋值为默认值
* 2.调用构造函数(为执行方法体)
* 3.调用父类构造函数
* 4.给成员变量赋初始值
* 5.执行代码块
* 6.执行构造函数方法体。

下面是具体的例子
  1. class A {
  2.         static int a1 = 1;
  3.         int a2 = 2;
  4.        
  5.         A(){
  6.                 System.out.println("基类A的构造函数:init A");
  7.                 System.out.println();
  8.         }
  9.         static {
  10.                 a1 = 10;
  11.                 System.out.println("基类A的静态代码块:static block a1 = " + a1);
  12.         }
  13.        
  14.         {
  15.                 a2 = 20;
  16.                 System.out.println("基类A的代码块:block a2 = " + a2);
  17.         }
  18.        
  19.         static void showA(){
  20.                 System.out.println("static showA = " + a1);
  21.         }
  22.        
  23.        
  24. }

  25. class B extends A{
  26.        
  27.         static int b1 = getB1();
  28.         int b2 = getB2();
  29.        
  30.         B(){
  31.                 System.out.println("父类B的构造函数:init B");
  32.                 System.out.println();
  33.         }
  34.        
  35.         static {
  36.                 b1 = 110;
  37.                 System.out.println("父类B的静态代码块:static block b1 = " + b1);
  38.         }
  39.        
  40.         {
  41.                 b2 = 220;
  42.                 System.out.println("父类B的代码块:block b2 = " + b2);
  43.         }
  44.        
  45.         static void showB(){
  46.                 System.out.println("static showB = " + b1);
  47.         }
  48.        
  49.         static int getB1(){
  50.                 System.out.println("父类B的静态成员初始化赋值函数:static getB1");
  51.                 return 11;
  52.         }
  53.        
  54.         int getB2(){
  55.                 System.out.println("父类B的成员初始化赋值函数:getB2");
  56.                 return 22;
  57.         }
  58. }

  59. class C extends B{
  60.        
  61.         static int c1 = getC1();
  62.         int c2 = getC2();
  63.        
  64.         C(){
  65.                 System.out.println("子类C的构造函数:init C");
  66.         }
  67.        
  68.         static {
  69.                 c1 = 1110;
  70.                 System.out.println("子类C的静态代码块:static block c1 = " + c1);
  71.                 System.out.println();
  72.         }
  73.        
  74.         {
  75.                 c2 = 2220;
  76.                 System.out.println("子类C的代码块:block c2 = " + c2);
  77.         }
  78.        
  79.         static void showC(){
  80.                 System.out.println("static showC = " + c1);
  81.         }
  82.        
  83.         static int getC1(){
  84.                 System.out.println("子类C的静态成员初始化函数:static getC1");
  85.                 return 111;
  86.         }
  87.        
  88.         int getC2(){
  89.                 System.out.println("子类C的成员初始化函数:getC2");
  90.                 return 222;
  91.         }
  92.        
  93. }

  94. public class Demo
  95. {
  96.         public static void main (String[] args){
  97.         C c = new C();
  98.         }
  99. }

  100. /* 输出结果:
  101. 基类A的静态代码块:static block a1 = 10
  102. 父类B的静态成员初始化赋值函数:static getB1
  103. 父类B的静态代码块:static block b1 = 110
  104. 子类C的静态成员初始化函数:static getC1
  105. 子类C的静态代码块:static block c1 = 1110

  106. 基类A的代码块:block a2 = 20
  107. 基类A的构造函数:init A

  108. 父类B的成员初始化赋值函数:getB2
  109. 父类B的代码块:block b2 = 220
  110. 父类B的构造函数:init B

  111. 子类C的成员初始化函数:getC2
  112. 子类C的代码块:block c2 = 2220
  113. 子类C的构造函数:init C


  114. //**************
  115. * 结论:
  116. * 静态成员函数-->静态成员变量-->静态代码块
  117. *
  118. * 成员函数-->成员变量-->代码块-->构造函数
  119. *
  120. * 因为成员变量是在赋值之前开辟的并被赋值为默认值 0,false,null;
  121. *
  122. *
  123. */
复制代码

作者: 136616244    时间: 2014-4-25 01:32
Sword 发表于 2013-4-30 01:49
数据成员可以分静态变量、非静态变量两种.
静态成员:静态类中的成员加入static修饰符,即是静态成员.可以 ...

创建对象的时候是根据方法区中的类信息创建对象的,如果加载的时候不加载非静态成员变量进方法区,那怎么实例化成员变量呢?





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2