zoukankan      html  css  js  c++  java
  • Java编程思想之五初始化与清理

    随着计算机革命的发展,"不安全"的编程方式已经逐渐称为编程代价高昂的主因之一。
    初始化和清理正是涉及安全的两个问题。

    5.1 用构造器确保初始化

    通过提供构造器,类的设计者可确保每个对象都会得到初始化。
    考虑到初始化期间编译器要自动调用构造器,构造器采用和类相同的名称。
    在创建对象时,将会为对象分配存储空间,并调用相应的构造器。
    构造器是一种特殊类型的方法,因为它没有返回值(void是空返回,任然有返回值)。

    5.2 方法重载

    方法名相同而形式参数不同的方法。

    5.2.1 区分重载方法

    每个重载方法都必须有一个独一无二的参数类型列表。参数顺序不同有足够区别两个方法。

    5.2.2 涉及基本类型的重载

    如果传入的实际参数类型小于方法中声明的形式参数类型,实际数据类型会被提升。
    如果传入的实际参数类型大于方法中声明的形式参数类型,就要通过类型转换执行窄化转换。

    5.3 默认构造器

    默认构造器是没有形式参数的——它的作用是创建一个"默认对象"。

    5.4 this关键字

    先看看下面的代码:

    Banana a=new Banana();
    Banana b=new Banana();
    a.peel(1);
    b.peel(2);
    

    对于上面的代码,发送消息给对象,编译器做了一些背后的工作。它暗自把所操作的对象作为第一个参数传递给peel()。

    Banana.peel(a,1);
    Banana.peel(b,1);
    

    this关键字只能在方法内部使用,表示对"调用方法的那个对象"引用。
    this。关键字对于将当前对象传递给其他方法也很有用。

    5.4.1 在构造器中调用构造器

    想在一个构造器调用另一个构造器,使用this就可以做到这一点。
    this可以调用一个构造器,但不能调用两个。

    5.4.2 static的含义

    在static方法的内部不能调用非静态方法,反之可以。

    5.5 清理:终结处理和垃圾回收

    Java有垃圾回收器负责回收无用对象占据的内存资源。但也有特殊情况:假定你的对象(并非使用new)获得一块内存区域,由于垃圾回收器只知道释放那些由new分配的内存,所有它不知道该如何释放该对象的这块特殊内存。
    为了应对这种情况,Java允许在类中定义一个名为finalize()的方法:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用finalize()的方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。但要注意finalize()不等于析构函数。
    在C++中,对象一定会被销毁,而Java中对象却并非总是被垃圾回收:

    • 对象可能不被垃圾回收
    • 垃圾回收并不等于"析构"
    5.5.1 finalize()用途何在

    垃圾回收只与内存有关。
    使用垃圾回收器唯一的原因是为了回收程序中不在使用的内存。
    无论对象怎么创建,垃圾回收器都会负责释放对象占据的所有内存。

    5.5.2 你必须实施清理

    如果Java虚拟机并没有面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。

    5.5.3 终结条件

    当对某个对象不再感兴趣——也就是它可以被清理了,这个对象应该处于某种状态,使它占用的内存可以被安全的释放。

    5.5.4 垃圾回收器如何工作

    再堆上分配对象的代价十分高昂,然而,垃圾回收器对于提高对象创建速度,却具有明显的效果。
    在某些Java虚拟机中,堆的实现:它更像一个传送带,没分配一个新对象,它就往前移动一格。
    垃圾回收当它工作时,将一面收回空间,一面使堆中的对象紧凑排列,这样堆指针就可以很容易移动到更靠近传送带的开始处,也可以尽量避免页面错误。通过垃圾回收器对对象重新排列,实现了一种高速的,有无线空间可供分配的堆模型。
    其他系统中的垃圾回收机制:引用技术法,一种简单但速度慢的的垃圾回收技术。每个对象都有一个计数器,当有引用连接至对象时,引用计数加1。当引用离开作用域或被置为null时,引用计数减1。
    一种更快的模式:对任何活的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。
    Java虚拟机采用一种自适应的垃圾回收技术。
    有一种做法叫做停止——复制。先暂停程序运行,然后将所有存活对象从当前堆复制到另一个堆,没有被复制的就都是垃圾。当对象被复制到新堆时,在新堆中保持紧凑排列。
    在程序进入稳定状态下,这样复制太浪费。一些Java虚拟机会进行检查:要是没有产生新垃圾,就会转换到另一种工作模式,标记——清扫:从堆栈和静态存储区出发,遍历所有引用,进而找出所有存活对象,每当它找到一个存活对象,就会给对象一个标记,这个过程中不会回收任何对象。只有标记全部完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将被释放,不会发送任何复制动作。

    5.6 成员初始化

    Java尽力保证:所有遍历在使用前都能恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻。
    在类里定义一个对象引用时,如果不将其初始化,此引用就会获得一个特殊的null值。

    5.6.1 定义成员变量的地方为其赋值。

    5.7 构造器初始化

    在运行时刻,可以调用方法或执行某些动作来确定初值。但牢记:无法阻止自动初始化的进行,它将在构造器中被调用。

    5.7.1 初始化顺序

    在类的内部,变量的先后顺序决定了初始化的顺序。变量定义散步于方法定义之间,他们仍旧会在任何方法被调用前初始化。

    5.7.2 静态数据初始化

    无论创建多少对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值。如果它是一个对象引用,那么它的默认初始值就是null。

    
    
    public class StaticInitialization {
        static Table table =new Table();
        static Cupboard cupboard=new Cupboard();
        public static void main(String[] args){
            System.out.println("in main");
            new Cupboard();
            new Cupboard();
            table.f2(1);
            cupboard.f3(3);
        }
    }
    
    class Bowl{
        Bowl(int marker){
            System.out.println("Bowl("+marker+")");
        }
        void f1(int marker){
            System.out.println("f1("+marker+")");
        }
    }
    
    class Table{
        static Bowl bow1=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);
    }
    

    初始化的顺序是先静态对象,而后是"非静态"对象。
    对象创建过程,假设有个名为Dog的类:

    • 1.即使没有显示地使用static关键字,构造器实际上也是静态方法。
    • 2.载入new Dog()创建对象的时候,有关静态化初始化的所有动作都会执行,并且只会在第一次执行。
    • 3.当用new Dog()创建对象的时候,首先会先为Dog对象分配足够的存储空间。
    • 4.这块存储空间会被清零,这就自动的将Dog对象中的所有基本类型数据都设置成默认值,而引用则被设置成了null。
    • 5.执行所有出现于字段定义出的初始化动作。
    • 6.执行构造器。
    5.7.3 显式的静态初始化

    Java允许将多个静态初始化动作组织成一个特殊的"静态子句"。

    public class Spon{
    static int i;
    static{
    i=47;
    }
    }
    
    5.7.4 非静态实例初始化

    Java中也有被称为实例化的类似语法,用来初始化每一个对象的非静态变量。

    5.8 数组初始化

    数组只是相同类型的,用一个标识符名称封装到一起的一个对象序列或基本类型数据序列。数组是通过方括号下标操作符[]来定义和使用的。
    数组的使用和C#一致。

    5.8.1 可变参数列表

    所有的类都直接或间接继承于Object类,所以可以创建以Object数组为参数的方法。

    public class VarArgs {
    
        public static void main(String[] args){
           // printArray1(15,13,16,34,"wer",new Integer[]{1,2,3,4});
            printArray1(new Integer[]{1,2,3,4});
        }
    
        static void printArray1(Object[] args){
            for (Object obj:args) {
                System.out.println(obj);
            }
        }
    }
    
    
    

    Java SE5新加可变参数语法。在可变参数中,可以使用任何类型的参数,包括基本类型。

     static void printArray(Object... args){
            for (Object obj:args) {
                System.out.println(obj);
            }
        }
    
        public static void main(String[] args){
            printArray(15,13,16,34,"wer",new Integer[]{1,2,3,4});
            printArray(new Integer[]{1,2,3,4});
        }
    

    将0个参数传递给可变参数也是可行的。

    public class VarArgs {
        static void printArray(Object... args){
            for (Object obj:args) {
                System.out.println(obj);
            }
        }
    
        public static void main(String[] args){
           // printArray1(15,13,16,34,"wer",new Integer[]{1,2,3,4});
           // printArray1(new Integer[]{1,2,3,4});
            printArray();
        }
    
    //    static void printArray1(Object[] args){
    //        for (Object obj:args) {
    //            System.out.println(obj);
    //        }
    //    }
        //printArray1(15,13,16,34,"wer",new Integer[]{1,2,3,4});
    }
    
    

    5.9 枚举

    public class SimpleEnumUse {
        public static void main(String[] args){
            Spiciness howHot=Spiciness.MEDIUM;
            for (Spiciness spic:Spiciness.values()) {
                System.out.println(spic+":"+spic.ordinal());
            }
    
        }
    }
     enum Spiciness{
        NOT,MILD,RT,MEDIUM,HOT,FLAMING
    }
    
  • 相关阅读:
    积水路面Wet Road Materials 2.3
    门控时钟问题
    饮料机问题
    Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
    Educational Codeforces Round 82 (Rated for Div. 2)部分题解
    Educational Codeforces Round 86 (Rated for Div. 2)部分题解
    Grakn Forces 2020部分题解
    2020 年百度之星·程序设计大赛
    POJ Nearest Common Ancestors (RMQ+树上dfs序求LCA)
    算法竞赛进阶指南 聚会 (LCA)
  • 原文地址:https://www.cnblogs.com/Tan-sir/p/11228595.html
Copyright © 2011-2022 走看看