第五章 初始化与清理(下)
来源:互联网 发布:oa数据库 编辑:程序博客网 时间:2024/05/16 12:10
第五章 初始化与清理
现在总结的东西很多都需要用代码来帮助理解了,所以会有大量的测试代码,不过这中方式非常有用,如果认真敲过一遍之后,并且将这些代码弄清楚了,我相信你一定会对书中描述的内容有一个更清楚的认识。我是在eclipse工具上进行测试的,这里边的代码可以之间粘贴运行,不过对于程序员来说还是自己敲一遍吧,效果会更好。
5.5 清理 : 终结处理和垃圾回收
程序员都了解初始化的重要性,但常常会忘记同样也重要的清理工作。Java有垃圾回收器负责回收无用对象占据的内存资源。但是,垃圾回收器只知道释放那些经过new分配的内存,如果你的对象(并非使用new)获得了一块“特殊”的内存区域,则垃圾回收器就不知道该如何释放这块“特殊”内存。为了应对这种情况,Java允许在类中定义一个名为finalize()的方法。这个方法的工作原理:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以要是你打算用finalize(),就能在垃圾回收时刻做一些重要的清理工作。
注意:在Java中
1、对象可能不被垃圾回收。
2、垃圾回收并不等于“析构”。(析构是在c++里出现的一个概念,就是在c++中要销毁对象必须使用析构函数)
5.5.1 finalize()的用途何在
这里需要记住第三点:
3、垃圾回收只与内存有关
也就是说,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾回收相关的任何行为来说(尤其是finalize()方法),它们也必须同内存及其回收有关。
5.5.2 你必须实施清理
要清理一个对象,用户必须在需要清理的时刻调用执行清理动作的方法。无论是“垃圾回收”还是“终结”,都不保证一定会发生。如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。
5.5.3 终结条件
通常,不能指望finalize(),必须创建其他的“清理”方法,并且明确地调用他们。
class Book{
boolean checkedOut = false;
Book(boolean checkOut){
checkedOut=checkOut;
}
void checkIn(){
checkedOut=false;
}
protected void finalize(){
if(checkedOut){
System.out.println("error : checked out");
try {
super.finalize();
} catch (Throwable e) {
System.out.println("Throwable");
e.printStackTrace();
}
}
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();
new Book(true);
System.gc();
}
Book(boolean checkOut){
checkedOut=checkOut;
}
void checkIn(){
checkedOut=false;
}
protected void finalize(){
if(checkedOut){
System.out.println("error : checked out");
try {
super.finalize();
} catch (Throwable e) {
System.out.println("Throwable");
e.printStackTrace();
}
}
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();
new Book(true);
System.gc();
}
}
运行结果:error : checked out
因为在main()方法中,由于程序员错误,有一本书未被签入。要是没有finalize()来验证终结条件,将很难发现这种缺陷。
5.5.4 垃圾回收器如何工作
5.6 成员初始化
Java尽力保证:所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。
例如:我们定义成员变量的时候并没有给它们赋值,但是编译器会给它们初始化默认值,比如 int i;在编译的时候初始值就是0。但是在方法中就不行了: void f(){
int i;
i++; //错误,i没有被初始化
}
5.6.1 指定初始化
如果想为某个变量赋初值,在基本数据类型中可以直接赋值。例如:int i=1; char ch='x' ; boolean bool=true;
如果是其他类型的对象则可以创建一个对象来初始化:Depth d=new Depth();
当然也可以通过调用方法来初始化:int i=f();
5.7 构造器初始化
public class Counter {
int i;
public Counter() {
i=7;
int i;
public Counter() {
i=7;
}
}
该程序中i首先会被置零,然后变成7。
5.7.1 初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散步与方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
5.7.2 静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象的引用,那么它的默认初始化值就是null。
class Bowl{
Bowl(int marker){
System.out.println("Bow1("+marker+")");
}
void f1(int marker){
System.out.println("f1("+marker+")");
}
}
class Table{
static Bowl bowl1= new Bowl(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2("+marker+")");
}
static Bowl bowl2=new Bowl(2);
}
class Cupboard{
Bowl bowl3=new Bowl(3);
static Bowl bowl4=new Bowl(4);
Cupboard(){
System.out.println("Cupboard");
bowl4.f1(2);
}
void f3(int marker){
System.out.println("f3("+marker+")");
}
static Bowl bowl5=new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
System.out.println("createing new cupboard in main");
new Cupboard();
System.out.println("createing new cupboard in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table=new Table();
static Cupboard cupboard=new Cupboard();
Bowl(int marker){
System.out.println("Bow1("+marker+")");
}
void f1(int marker){
System.out.println("f1("+marker+")");
}
}
class Table{
static Bowl bowl1= new Bowl(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2("+marker+")");
}
static Bowl bowl2=new Bowl(2);
}
class Cupboard{
Bowl bowl3=new Bowl(3);
static Bowl bowl4=new Bowl(4);
Cupboard(){
System.out.println("Cupboard");
bowl4.f1(2);
}
void f3(int marker){
System.out.println("f3("+marker+")");
}
static Bowl bowl5=new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
System.out.println("createing new cupboard in main");
new Cupboard();
System.out.println("createing new cupboard in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table=new Table();
static Cupboard cupboard=new Cupboard();
}
运行结果:
Bow1(1)
Bow1(2)
Table()
f1(1)
Bow1(4)
Bow1(5)
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
f2(1)
Table()
f1(1)
Bow1(4)
Bow1(5)
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
createing new cupboard in main
Bow1(3)
Cupboard
f1(2)
f2(1)
f3(1)
由运行结果可以发现:初始化的顺序是先对静态对象(前提是得有对象被初始化时才会进行,就是说静态初始化只有在必要时刻才会进行),而后是“非静态”对象,然后才是构造器。
5.7.3 显式的静态初始化
Java允许将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫做“静态块”)。
class Cup{
Cup(int marker){
System.out.println("cup("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
class Cups{
static Cup cup1;
static Cup cup2;
static{
cup1=new Cup(1);
cup2=new Cup(2);
}
Cups(){
System.out.println("cups ()");
}
}
public class Explicitstatic {
public static void main(String[] args) {
System.out.println("inside main");
Cups.cup1.f(99);
}
// static Cups cups1=new Cups();
Cup(int marker){
System.out.println("cup("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
class Cups{
static Cup cup1;
static Cup cup2;
static{
cup1=new Cup(1);
cup2=new Cup(2);
}
Cups(){
System.out.println("cups ()");
}
}
public class Explicitstatic {
public static void main(String[] args) {
System.out.println("inside main");
Cups.cup1.f(99);
}
// static Cups cups1=new Cups();
}
运行结果:
inside main
cup(1)
cup(2)
cup(1)
cup(2)
f(99)
静态块跟静态初始化一样也只执行一次,当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员(即便从未生成过那个类的对象)。就会被执行。
5.7.4 非静态实例初始化
Java中也有被称为实例初始化的类似语法,用来初始化每一个对象的非静态变量。例如:
class Mug{
Mug(int marker){
System.out.println("Mug("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
public class Mugs {
Mug mug1;
Mug mug2;
{
mug1=new Mug(1);
mug2=new Mug(2);
System.out.println("mug1 & mug2 initialized");
}
Mugs(){
System.out.println("Mugs()");
}
Mugs(int i){
System.out.println("Mugs(int)");
}
public static void main(String[] args) {
System.out.println("inside main()");
new Mugs();
System.out.println("new Mugs() completed");
new Mugs(1);
System.out.println("new Mugs(1) completed");
}
Mug(int marker){
System.out.println("Mug("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
public class Mugs {
Mug mug1;
Mug mug2;
{
mug1=new Mug(1);
mug2=new Mug(2);
System.out.println("mug1 & mug2 initialized");
}
Mugs(){
System.out.println("Mugs()");
}
Mugs(int i){
System.out.println("Mugs(int)");
}
public static void main(String[] args) {
System.out.println("inside main()");
new Mugs();
System.out.println("new Mugs() completed");
new Mugs(1);
System.out.println("new Mugs(1) completed");
}
}
运行结果:
inside main()
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs() completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs() completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
new Mugs(1) completed
从以上代码可以看出少了static关键字,所以会重复执行。
5.8 数组的初始化
数组的初始化有几种方法:
第一种:int [] a={a,b,c} 这种方式是你明确知道要初始化多少个数据,这种形式很有用,但缺点也很明显,就是更加受限。
第二种 : int [] a = new a [n] 这种形式可以解决你不知道具体要多少数据的难题,使用时可以根据情况而定。
5.9 枚举类型
在Java SE5中添加了一个看似很小的特性,即enum关键字,它使得我们在需要群组并使用枚举类型集时,可以很方便的处理。在很大程度上,可以将enum当作其他任何类来处理,事实上enum确实是类,并且具有自己的方法。enum有一个特别实用的特性,即ta3可以在switch语句内使用;
enum Spiciness{
NOT, MILD, MEDIUM, HOT, FLAMING
}
public class Burrito {
Spiciness degree;
public Burrito(Spiciness degree){
this.degree=degree;
}
public void describe(){
System.out.print("this burrito is ");
switch (degree) {
case NOT:
System.out.println("not spicy at all");
break;
case MILD:
case MEDIUM:
System.out.println("A little hot");
break;
case HOT:
case FLAMING:
default:
System.out.println("maybe too hot");
break;
}
}
public static void main(String[] args) {
Burrito
plain = new Burrito(Spiciness.NOT),
greenChile=new Burrito(Spiciness.MEDIUM),
jalapeno=new Burrito(Spiciness.HOT);
plain.describe();
greenChile.describe();
jalapeno.describe();
NOT, MILD, MEDIUM, HOT, FLAMING
}
public class Burrito {
Spiciness degree;
public Burrito(Spiciness degree){
this.degree=degree;
}
public void describe(){
System.out.print("this burrito is ");
switch (degree) {
case NOT:
System.out.println("not spicy at all");
break;
case MILD:
case MEDIUM:
System.out.println("A little hot");
break;
case HOT:
case FLAMING:
default:
System.out.println("maybe too hot");
break;
}
}
public static void main(String[] args) {
Burrito
plain = new Burrito(Spiciness.NOT),
greenChile=new Burrito(Spiciness.MEDIUM),
jalapeno=new Burrito(Spiciness.HOT);
plain.describe();
greenChile.describe();
jalapeno.describe();
}
}
运行结果:
this burrito is not spicy at all
this burrito is A little hot
this burrito is A little hot
this burrito is maybe too hot
0 0
- 第五章 初始化与清理(下)
- 第五章 初始化与清理(上)
- 第五章:初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章 初始化与清理
- 第五章:初始化与清理
- 第五章:初始化与清理
- 第五章——初始化与清理
- 【学习笔记】第五章 初始化与清理
- java-第五章 初始化与清理
- 第五章 初始化和清理
- Java分布式事务-转载
- java中,通过身份证号获取信息
- IOS 添加评论功能
- ssh问题
- 页面刷新方法
- 第五章 初始化与清理(下)
- 基于HTML5的可预览多图片Ajax上传
- Centos6.7_x64下安装Nodejs v4.0
- 通过重写ViewGroup学习onMeasure()和onLayout()方法
- setTimeout & setInterval
- JS window 对象 open方法弹窗实现父子窗口中的参数传递
- Java web添加log4j
- 归途
- int(*p)[4] int*p[4]