`

J2SE自学(五)——Java内存管理

阅读更多
1、变量就是计算机中一块块内存空间

2、 Java内存管理原理(是三方关系——程序<-->JVM<-->操作系统) :
    1)、程序运行前:有些编程语言编写的程序会直接向操作系统请求内存,但 Java 并不支持那么做。这样做的一个重要优点是保证了程序的平台无关性。既然 Java 程序不负责创建内存空间,那由谁创建呢?是由 JVM 完成。当程序准备执行时,由JVM 预先向操作系统请求一定的内存空间,称为初始内存空间。程序执行过程中所需的内存都由Java 虚拟机从这片内存空间中划分。

    2)、程序运行中:Java 程序一直向 Java 虚拟机申请内存,当程序所需内存空间超出初始内存空间时,Java 虚拟机会再次向操作系统申请更多的内存供程序使用。

    3)、内存溢出:程序接着运行,当 Java 虚拟机已申请的内存达到了规定的最大内存空间,但程序还需要更多的内存,这时会出现内存溢出的错误。 


至此可以看出,Java 程序所使用的内存是由 Java 虚拟机进行管理、分配的。Java 虚拟
机规定了 Java 程序的初始内存空间和最大内存空间,开发者只需要关心 Java 虚拟机是如何
管理内存空间的,而不用关心某一种操作系统是如何管理内存的。

3、 内存空间逻辑划分:方法区,堆与栈 ——JVM 会把申请的内存从逻辑上划分为三个区域,即:方法区、堆与栈。

//这个class整体就是一个方法区!

public class Student {

	public String name ;
	
	public int age ;
	 
	public void study() {
		System.out.println("我在学习java!");
	}
}



//这个class中的stu和i都是变量,而 new Student()是对象
public class Demo {

	public static void main(String[] args) {

		Student stu = new Student() ;
		stu.name = "张三" ;
		stu.age = 18 ;
		int i = 10 ;
	}

}



Java虚拟机对应的在内存中划分了三个区域“方法区”、“堆区”和“栈区”,分别保存类结构、对象中的数据和变量(基本型和引用型)。 这三个内存区域都有大小限制,任何一个区域内存溢出都会导致程序出现错误,栈内存溢出会发生StackOverflowException错误,堆内存溢出会发生OutOfMemoryError错误。

1)、方法区中的内存分配:方法区默认最大容量为64M,Java虚拟机会将加载的java类存入
方法区,保存类的结构(属性与方法),类静态成员等内容。编写中小型程序时,一般不会
造成方法区的内存溢出。

2)、堆中的内存分配:堆默认最大容量为64M,堆存放对象持有的数据,同时保持对原类的
引用。可以简单的理解为对象属性的值保存在堆中,对象调用的方法保存在方法区。

3)、栈中的内存分配:栈默认最大容量为1M,在程序运行时,每当遇到方法调用时,Java虚拟机就会在栈中划分一块内存称为栈帧(Stack frame),栈帧中的内存供局部变量(包括基本类型与引用类型)使用,当方法调用结束后,Java虚拟机会收回此栈帧占用的内存。
  另:还有数组内部也封装了指针,即便是基本数据类型的数组,也封装了指针,数组也是引用类型。


4、JAVA 数据类型
   C 语言可以声明指针类型的变量。那就会问,java 中有没有指针呢?您一定要明确回答:“JAVA 中没有指针”。问题并没有到此终结,您要紧接着说“但 JAVA 底层封装了指针”。对,Java 底层封装了指针,但我们要说java 中没有指针,也就是不能创建指针类型的变量。
   但也并不是所有的类型都封装了指针根据这点不同,java 的数据类型分为两类,即:值类型(基本数据类型)和引用类型。

   1)、分类原则:根据是否封装指针(分配空间形式)
   2)、基本数据类型:值类型(又称基本数据类型和基元数据类型)——只在栈中分配一块内存(四类八种,详见J2SE自学(三)——Java语法基础(一))  
   3)、引用数据类型(就是底层封装指针的数据类型。):在栈和堆中各各分配一块内存,例如:类、数组、接口等——他们在内存中分配两块空间,第一块内存分配在栈中,只存放别的内存地址,不存放具体数值,我们也把它叫指针类型的变量,第二块内存分配在堆中,存放的是具体数值,如对象属性值等。


5、声明对象与创建对象
    声明对象,相当分配指针类型变量,在栈中分配内存
    类是引用类型,那声明对象就相当于在栈中声明指针类型的变量,它的内存不存放具体的数值,而只存放另一块堆中内存的地址。

    创建对象,创建具体内存空间,在堆中分配内存
    在java 中一般使用new 关键字创建对象(当然还有更高级的反射可以不用new 关键字)例如:
    zhouxingxing = new Student()就是创建对象。这行代码一共做了两件事情:第一件是在堆中分配一块存放学生具体数值的内存(例如:35DF),第二件是把这个内存的首地址赋给上面声明的指针变量。

    对象必须创建后才能使用,如果只声明不创建,那么调用对象属性和方法时将会报空指针异常(NullPointerException)
    只声明对象,只相当于在栈中分配一块不存放具体数值的内存;没有创建,在堆中没创建存放具体数值的内存,当我们调用其属性方法时,系统找不到具体堆内存,则报空指针异常。同时我们也可以反过来说,空指针异常是因为没有指向堆中内存引起的。


6、JAVA 值传参与引用传参——定义:方法根据调用后的效果不同,即是否改变参数的原始数值
   按值传递参数数值不变,按引用传递参数数值改变。
   对于java的数据类型而言,基本数据类型就是按值传递的,又称为值类型,而引用类型是按引用传递的。如:
   public class TestValueAndRef { 
  /** 
   * 方法参数有三个 
   * @param pa 基本类型  值类型 
   * @param pstu 自定义类 引用类型  
   * @param parr 数组 引用类型 
   */ 
  void change(int pa, Student pstu, int[] parr) { 
     
    //方法体中改变值类型pa的值 
    pa = pa + 10; 
    //方法体中改变引用类型stu,parr的值
    pstu.stuAge = pstu.stuAge + 10; 
    parr[0] = parr[0] + 10; 
     
    System.out.println("方法体改变后pa = " + pa); 
    System.out.println("方法体改变后pstu.stuAge = " + pstu.stuAge); 
    System.out.println("方法体改变后parr[0] = " + parr[0]); 
  } 
 
} 


运行类:
public class Test { 
  public static void main(String[] args) { 
     
    Student student = new Student(); 
    student.stuAge = 10; 
    int a = 10; 
    int arr[] = new int[]{9, 5, 27}; 
     
    System.out.println("初始值 a = " + a); 
    System.out.println("初始值 student.stuAge = " +  
student.stuAge); 
    System.out.println("初始值 arr[0] = " + arr[0]); 
     
    TestValueAndRef testValueAndRef = new TestValueAndRef(); 
    testValueAndRef.change(a, student, arr); 
     
    System.out.println("调用函数后 a = " + a); 
    System.out.println("调用函数后 student.stuAge = " +  
student.stuAge); 
    System.out.println("调用函数后 arr[0] = " + arr[0]); 
 
  } 
} 


运行结果:
初始值 a = 10
初始值 student.stuAge = 10
初始值 arr[0] = 9
方法体改变后pa = 20
方法体改变后pstu.stuAge = 20
方法体改变后parr[0] = 19
调用函数后 a = 10
调用函数后 student.stuAge = 20
调用函数后 arr[0] = 19


我们看到,基本数据类型int 变量a 虽然在方法体中改变了数值,但方法调用完后其原始数值并没有改变。而引用数据类型Student 在方法体中改变年龄的数值,方法执行完其数值发生了改变,数组也是引用类型,所以其值也发生了改变。也就是说:值类型按值传递参数,方法调用结束后,原始数值不变,引用类型按引用传递参数方法调用结束后,原始数值改变。

不管是按值传递还是按引用传递,都是把栈中的数据备份了一份给参数变量,只不过值类型备份的是具体的数值,而引用类型备份的是内存地址,所以从这个角度看,我们也可以说Java 全部是按值传参的,因为它都是把数据备份了一份。

7、String类
   特例String 类型,虽然它也是引用类型,但用引用传参后,原始数值却不会改变

   public class TestString { 
   public static void main(String[] args) { 
     
    String name = "zhangsan"; 
    TestString testString = new TestString(); 
     
    System.out.println("方法调用前:" + name); 
    testString.change(name); 
    System.out.println("方法调用后:" + name); 
  } 
   
  void change(String str) { 
    str = "张三"; 
    System.out.println("方法体内修改值后:" + str); 
  } 
} 

运行结果:
方法调用前:zhangsan
方法体内修改值后:张三
方法调用后:zhangsan

虽然参数String 是引用数据类型,但其值没有发生改变,这是因为String 类是final 的,它是定长。方法体内改变的仅仅是改变了str的引用!对方法体外的name并没有任何影响!

以后遇到类似而的问题要“多思考,多画图,多实践!”
分享到:
评论

相关推荐

    j2se学习笔记——课堂笔记

    **J2SE学习笔记——接口与相关程序** Java 2 Platform, Standard Edition(J2SE)是Java平台的核心部分,提供了开发和运行桌面应用程序、Web应用程序和服务的基础。本笔记主要聚焦于J2SE中的接口(Interface)概念...

    实验1 JAVA开发环境J2SE实验报告.doc

    JAVA开发环境J2SE实验报告 在本实验中,我们将学习和掌握JAVA开发环境J2SE的基本概念和使用方法。具体来说,我们将学习如何下载和安装J2SE开发工具,熟悉J2SE开发工具的使用,编写简单的Java Application和Java ...

    由浅入深——Java 2自学教程 配书光盘.rar

    《由浅入深——Java 2自学教程》是一本旨在帮助初学者逐步掌握Java编程语言的书籍。配书光盘中的“由浅入深——Java 2自学教程 配书光盘.rar”压缩包文件,包含了书中所有工程素材和源码,这对于读者实践和理解Java...

    手工完成java项目(一)——J2SE项目

    【标题】"手工完成java项目(一)——J2SE项目"揭示了这个压缩包文件是关于使用Java标准版(J2SE)进行项目开发的教程。在Java领域,J2SE代表Java 2 Platform, Standard Edition,它是Java平台的核心,主要用于桌面...

    J2SE6.0API+JAVA-API1.6中文版合集

    "J2SE6.0 API + JAVA-API1.6中文版合集"是一个非常实用的资源,它整合了Java Standard Edition(J2SE)6.0版本和Java API 1.6的中文文档,为开发者提供了详细的API参考,帮助他们更好地理解和使用这两个版本中的各种...

    J2SE基础,内容是JAVA

    Java J2SE(Java 2 Platform, Standard Edition)是Java平台的核心部分,它提供了用于开发和部署桌面应用程序的API和运行环境。这个平台包含了Java语言的基础类库,如集合、多线程、网络编程、I/O操作等核心功能。在...

    J2SE宏观性总结

    3. JVM工作原理:内存管理、字节码执行、垃圾回收。 4. 开发工具:如JDK中的javac编译器、jar打包工具等。 5. 实践应用:编写简单的桌面应用、服务端程序等,加深对J2SE的理解。 通过这个宏观性的总结,你可以逐步...

    如何才算掌握Java(J2SE篇

    ### 如何才算真正掌握Java(J2SE篇) 在当今的软件开发领域中,Java作为一门重要的编程语言,被广泛应用于各种应用场景之中。对于初学者来说,如何判定自己是否已经掌握了Java,特别是在J2SE(Java 2 Standard ...

    java课程设计大作业-用J2SE写的一个坦克大战小游戏

    java课程设计大作业——用J2SE写的一个坦克大战小游戏java课程设计大作业——用J2SE写的一个坦克大战小游戏java课程设计大作业——用J2SE写的一个坦克大战小游戏java课程设计大作业——用J2SE写的一个坦克大战小游戏...

    j2se学习笔记和java学习笔记

    它的主要特点包括跨平台性(Write Once, Run Anywhere)、垃圾回收机制、自动内存管理、异常处理和丰富的类库。学习Java首先要掌握其语法基础,包括变量、数据类型、运算符、控制结构(如if语句和循环)、函数等。 ...

    j2se6.rar_J2se6

    首先,J2SE6引入了显著的性能提升,包括更快的启动时间和更高效的内存管理。它采用了新的垃圾回收算法,提高了程序运行时的内存效率,降低了应用的暂停时间。此外,J2SE6对Java虚拟机(JVM)进行了优化,使得应用...

    JAVA基础入门资料,J2SE入门资料,JAVA培训第一课,JAVA初学者资料,JAVA学习者必须知道的问题汇总

    这份"JAVA基础入门资料,J2SE入门资料,JAVA培训第一课,JAVA初学者资料,JAVA学习者必须知道的问题汇总"是绝佳的学习资源,涵盖了Java编程的基础知识,将帮助你快速进入Java的世界。 首先,让我们从Java的基础开始...

    liyingfang.rar_JDBC SQL SERVER_j2se_j2se sql_java jdbc_销售系统

    4. 安全性:Java语言的强类型和内存管理机制,以及JDBC的事务处理,确保了数据的安全性。 综上,“丽婴房库存销售系统”充分利用了J2SE和JDBC的优势,实现了高效的数据管理与业务流程整合,为企业提供了一套完善的...

    java工资管理系统(J2SE)

    Java工资管理系统是一款基于J2SE(Java Standard Edition)平台开发的应用程序,主要用于处理企业员工的薪资计算、管理和发放。J2SE是Java的核心版本,提供了丰富的API和工具,支持桌面应用开发。在这个系统中,...

    图书管理系统java j2se mysql mcx模式

    在这个图书管理系统中,Java J2SE为开发提供了基础的编程环境和运行支持。 2. **MySQL**: MySQL是一种广泛使用的开源关系型数据库管理系统,以其高效、稳定和易于使用而著名。在这个系统中,MySQL用于存储和管理...

    JBuilder 9_0程序设计——Java程序员成功之路_0

    《JBuilder 9_0程序设计——Java程序员成功之路》是一部专为Java程序员设计的教程,旨在帮助读者熟练掌握JBuilder 9.0这一强大的Java集成开发环境(IDE)。JBuilder是由Borland公司开发的一款专业级的Java应用程序...

    基于J2SE和EXCEL的人事合同管理

    本文将深入探讨如何利用Java的标准版(J2SE)和Excel进行高效的人事合同管理。在Java环境中,Swing库为我们提供了丰富的图形用户界面(GUI)组件,而处理Excel文件则可以借助于PIO和JXL这两个强大的库。 首先,Java...

    j2se异常课件是java的基础课程章节之一

    Java 2 Platform, Standard Edition(J2SE)是Java编程语言的核心部分,它提供了开发和运行桌面应用、服务器端应用和服务的基本平台。异常处理是Java编程中的关键概念,也是J2SE课程中不可或缺的一部分。在Java中,...

Global site tag (gtag.js) - Google Analytics