一、数据结构上堆栈

1、栈

先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素);栈的入口、出口的都是栈的顶端位置。

向一个栈插入新元素称为入栈,删除一个元素称为出栈或退栈;

入栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。

出栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

栈分顺序栈和链式栈两种。栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。

2、栈

堆:树形数据结构

堆是一个完全二叉树
堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值

java函数参数入栈顺序 java进栈出栈顺序_堆栈

注意: 堆栈内存和数据结构上堆栈不是一个概念

二、栈内存

1、栈的基本定义

声明基本数据类型和对象的引用变量的时候,就会由栈内存进行分配。当在一段代码快中定义一个变量,Java就在栈中为其分配内存空间,若该变量退出作用域后,JAVA会自动释放该变量占有内存,另作他用。

2、栈具有的特点

存取速度比堆要快,仅次于寄存器,栈数据可以共享

存在栈中的数据大小与生存期必须是确定的,缺乏灵活性

3、java中的基本数据类型一定存储在栈中的吗?

不一定,要看基本数据类型是放在栈中还是放在堆中,这取决于基本类型在何处声明。

第一种:在方法中声明

在方法中声明的变量,即该变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因。

在方法中声明的变量可以是基本类型的变量,也可以是引用类型的变量。

(1)当声明是基本类型的变量的时,其变量名及值(变量名及值是两个概念)是放在JAVA虚拟机栈中
(2)当声明的是引用变量时,所声明的变量(该变量实际上是在方法中存储的是内存地址值)是放在JAVA虚拟机的栈中,该变量所指向的对象是放在堆类存中的。

例如:

public void method() {
	// 在方法中声明一个数组,这时就会由栈内存为其分配内存空间
	int[] array ;
}

java函数参数入栈顺序 java进栈出栈顺序_java_02

public void method() {
	int[] array ;
	// 分配内存空间
	array= new int[2];
}

接着分配内存空间,为array数组分配内存空间,并分配默认的初始值:所有数值类型数组元素默认赋值为0。

java函数参数入栈顺序 java进栈出栈顺序_数据结构_03


第二种:在类中声明

在类中声明的变量是成员变量,也叫全局变量,放在中的(因为全局变量不会随着某个方法执行结束而销毁)。

在类中声明的变量即可是基本类型的变量 也可是引用类型的变量

(1)当声明的是基本类型的变量其变量名及其值放在堆内存中的
(2)引用类型时,其声明的变量仍然会存储一个内存地址值,该内存地址值指向所引用的对象。引用变量名和对应的对象仍然存储在相应的堆中

三、堆内存

堆内存:用于存放由new创建的对象和数组,内存的分配由Java虚拟机的自动垃圾回收器来管理

释放

数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍 然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走

特点:

动态地分配内存大小,生存期也不必事先告诉编译器

在运行时动态分配内存,存取速度较慢
  1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
  2. 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。

四、常量池

1、什么是常量

用final修饰的成员变量表示常量,值一旦给定就无法改变!
final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。

2、基本类型的包装类和常量池

java8大基本类型的包装类中,除了两种浮点数类型的包装类Float,Double并没有实现常量池技术。其余都实现了常量池。

Byte,Short,Integer,Long,Character,Boolean

public static void main(String[] args) {
	Integer a1 = 2;
	Integer a2 = 2;
	System.out.println(a1==a2); //  true
}
public static void main(String[] args) {
	Integer a1 = 200;
	Integer a2 = 200;
	System.out.println(a1==a2); //  false
}

这几种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。

3、字符串String常量池

public static void main(String[] args) {
     String s1 = "abc";
     String s2 = "abc";
     System.out.println(s1==s2);  // true
   
     String s3 = new String("abc");
     String s4 = new String("abc");
     System.out.println(s3==s4); // false 
     
}

只要使用new方法,便需要创建新的对象。

// 创建了几个对象
String s1 = new String("abc"); 
// 创建了2个对象