美文网首页
第四,五章 控制,初始化与清理

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

作者: 浩林Leon | 来源:发表于2017-12-20 21:52 被阅读2次

    执行流程

    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

    相关文章

      网友评论

          本文标题:第四,五章 控制,初始化与清理

          本文链接:https://www.haomeiwen.com/subject/ssvnwxtx.html