zoukankan      html  css  js  c++  java
  • 第5章-初始化与清理

    Think in java 读书笔记

    pikzas

    2019.03.06

    第五章 初始化与清理

    Think in Java 中该章节的内容只是初步介绍了一些语法层面的内容,具体的细节需要参考之后的另一本书周志明的《深入理解Java虚拟机》

    知识点

    方法重载 方法名相同 但是参数列表不同

    • 参数的个数
    • 参数的类型
    • 参数的顺序

    基本数据类型参数的重载

    基本参数类型可以从一个较小的类型转为一个较大的类型,但是有些要注意

    可以看到char是特例 char类型会直接提升到int类型。

    反之 如果实参是较大的数据类型,而形参是较小的数据类型。则在调用的时候需要显示强转。表明你已经认识到可能会有丢失数据精度的可能。

    一个认知错误的地方就是,不可能依据返回值的不同来重载方法。因为返回值不是方法签名中的一员。

    一旦手动改写了构造函数,则编译器就不会为我们隠式添加默认的构造函数。

    this关键字指的是调用当前类中某个方法的对象是谁,所以this关键字只可能存在于方法之内。

    this的一个应用就是用来返回自身对象

    class Demo{
        int i = 0;
        Demo increment(){
            i++;
            return this;
        }
        void print(){
            System.out.println("i = "+i);
        }
        public static void main(String[] args){
            Demo demo = new Demo();
            demo.increment().increment().increment().print();
        }
    }
    //output 
    //i = 3
    

    构造器中可以调用别的构造器,但是某个构造器中只能调用最多一次其他构造器,并且调用的代码必须写在该构造器的第一行,同时方法中不能调用构造器。

    你的构造器都没执行完,对象都没有创建成功,就不要想搞别的东西。

    static关键字的含义

    static表示,我是类固有的属性或者方法,不需要依托于该类对象,就能够存在。所以static声明的属性或者方法,在编译器加载.class文件的时候,就被放到内存当中了。所以无论你new出了多少对象,我还是只有一份。

    java 中垃圾回收器是如何工作的

    • JVM 如果不是在内存即将耗尽的前提下,垃圾回收器是不会去执行垃圾回收的。
    • Java 垃圾回收器是 自适应 分代的 停止-复制(stop-copy) 标记-清扫(mark-sweep)式的

    自适应 系统处于不同运行阶段,使用不同的垃圾回收策略

    分代的 处于稳定期的系统,会对内存分块,同时标记上所处的代数,新生代、老生代、伊甸区。。。

    停止-复制 刚启动的系统,加载的新对象较多,需要频繁的分配内存、整理内存。在通过对堆栈和静态存储区中对象标记,找出不在使用的死对象之后,将其内存回收,同时整理空间,此时程序会停止。

    标记-清扫 对于较早版本的jvm,如果系统处于稳定期,会同样对内存进行标记,清扫只有内存不够用的时候才会发生。一旦发生,系统也会停止一会。

    成员初始化

    • 类中的字段(全局变量),如果未给定值,基本数据类型会默认给0、0.0或者空,引用数据类型会给null
    • 方法中的字段(局部变量),不给定初始值,编译器就会报错。

    全局变量的初始化方式-指定初始化

    • 可以直接给特定的值
    class Demo{
        int i = 123;
    }
    
    
    • 调用方法来赋值
    class Demo{
        int i = fun(); 
        int j = fun2(i);
        int fun2(int in){
            return 2*in;
        }
        int fun(){
            return 11;
        }
    }
    
    

    构造器初始化

    构造器初始化之前,默认的成员初始化一定会发生,该类被分配到内存上的时候,就给所有的全局变量指定了默认值。

    think in java 中文第四版(94页)

    class Counter{
        int i;
        Counter(){
            i = 7;
        }
    }
    

    我们无法阻止自动初始化的进行,它将在构造器被调用之前发生。就是 i首先会被置0,然后变成7。对于所有基本类型和引用类型,包括在定义的时候已经指定初始值的变量,这种情况都是成立的。
    所以我们在并发的时候要考虑到,对象只进行了自动初始化,构造器还尚未调用的情况,这时候的产生的对象是不完整的对象。

    初始化顺序

    1 静态对象先初始化(如果之前该类已经实例化过,静态对象就不会再次加载了)
    2 然后是非静态对象
    3 最后是构造器

    初始化实际的执行流程

    1 查找*.class文件
    2 载入class文件 创建一个Class对象 然后所有静态对象初始化
    3 new 对象的时候,首先在堆上分配足够的内存 (静态属性都加载完了)
    4 将这块内存区域空间置0 (自动初始化的结果,所有数据先开始是0或者空)
    5 执行类中定义的赋值操作 (所有非静态属性有了设定的值)
    6 指定构造器 (构造器被调用,可能导致对象的属性发生变化,还可能会导致父类被调用。。。)

    静态代码块

    class Cup{
        static Cpu cup1;
        static Cpu cup2;
        static {
            cup1 = new Cup(); // 只有该对象第一次创建的时候才会执行
            cup2 = new Cup();
        }
    }
    

    非静态代码块

    class Cup{
        Cpu cup1;
        Cpu cup2;
        {
            cup1 = new Cup();  // 每new一个该对象的时候都会执行一次
            cup2 = new Cup();
        }
    }
    

    数组的初始化

    • int[] arrays;
    • int arrays[]; 两种定义方式都可以。

    数组默认有一个属性length 表明数组内对象的的个数,且数组的下标是从0开始的,所以最大值为length-1

    可变参数列表

    
    class Demo{
        void fun(Object... objs){
            //objs 就是一个数组
        }
    }
    

    所以在调用fun()的时候,实参可以直接是个数组对象,如fun(new Object[]{1,2,3})。也可以是一串对象,如fun(1,2,3),这时候会自动转换为一个数组作为参数。也可以什么都不传入。

    可变参数列表与方法重载之间的冲突 由于可以接受可变参数的方法,也可以什么入参都没有,如果同时又两个可变参数列表的方法,都不传入入参,此时就会爆出编译器错误。

    class Demo{
        static void f(Character... cs){print("first");}
        static void f(Integer... ins){print("second");}
        static void f(Long... ls){print("third");}
        public static void main(String[] args){
            //f(); 这时候会提示编译错误,因为方法f被重载了三次,而不传入参数都可以调用,编译器判定不了,所以报错。
        }
    }
    
    

    枚举 也是一个类,只是java默认添加了很多方法,也可以通过接口来实现。但是较为复杂。而且枚举的实现是线程安全的

    
    public enum Smile{
        HAHA,XIXI,HEHE
    }
    

    自带的一些方法

    • ordinal() 按照定义顺序,从0开始计数
    • toString() 转为字面量(定义顺序未被写入toString方法)
    • values() 获得由字面量组成的数组
    class Demo{
        public static void main(String[] args){
          for(Smile s: Smile.values()){
              System.out.println(s + ". ordinal " + s.ordinal());
          }
        }
    }
    //output
    // HAHA. ordinal 0
    // XIXI. ordinal 1
    // HEHE. ordinal 2
    

    枚举和switch case并用

    switch(Smile){
        case HAHA: sout(1111) break;
        case XIXI: sout(2222) break;
        case HEHE: sout(3333) break;
        default: sout(4444);
    }
    
  • 相关阅读:
    中医手诊原理
    半月痕
    0020 教您新手修车的五种实用技巧
    下面说说我开车12年来的一些心得
    创建电子邮件信纸
    交通事故责任划分2011版(图解)
    育儿语录
    汽车中控台那些按钮是什么用的?
    我的书中的部分函数
    纠结的书名
  • 原文地址:https://www.cnblogs.com/Pikzas/p/12164323.html
Copyright © 2011-2022 走看看