第四,五章 控制,初始化与清理

2017-12-20  本文已影响2人  浩林Leon

执行流程

While{}do 和do{}while

do{}while(flag) 至少会执行一次,而while(flag){} do 会根据条件判断
for
//这是一个无线循环

for(;;){
}

逗号操作符 可以用逗号分割一系列的语句,语句会独立,他们的类型必须相同.
标签: 用于迭代语句中(唯一的使用场景)例如:

public class ConditionTest {
    public static void main(String[] args) {
        out:
        for (int x = 0; x < 100; x++) {
            inner:
            for (; x < 4; x++) {
                if (x == 3) {
                    break inner;
                }
                System.out.println("inner" + x);
            }
            System.out.println(x);
            if (x == 4) {
                break out;
            }
        }
    }
}
//---output
inner0
inner1
inner2
3
4

Process finished with exit code 0

5.1构造函数确保初始化

注意,因为构造函数必须和类名一致,所以每个方法首字母小写的规则不适合构造函数.构造器是一种特殊的方法,因为他没有返回值.
区分重载的方法只能是参数类型不同,或者参数数量不同.不能通过返回值不同来区分重载.

5.3默认构造器

如果类中没有写任何构造器,编译器会自动生成一个无参构造器,如果类中包含任何参数的构造器,编译器是不会生成无参构造器.(因为这时候编译器会认为你是故意不需要默认构造器)

5.4this关键字

构造器中调用构造器.可以用this,表示符合参数条件的构造函数.
Static 的含义:
因为static 意思就是不没有this对象,所以他不能调用其他非静态方法.因为他无法向对象发送消息,只有对象才能发消息.但是可以通过传引用参数,让引用参数去调用他自身的方法.如果在代码中大量出现static方法,就需要重新考虑自己的设计了.

5.5清理:终结处理和回收

对于某些对象可能不是调用new 获取了一块特殊空间,由于垃圾回收器只知道回收new 分配的内存,所以对这部分特殊的空间,垃圾回收器是无法释放的.这个时候类可以override finalize(),Object在回收前会触发,垃圾回收器会调用对象的 finalize(),在下次回收的时候便可以真正释放.所以可以在finalize()里做一些清理工作.

需要明白:
 1.对象可能不被垃圾回收
 2.垃圾回收并不等于析构

所以finalize() 里面的做的清理工作,有可能在你离开界面的时候不被调用,也有可能在这一时刻被调用.如果需要很严格的确保离开界面被释放对象,需要手动创建一个执行清理的方法.

5.5.1 finalize 用途何在?

不应该将finalize 作为通用的清理方法.

记住:垃圾回收只与内存有关.

一般在调用其他非java代码创建的对象,java垃圾回收器无法释放内存,比如 调用 本地jni /c/c++ 调用了malloc 系列分配的存储空间,除非调用了free() 函数,否则存储空间将无法得到释放,从而造成内存泄露.当然free()是c/c++的函数,需要用本地方法调用.
可以通过在finalize(){ }做一些对象测试,看看某些很难跟踪的成员有没有及时在该对象释放前做变动.通常是解决一些疑难问题.

java内存回收的方案:"自适应,分代,mark-copy,mark-sweep"的 自适应,就是会自动检视当前堆空间处于什么状态,如果是所有对象都相对稳定,垃圾回收器效率比较低,就切换到mark-sweep(标记-清除),如果碎片比较多,自动切换到Copying(停止-复制);分代在新生代 采用停止-复制算法,在老年代 采用mark-sweep算法.

jvm中有一些提升速度的附加技术.有一种叫JIT(just-in-time)这个技术可以把程序全部或者部分翻译成本地机器码, 代替JVM的工作(这部分工作本来是JVM来操作的).虚拟机要执行某个类的代码,先加载class 文件,然后装进内存中.在这部的时候按理需要进行把程序翻译成本地机器码执行.通过采用JIT技术 可以使用惰性评估(lazy evaluation)在必要时才编译代码,从而可以使得部分不会被执行的代码无需编译,达到提高运行速度.Java hotSpot用到了这技术.

5.6成员初始化

java在成员变量中会进行默认初始化,但是在局部函数里面是不会自动默认初始化变量的,如果在局部函数中需要用到没有初始化的局部变量,编译器是无法编译通过的.
在给变量赋值的时候可以直接把函数值赋予变量,也可以把已经存在的变量当做参数,传给函数,再次赋值给其他变量.但是如果是通过调用函数并且传递另一个变量作为参数时,需要确保该参数的初始化要在调用之前.

public class IniteTest {
    int i = f();
    int j = g(i);
    private int f() {
        return 0;
    }
    private int g(int g) {
        return g;
    }
    public static void main(String[] args) {
    }
}

如果需要用到的变量在需要调用函数之后则无法正常编译.

public class IniteTest {
    int j = g(i);
    int i = f();
    private int f() {
        return 0;
    }
    private int g(int g) {
        return g;
    }
    public static void main(String[] args) {
    }
}
//output
IniteTest.java:9: 错误: 非法前向引用
  int j = g(i);
            ^
1个错误

5.7构造器初始化

成员变量自动初始化,会在构造器初始化变量之前发生.
在类内部,变量的定义顺序决定了初始化的顺序.(也就是说变量初始化顺序只跟,变量在类中定义的顺序有关,变量初始化,会优先构造函数里面调用,而方法的定义只有在第一次调用是才会被初始化)

/**
 * Created by leon on 17-12-13.
 */
class Window {
    public Window(int seq) {
        System.out.println("window" + seq);
    }
}
class House {
    Window w1 = new Window(1);     //---①
    void f() {
        System.out.println("f()"); //---⑤
    }
    House() {
        System.out.println("开始进入构造函数");
        w3 = new Window(3);         //---④
    }
    Window w2 = new Window(2);     //---②
    Window w3 = new Window(3);     //---③
}
public class inilationOrder {
    public static void main(String[] args) {
        House house = new House();
        house.f();
    }
}

//output---
window1
window2
window3
开始进入构造函数
window3
f()

5.7.2静态数据的初始化

无论创建多少个对象,静态数据都只占一份存储区域.就是在方法区,不是在垃圾回收器的堆中.static 不能应用与局部变量,他只能作用于域.因为局部变量是存放在栈中.

/**
 * Created by leon on 17-12-13.
 */
class Bowl {
    Bowl(int marker) {
        System.out.println("Bowl " + marker);
    }
    void f1(int marker) {
        System.out.println("f1 maker" + marker);
    }
}
class Table {
    static Bowl bowl = new Bowl(1);
    Table() {
        System.out.println("Table 构造函数");
        bowl2.f1(1);
    }
    void f2(int maker) {
        System.out.println("f2 maker" + maker);
    }
    static Bowl bowl2 = new Bowl(2);
}
class Cupboad {
    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);
    Cupboad() {
        System.out.println("Cupboad构造函数");
        bowl4.f1(2);
    }
    void f3(int maker) {
        System.out.println("f3 maker" + maker);
    }
    static Bowl bowl5 = new Bowl(5);
}
public class StaticInitionTest {
    public static void main(String[] args) {
        new Cupboad();
        new Cupboad();
        table.f2(1);
        cupboad.f3(1);
    }
    static Table table = new Table();
    static Cupboad cupboad = new Cupboad();
}
//output---
Bowl 1
Bowl 2
Table 构造函数
f1 maker1
Bowl 4
Bowl 5
Bowl 3
Cupboad构造函数
f1 maker2
Bowl 3
Cupboad构造函数
f1 maker2
Bowl 3
Cupboad构造函数
f1 maker2
f2 maker1
f3 maker1

结果说明 :
1.静态成员变量不论创建多少个实例,都只会创建一次.静态变量不会再次被初始化
2.静态变量的初始化顺序要优先非静态成员变量的顺序
3.构造函数的顺序在成员变量之后

5.7.3 显示静态初始化(静态块/静态子句)

静态块看起来想一个方法,实际上是只是一段跟在 static  后面的代码,和其他静态化变量的初始化动作一样,这段代码只执行一次.①在首次生成这个对象时,②或则首次访问属于那个类的静态数据成员时.事实证明,只要调用一个类的任意一个静态变量,其他的所有的静态变量都会被初始化,包括静态块里面的.

class BlockBowl {
    BlockBowl(int marker) {
        System.out.println("Bowl " + marker);
    }
    void f1(int marker) {
        System.out.println("f1 maker" + marker);
    }
}
class BlockTable {
    static BlockBowl bowl;
    static BlockBowl bowl2;
    static {
        bowl = new BlockBowl(1);
        bowl2 = new BlockBowl(2);
    }
    BlockTable() {
        System.out.println("Table 构造函数");
        bowl2.f1(1);
    }
    void f2(int maker) {
        System.out.println("f2 maker" + maker);
    }
    BlockBowl bowl3 = new BlockBowl(3);
}
public class StaticBlockTest {
    public static void main(String[] args) {
        System.out.print(BlockTable.bowl);
    }
}
//output-----
Bowl 1
Bowl 2
tinking_in_java.BlockBow

5.8数组初始化

int [] a;
int a[];都可以
为什么不能写成 int a[3] ? 因为在定义区只是申明了一个变量,作为一个数组的引用,没有给他本身分配任何空间.
数组有3中初始化方式:

int a1[] = {1, 2, 3};
int a2[] = new int[]{1, 2, 3};
int a3[] = new int[3];
// int[] arr=new int[3]{1,2,3}  这是不合语法的,因为 int[3] 的意思是分配3个空间大小,
// 同时把所有的值都赋0,而{1,2,3}又是直接赋值 .这两种意义上冲突了.所以语法规定不能这么同时赋值
float[][][] ratings = new float[9][][];
//只需要能确定ratings 数据的长度就可以

5.9枚举类型

eunm 看起来像一个新的数据类型,其实是一个类.java.lang.Enum

上一篇下一篇

猜你喜欢

热点阅读