一、数据结构上堆栈
1、栈
先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素);栈的入口、出口的都是栈的顶端位置。
向一个栈插入新元素称为入栈,删除一个元素称为出栈或退栈;
入栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
出栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。
栈分顺序栈和链式栈两种。栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。
2、栈
堆:树形数据结构
堆是一个完全二叉树
堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值
注意: 堆栈内存和数据结构上堆栈不是一个概念
二、栈内存
1、栈的基本定义
声明基本数据类型和对象的引用变量的时候,就会由栈内存进行分配。当在一段代码快中定义一个变量,Java就在栈中为其分配内存空间,若该变量退出作用域后,JAVA会自动释放该变量占有内存,另作他用。
2、栈具有的特点
存取速度比堆要快,仅次于寄存器,栈数据可以共享
存在栈中的数据大小与生存期必须是确定的,缺乏灵活性
3、java中的基本数据类型一定存储在栈中的吗?
不一定,要看基本数据类型是放在栈中还是放在堆中,这取决于基本类型在何处声明。
第一种:在方法中声明
在方法中声明的变量,即该变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因。
在方法中声明的变量可以是基本类型的变量,也可以是引用类型的变量。
(1)当声明是基本类型的变量的时,其变量名及值(变量名及值是两个概念)是放在JAVA虚拟机栈中
(2)当声明的是引用变量时,所声明的变量(该变量实际上是在方法中存储的是内存地址值)是放在JAVA虚拟机的栈中,该变量所指向的对象是放在堆类存中的。
例如:
public void method() {
// 在方法中声明一个数组,这时就会由栈内存为其分配内存空间
int[] array ;
}
public void method() {
int[] array ;
// 分配内存空间
array= new int[2];
}
接着分配内存空间,为array数组分配内存空间,并分配默认的初始值:所有数值类型数组元素默认赋值为0。
第二种:在类中声明
在类中声明的变量是成员变量,也叫全局变量,放在堆中的(因为全局变量不会随着某个方法执行结束而销毁)。
在类中声明的变量即可是基本类型的变量 也可是引用类型的变量
(1)当声明的是基本类型的变量其变量名及其值放在堆内存中的
(2)引用类型时,其声明的变量仍然会存储一个内存地址值,该内存地址值指向所引用的对象。引用变量名和对应的对象仍然存储在相应的堆中
三、堆内存
堆内存:用于存放由new创建的对象和数组,内存的分配由Java虚拟机的自动垃圾回收器来管理
释放:
数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍 然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走
特点:
动态地分配内存大小,生存期也不必事先告诉编译器
在运行时动态分配内存,存取速度较慢
- 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
- 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,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个对象