美文网首页
OnJava8_初始化和清理

OnJava8_初始化和清理

作者: 啊啊啊哼哼哼 | 来源:发表于2020-01-07 22:31 被阅读0次

    Java对象初始化通过构造器,清理通过垃圾收集器(Garbage Collector, GC)

    构造器

    无参构造函器,有参构造器
    如果创建一个类,没有自定义构造器,编译器会自动创建一个无参构造器

    方法重载

    函数名相同,参数个数或者参数类型不同,也可参数顺序不同(不推荐)

    this关键字

    • this可以表示当前对象的引用,不能用于静态方法(静态方法与对象无关)
    public class Leaf{
    int i = 0;
    Leaf increment(){
       this.i++;
       return this;
    }
    void print(){
       System.out.println("i = "+i);
    }
    public static void main(String [] args){
       Leaf x = new Leaf();
       x.increment().increment().increment.print();
    }
    }
    
    • this 关键字在向其他方法传递当前对象时也很有用:
    class Person {
        public void eat(Apple apple) {
            Apple peeled = apple.getPeeled();
            System.out.println("Yummy");
        }
    }
    
    public class Peeler {
        static Apple peel(Apple apple) {
            // ... remove peel
            return apple; // Peeled
        }
    }
    
    public class Apple {
        Apple getPeeled() {
            return Peeler.peel(this);
        }
    }
    
    public class PassingThis {
        public static void main(String[] args) {
            new Person().eat(new Apple());
        }
    }
    
    • this 在构造器中如果被传入一个参数列表,则是通过最直接的方式显示得调用匹配参数列表得构造器
    public class Flower {
        private int preCount = 0;
        String s = "initial value";
        Flower(int preCount){
            this.preCount = preCount;
            System.out.println("Constructor w/ int arg only, preCount = " + preCount);
        }
        Flower(String s){
            System.out.println("Constructor w/ string arg only, s = " + s);
            this.s = s;
        }
        Flower(int preCount, String s){
            this(preCount);
            this.s = s;
            System.out.println("String & int args");
        }
        Flower(){
            this(7,"hi");
            System.out.println("no-arg constructor");
        }
        public void print(){
            System.out.println("preCount = " + preCount + " s = " + s);
        }
    
        public static void main(String []args){
            Flower flower1 = new Flower();
            flower1.print();
    //        Tree tree1 = new Tree(1);
    //        flower1.print();
    //        flower1.preCount = 2;
    //        flower1.print();
        }
    
    }
    class Tree{
        private int height;
        Tree(int height){
            this.height = height;
        }
    }
    
    • 成员变量和参数列表中变量同名,用this.s来表明指代得是成员变量,防止混淆

    在构造器中调用构造器

    • 在构造器中可以通过this加参数列表的形式调用其他构造器
    • 在一个构造器内只可以通过this调用一次其他的构造器
    • 必须首先调用构造器
    • 不能在非构造器的方法中调用构造器

    static的含义

    • 不能在静态方法中调用非静态方法和this,后两者与对象有关,静态方法与对象无关
    • 非静态方法可以调用静态方法
    • 静态方法只能调用静态变量

    垃圾回收器(Garbage Collector)

    • 垃圾回收器一边回收内存,一边使堆中的对象紧凑排列
    • 引用计数,每个对象有一个引用计数器,每当有引用指向该对象时,引用计数加1,当引用离开作用域或者置null时,引用计数器减1。当引用计数器为0时,释放其内存空间
    • 如果从栈或静态存储区出发,遍历所有的引用,你将会发现所有"活"的对象。对于发现的每个引用,必须追踪它所引用的对象,然后是该对象包含的所有引用,如此反复进行,直到访问完"根源于栈或静态存储区的引用"所形成的整个网络。
    • Java虚拟机采用一种自适应的垃圾回收技术,停止-复制(stop-and-copy)和标记-清扫(mark-and-sweep)相结合。

    "标记-清扫"所依据的思路仍然是从栈和静态存储区出发,遍历所有的引用,找出所有存活的对象。但是,每当找到一个存活对象,就给对象设一个标记,并不回收它。只有当标记过程完成后,清理动作才开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。"标记-清扫"后剩下的堆空间是不连续的,垃圾回收器要是希望得到连续空间的话,就需要重新整理剩下的对象

    构造器初始化

    • 自动初始化发生在构造器初始化之前
    • 类中变量定义初始化在构造器之前
    • 静态的基本类型,如果你没有初始化它,那么它就会获得基本类型的标准值,如果是对象引用,就是null。
      加载类->如果类是第一次加载则初始化静态成员变量->初始化非静态成员变量
    • 导致类加载的原因: 1、new 一个类的对象,(构造器其实也是静态方法) ; 2、调用类的静态方法和静态成员变量
    • 创建一个类的对象过程:
      1、构造器其实也是静态方法,加载类,Java解释器在类路径中查找,定位java.com.util...class;
      2、加载类之后,首先初始化静态成员变量(如果是第一次加载类);
      3、当通过new 方法创建对象,在堆上分配内存空间;
      4、分配的存储空间首先会被清零,对象的基本类型数据设置为默认值,引用设置为null;
      5、执行所有出现在字段定义处的初始化动作;
      6、执行构造器。
    • 静态块和其他静态初始化动作一样,仅在第一次类加载时执行
    • 只有new对象的类加载才会初始化非静态属性

    数组初始化

    • 静态数组初始化
      int [] a = {1,2,3,4,5};
    • 动态数组初始化
      int [] a = new int[5];
            int [] intA = new int[5];
            System.out.println(intA[0]);
            System.out.println(Arrays.toString(intA));
            System.out.println("*********");
            char [] charA = new char[5];
            System.out.println(charA[0]);
            System.out.println(Arrays.toString(charA));
            System.out.println("*********");
            Character [] characterA = new Character[5];
            System.out.println(characterA[0]);
            System.out.println(Arrays.toString(characterA));
            System.out.println("*********");
            Integer [] IntegerA = new Integer[5];
            System.out.println(IntegerA[0]);
            System.out.println(Arrays.toString(IntegerA));
    

    结果:

    0
    [0, 0, 0, 0, 0]
    *********
     
    [ ,  ,  ,  ,  ]
    *********
    null
    [null, null, null, null, null]
    *********
    null
    [null, null, null, null, null]
    

    可变参数列表

    import java.util.Arrays;
    
    public class OverloadingVarargs2 {
        static void f(float i, Character... args) {
            System.out.println(i);
            System.out.println(Arrays.toString(args));
            System.out.println("first");
        }
    
        static void f(Character... args) {
            System.out.println("second");
        }
    //  修改为下面函数就不会报错
    // static void f(char c, Character... args) {
    //        System.out.println("second");
    //    }
    
        public static void main(String[] args) {
    //        f(1, 'a');
            f('a', 'b');
    //        System.out.println((float) 'r');
        }
    }
    

    会报错

    Error:(19, 9) java: 对f的引用不明确
      OverloadingVarargs2 中的方法 f(float,java.lang.Character...) 和 OverloadingVarargs2 中的方法 f(java.lang.Character...) 都匹配
    

    因为char向上转换(隐式转换)到float和装箱为Character优先级相同,如果改为注释,char能找到对应的参数类型,就不会产生歧义。

    枚举类型 enum

    public enum Course {
        ENGLISH, CHINESE, MATH, PHYSICAL,
    }
    public class EnumTest {
        Course takeCourse;
    
        EnumTest(Course takeCourse) {
            this.takeCourse = takeCourse;
        }
    
    
        public static void main(String[] args) {
            Course course1 = Course.CHINESE;
            System.out.println(course1);
            for (Course c1 : Course.values())
                System.out.println(c1.ordinal());
    
            EnumTest test1 = new EnumTest(Course.CHINESE);
            EnumTest test2 = new EnumTest(Course.ENGLISH);
            EnumTest test3 = new EnumTest(Course.MATH);
    
            test1.printTakeCourse();
            test2.printTakeCourse();
            test3.printTakeCourse();
        }
    
        private void printTakeCourse() {
            switch (this.takeCourse) {
                case ENGLISH:
                    System.out.println("take english");
                    break;
                case CHINESE:
                    System.out.println("take chinese");
                    break;
                default:
                    System.out.println("take other courses");
                    break;
            }
        }
    }
    
    • enum类型适用于switch;
    • values() 方法按照 enum 常量的声明顺序,生成这些常量值构成的数组;
    • ordinal() 方法表示某个特定 enum 常量的声明顺序。

    相关文章

      网友评论

          本文标题:OnJava8_初始化和清理

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