Java中的初始化与清理

随着计算机革命的发展,"不安全"的编程方式以逐渐成为编程代价高昂的原因之一。而初始化和清理(cleanup)正是设计安全的两个问题。为了处理相关的问题,Java中引入了"构造器"的概念,并额外提供了垃圾回收机制来释放不再使用的内存资源。

构造器

1.1 构造器概念
构造器可以看作是编写类时所定义的一个方法,该方法提醒你在使用其对象时应该先调用此方法。
在java中,通过提供构造器,可以确保每个对象都会得到初始化。创建对象时,如果类对象有构造器,java就会在操作对象之前自动调用相应的构造器,从而保证了初始化进行。

1.2 定义构造器
想要定义构造器,首先我们应该知道如何命名,构造器的名称要解决两个问题, 一是构造器的名称和成员名称冲突问题,二是让编译器识别构造器的名称。 因此在Java中使用类名来作为构造器的名称。
例:

class Test{
    Test(){
        System.out.println("初始化...");
    }
}
public class Thinking_test {
    public static void main(String []args){
       for(int i=0;i<5;i++){
           new Test();
       }
    }
}
Output:
	初始化...
	初始化...
	初始化...
	初始化...
	初始化...

每当我们创建对象(new Test();)时,将会为对象分配存储空间,并调用相应的构造器,这样就保证了在操作对象之前,对象已经被初始化了。

不接受任何参数的构造器叫做默认构造器(无参构造器),当编写一个类时,如果你的类中没有构造器,那么编译器会自动帮你创建一个这样类型的构造器。同样构造器也是可以带有参数的,在构造器中带有参数可以方便我们指定如何创建对象。
例:

class Test{
    Test(int i){
        System.out.println("初始化"+i+"...");
    }
}
public class Thinking_test {
    public static void main(String []args){
       for(int i=0;i<5;i++){
           new Test(i);
       }
    }
}
Output:
	初始化0...
	初始化1...
	初始化2...
	初始化3...
	初始化4...

值得注意的是,如果Test(int i)是Test类中唯一的构造器,那么编译器将不会允许你以其他任何方式创建Test对象。

重载

在同一个类里可以有多个同名函数,但是每一个同名函数都有着独一无二的参数类型列表,这样我们就可以通过不同的参数组合调用同一个名字的参数,这种形式叫方法重载

class Tree{
    int height;
    Tree(){
        System.out.println("播种");
    }
    Tree(int initHeight){
        height=initHeight;
        System.out.println("种植一棵"+initHeight+"米的数");
    }
    void info(){
        System.out.println("树的高度是"+height+"米");
    }
    void info(String s){
        System.out.println(s+": 树的高度是"+height+"米");
    }
}
public class Thinking_03_test1 {
    public static void main(String []args){
        Tree t=new Tree(10);
        t.info();
        t.info("重载方法");
        new Tree();
    }
}
Output:
  种植一棵10米的数
  树的高度是10米
  重载方法: 树的高度是10米
  播种

重载之后,如果传入的实参类型并非任意一个重载函数需要的类型,但经过非窄化转换仍能匹配所有的重载函数需要的参数类型,这个参数就会类型提升为更接近它的那一个函数需要的参数类型,参与运算。

this关键字

假设你希望在方法内部获得当前对象的引用,就可以使用this关键字, this关键字只能在方法内部使用,代表当前函数所属对象的一个引用。

3.1 在构造器中调用构造器:
在一个构造器中调用另一个构造器,必须使用this(构造器参数);的形式,一个构造器中只能通过这种方法调用一次别的构造器,且这个调用要放在函数最开始。
注意:除构造器外,编译器禁止其他任何方法中调用构造器
例:

class Flower{
   int petalCount =0;
   String s ="初始化";
   Flower(){
       this("hi",47);
       System.out.println("无参构造函数");
   }
   Flower(int petals){
       petalCount=petals;
       System.out.println("petalCount="+petalCount);
   }
   Flower(String ss){
       s=ss;
       System.out.println("s="+s);
   }
   Flower(String s,int petals){
       this(petals);
       this.s=s;//this()不能出现两次
       System.out.println("字符串和数字");
   }
   void printPetalCount(){
       System.out.println("petalCount="+petalCount+",s="+s);
   }
}
public class Thinking_03_test1 {
    public static void main(String []args){
       Flower x=new Flower();
       x.printPetalCount();
    }
}
Output:
  petalCount=47
  字符串和数字
  无参构造函数
  petalCount=47,s=hi

this还有另一种用法。当参数与数据成员名字相同时,使用(this.名称)表示数据成员。

3.2 static方法:
static方法就是没有this的方法,static 方法不需要实例化,其在JVM刚加载的时候就编译过了。在程序的运行过程中随时可以调用,不需要去实例化某个对象然后再去调用,可以直接用类名去调用,直到结束释放内存,且静态方法内部只能调用类静态变量,不能调用非静态方法,且任意一个对象对静态方法进行修改,其他调用该静态方法也会相应修改

初始化

4.1 成员初始化
Java尽力保证:所有变量在使用前都得到恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。
如:

void test(){
	int i;
	i++;
}

就会得到一条错误信息(i not initialized),来告诉你i没有初始化。当然对于基本数据类型的数据成员,编译器会为这些成员赋一个默认值。如果我们在定义一个对象的引用时,不将其初始化,此引用就会获得一个特殊值null。

如果我们想为某个变量初始化,可以使用直接提供初值的方式,如:
boolean bool=false;
char ch='x';
int i=100;
double d=3.14;
同样对于类(以Test类为例)可以像下面这样创建一个对象并初始化它:
Test t=new Test();

4.2 数组初始化
数组只是相同类型的,用一个标识符号名称封装到一起的一个对象序列或基本类型序列,数组是通过方括号下标操作符[ ]来定义和使用的。其定义的方法为:int [] al;int al [];
数组的初始化方式主要包括一下几种:
1.静态初始化1:
数据类型 [ ] 数组名称 = {元素1,元素2,元素3…}
2.静态初始化2:
数据类型 [ ] 数组名称 = new 数据类型[ ]{元素1,元素2,元素3…}
3.动态初始化:
数据类型 [ ] 数组名称 = new 数据类型[数组长度]

所有数组都有一个固有成员,可以通过它获知数组中含有多少个元素,这个成员就是length
数组对象有一个叫做toString的方法,这个方法不需要参数,可以产生一维数组的可打印版本(字符串)。
注意:
当我们使用:int [] arr2=arr1;时,其意义并不是复制数组arr1到数组arr2,这样做到的只是复制了一个引用,例:

public class Thinking_test {
    public static void main(String []args){
       int[] arr1={1,2,3,4,5};
       int[] arr2=arr1;
       for(int i=0;i<arr2.length;i++){
           arr2[i]=arr2[i]+1;
       }
       System.out.println("arr1="+Arrays.toString(arr1));
       System.out.println("arr2="+Arrays.toString(arr2));

    }
}
Output:
  arr1=[2, 3, 4, 5, 6]
  arr2=[2, 3, 4, 5, 6]

垃圾回收

想要了解垃圾回收首先我们应该知道以下几点:
Java里的对象并非总是被垃圾回收的,垃圾回收并不等于“析构”,垃圾回收只与内存有关。

Java中的垃圾回收只可以找到释放经由new分配的内存,因此垃圾回收并不能释放对象这块所占用的内存。为了应对这样的情况,Java允许类中定义一个名为 finalize() 的方法。 当我们需要回收对象的时候,首先要调用这个类的finalize方法。一般的纯Java编写的Class不需要重新覆盖这个方法,因为Object已经实现了一个默认的,除非我们要实现特殊的功能。如果想覆盖Object的finalize方法,只需声明一个 protected void finalize( ) { } 这样的函数。在函数里写一些你想要Java的GC回收对象之前你想做的事情。

记住,无论是“垃圾回收”还是“终结”,都不保证一定会发生。如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。

枚举类型

在Java SE5中添加了新的的特性,枚举类型,其关键字为enum,用来方便的定义枚举类型。有了枚举,可以把相关的常量分组到一个枚举类型里。其定义方法如下:

public class Thinking_test {
    public enum Figure {
        Circular,Rectangle,Triangle
    }
    public static void main(String []args){
        String string = Figure.Circular.toString();
        System.out.println(string);
        System.out.println(Figure.Circular);
    }
}
Output:
  Circular
  Circular

enum有一个特别实用的特性,就是它可以在switch内使用,由于switch是要在有限的可能值集合中进行选择,enum与它成了最好的选择。例:

public class Thinking_test {
    public enum Figure {
        Circular,Rectangle,Triangle
    }
    public static void main(String []args){
        Figure figure = Figure.Circular;
        switch (figure) {
            case Circular:
                System.out.println("圆形");
                break;
            case Rectangle:
                System.out.println("矩形");
                break;
            case Triangle:
                System.out.println("三角形");
                break;
            default:
                break;
        }
    }
}
Output:
  圆形

猜你喜欢

转载自blog.csdn.net/Lzy410992/article/details/107499224
今日推荐