1.初始化与清理(Thinking in java学习一)
1. 用构造器来确保初始化
创建对象时,如果该类具有可用的构造器,java就会在用户有能力操作对象之前自动调用相应的构造器,从而保证了初始化的进行。
Java中“初始化”与“创建”捆绑在一起的两者不能分离。
问题1:构造器是一类特殊的方法,它没有返回值。与返回值为空(void)的区别?
- 对于空值返回,尽管方法本身没有返回什么,但是仍然可以选择让它返回别的东西,但是构造器则不会返回任何东西,你别无选择。
2.方法重载
- 区分重载方法
- 每个重载的方法都必须有一个独一无二的参数类型列表,参数相同,顺序不同也能区分。(参数列表和顺序的不同来区分)
- 每个重载的方法返回值类型有可能不一样,仅返回值不同不能区分方法重载。
- 涉及基本类型的重载
- 传入的实际参数类型小于方法中声明的参数类型,实际参数类型就会被提升(向上自动转换)。
- 传入的实际参数类型大于重载方法声明的形式参数,如果不强制转换的话,编译器就会报错。(向下强制转换)
3.默认构造器
没有形式参数的构造方法--创建一个默认的构造器。如果类中没有构造器,则编译器会自动帮创建一个默认构造器。
4.关键字
- this关键字
this关键字只能在方法内部使用,表示对调用方法的对象的引用。
注意:在方法内部调用同一个类的另外一个方法,就不必使用this,直接调用,当前方法中的this引用会自动应用于同一个类中的其他方法。
在构造器中调用构造器
使用this调用构造器,只能调用一个,不能调用两个及以上,且必须将构造器调用置于最起始处。
- static
static 的含义:
static修饰就是没有this的方法,在static方法内部不能调用非静态方法,反过来却是可以的,且在没有创建对象的前提下,仅仅通过类本身来调用static方法----static的主要用途。
5.清理:终结处理和垃圾回收
Java有垃圾回收器辅助回收无用对象占据的内存资源。但是对象获得了一块“特殊”的内存区域,而垃圾回收器只会释放由new分配的内存,所以它不会释放该对象的内存。
finalize()方法工作原理:
垃圾回收器准备好释放对象占用的存储空间时,首先调用其finalize(),并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
A.对象可能不会被垃圾回收;
B.垃圾回收不等于“析构”;
C.垃圾回收只与内存相关;
finalize()意义和用途:
由于在分配内存时可能采用了类似C语言中的做法,而非java中的通常做法。这种情况主要发生在使用本地方法。是一种在Java中调用非Java代码的方式。在非Java代码中调用了C的malloc()函数系列来分配内存空间,除非调用free()函数,否则存储空间将得不到释放,从而造成内存泄露。此时需要在finalize()中用本地方法调用它。
要清理一个对象,用户必须在需要清理的时刻执行清理动作的方法。无论是垃圾回收还有终结,都不一定会发生。如果Java虚拟机中并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。
终结条件
当对某个对象不再感兴趣,也就是它可以被清理了,该对象应该处于某种状态,使它占用的内存可以被完全安全地释放。
垃圾回收器工作原理
注:垃圾回收器对于提高对象的创建速度,却具有明显的效果。
注:在堆上分配的代价十分高昂。
自适应的、分代的、停止-复制、标记-清扫式垃圾回收器。
垃圾回收的意义:
在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。
垃圾回收能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾回收机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程的时候,靠垃圾回收机制可大大缩短时间。其次是它保护程序的完整性, 垃圾回收是Java语言安全性策略的一个重要部份。
垃圾回收的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象,而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾回收算法的不完备性,早先采用的某些垃圾回收算法就不能保证100%收集到所有的废弃内存。当然随着垃圾回收算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。
垃圾回收的算计分析:
所谓根集就是正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾回收首先需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。
-
引用计数法(Reference Counting Collector)
引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。
基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1。 -
tracing算法(Tracing Collector)
tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器
-
compacting算法(Compacting Collector)
为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。
-
copying算法(Coping Collector)
该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成一个对象区和多个空闲区,程序从对象区为对象分配空间,当对象满了,基于coping算法的垃圾回收就从根集中扫描活动对象,并将每个活动对象复制到空闲区(使得活动对象所占的内存之间没有空闲间隔),这样空闲区变成了对象区,原来的对象区变成了空闲区,程序会在新的对象区中分配内存。
一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象区和空闲区域区,在对象区与空闲区域的切换过程中,程序暂停执行。 -
generation算法(Generational Collector)
stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代 (generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。 -
adaptive算法(Adaptive Collector)
在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。
6.成员初始化
- 类的每个基本类型数据成员保证都会有一个初始值。尽管有一些初值没有给出,但它们确实有初值。
- 指定初始化:在定义类成员变量的地方为其赋值。
7.构造器初始化
可以用构造器来进行初始化。
注意:无法阻止自动初始化的进行,它将在构造器被调用之前发生。
-
初始化顺序
在类的内部,类的定义先后顺序决定了初始化的顺序。 -
静态数据的初始化
静态数据的初始化和非静态数据类似,但是初始化的顺序是先静态变量,后非静态变量。
对象创建过程:(Dog类为例子)
A.构造器没有显式的static关键字,单实际上就是静态方法。首次创建类型为Dog的对象时,或者Dog类的静态方法、静态域被访问时,
Java解释器必须查找类路径,以定位Dog.class文件。
B.然后载入Dog.class,有关静态初始化的所以动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
C.当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
D.这块存储空间为被清零,这就自动地将Dog对象中的所有基本数据类型都设置成了默认值,而引用则被设置成了null。
E.执行所有出现于字段定义处的初始化动作。
F.执行构造器。
-
显示的静态初始化. 静态语句块:Java允许将多个静态初始化动作组织成一个特殊的静态语句块。
-
非静态实例初始化
对于非静态初始化,用来初始化每个对象的非静态变量。这种语法对于支持“匿名内部类”的初始化是必须的。
8.数组初始化
编译器不允许指定数组的大小。
int[] a1;
现在拥有的只是对数组的一个引用,即内存已经分配了足够大的存储空间给该引用,并没有给数据对象本身分配任何空间。
可变参数列表
Object...args,String...testString;
Java SE5后加入了可变参数列表的特性。
9.枚举类型enum
在Java SE5中新增enum关键字,使得我们需要群组并使用枚举类型集时,可以方便地处理。
实用特性:它可以在switch语句内使用。
public enum SpecTest{A,B,C,D};
public class Burrito {
SpecTest degree;
switch(){
case A:break;
case B:break;
……
}
}