Java数组问题
《李刚疯狂Java》笔记
- Java数组是静态的
Java数组变量是引用类型变量,并不是数组本身,而是指向堆内存中的数组对象。
-
Java不能同时使用静态初始化和动态初始化数组
-
数组对象和数组变量
数组对象是堆内存中连续分配的空间,而数组变量是引用(类似指针的职责)
main 方法声明的变量属于局部变量,存在栈中,而数组元素作为数组对象保存在堆内存中。
###拓展: #
- Java中所有的引用变量,不需要经过初始化操作,需要进行初始化操作的是该引用变量所引用的对象。
- 异常:NullPointerException 。当通过引用变量访问实例属性时,或调用非静态方法时,若该变量未引用一个有效的对象,程序就会报错。
当发生这种错误时,应该看引用变量被调用时是否指向了有效对象。
Java 对象
局部变量(形参,方法内局部变量,代码块内局部变量)作用时间短暂,被存储在方法的栈内存中。JVM内的一个类的类变量只需一块内存空间;实例变量每次被创建即需要一块内存。
static关键字,将实例成员变为类成员。类变量初始化时处于实例变量之前。
对象的三种初始化方式:构造器,初始化块(直接添加{Xxxx}),定义变量时制定初始值。
- 构造器总是最后获得执行,即最终初始化值应属于构造器。
- 创建对象时,先调用父类的非静态初始块,构造器执行初始化(隐式调用),再调用本类的非静态初始化块,构造器执行初始化。或用super关键字进行显示调用。
- this关键字负责调用本类对应参数的重载的构造器。
- super和this只能在构造器中使用,必须作为构造器的第一行代码,一个构造器内只能使用其中之一并只能调用一次。
- 当一个子类被构建时,他的父类的实例变量也将对应着同时被构建。Java默认隐式调用父类的构造器。
- 上转型对象,父子,当通过变量调用方法时,方法总是表现出它们实际类型的行为,而通过变量访问他们所指对象的实例变量时,这些值总表现出声明这些变量所用的类型的行为。
被final修饰的变量必须显示指定初始值。
匿名类中使用局部变量,那么这个局部变量必须使用final修饰符修饰
Java对内存的控制
Java内存管理
内存分配(创建对象时,JVM为该对象在堆内存中分配的空间)
内存回收(对象失去引用,变成垃圾,JVM自动#回收占有的空间)
JVM回收标准:引用变量是否引用了对象
JVM回收机制采用有向图的方式管理内存中的对象。若从有向图的顶点(main)不可达它们,垃圾回收机制就会回收它们。
对象在堆内存中运行时的状态:
- 可达状态
- 可恢复状态:
不再有变量引用它,即进入可恢复状态,此状态下,垃圾回收机制准备回收该对象占有的内存,在回收它之前,系统会调用finalize方法进行资源清理,如果调用此方法时,重新让一个引用变量引用了该对象,则该对象变为可达状态,否则进入不可达状态)- **不可达状态:**系统真正的回收了该对象所占有的资源
为了更好管理对象的引用。Java.lang.ref 提供了 SoftReference, Phantom Reference, Weak Reference. 分别对应 软引用,虚引用,弱引用。
- **强引用:**平时我们默认使用的引用方式为强引用(无论内存是否紧张,都不会被系统垃圾回收机制回收),这种方式是造成Java内存泄漏的主要原因之一。
- 软引用:(动态回收)系统空间足够,不会被回收,空间不足则被回收。当程序需要大量创建某个类的新对象,而且有可能重新访问已创建的老对象时使用软引用解决内存紧张的难题。
例如:需要访问1000个Person对象(传统方式①依次创建1000个person对象,但只有一个person引用指向最后一个person对象②定义一个长度为1000的person数组,每个数组元素引用一个person对象)创建一个SoftReference 数组来保存100个person对象。
弱引用类似软引用,但生存期更短。不管内存是否足够,总会回收该对象占用的内存。
内存泄漏:
程序运行过程不断分配空间,那些不再使用的空间应该即使回收它们,从而保证系统可以再次使用这些恶内存,如果存在无用的内存没有被回收回来,这就是内存泄漏。
如果一些Java对象,它们处于可达状态,但程序以后永远不会再访问它们,那它们所占用的空间也不会被回收,那么这些空间也会产生内存泄漏。
在自行书写数据结构时,要注意内存泄漏的问题。
####垃圾回收机制:#
跟踪监测每个Java对象
清理内存分配,回收过程中产生的内存碎片。
实际上此机制并不可能实时监测每个Java对象,因此当一个对象失去引用后它也不会被立即回收,只有等垃圾回收运行时才会被回收。
*垃圾回收器设计算法:
*堆内存的分代回收:
内存管理小技巧:
- 使用直接量(有包装类实例时,不要去new)
- 使用StringBuilder和String Buffer进行字符串连接(序列可变的字符串)
- 尽早释放无用对象的引用
- 少用静态变量
- 避免在经常调用的方法,循环中创建Java对象
- 缓存经常使用的对象(使用hashmap进行缓存,开源的缓存项目)
- 尽量不使用finalize方法
- 考虑使用SoftReference
3/22/2019 1:19:39 AM