Java类的初始化和清理(三)

简介: Java类的初始化和清理

7 成员初始化

Java 尽量保证所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,这种保证会以编译时错误的方式呈现,所以如果写成:

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

你会得到一条错误信息,告诉你 i 可能尚未初始化。编译器可以为 i 赋一个默认值,但是未初始化的局部变量更有可能是程序员的疏忽,所以采用默认值反而会掩盖这种失误。强制程序员提供一个初始值,往往能帮助找出程序里的 bug。


要是类的成员变量是基本类型,情况就会变得有些不同。正如在"万物皆对象"一章中所看到的,类的每个基本类型数据成员保证都会有一个初始值。下面的程序可以验证这类情况,并显示它们的值:

// housekeeping/InitialValues.java
// Shows default initial values
public class InitialValues {
    boolean t;
    char c;
    byte b;
    short s;
    int i;
    long l;
    float f;
    double d;
    InitialValues reference;
    void printInitialValues() {
        System.out.println("Data type Initial value");
        System.out.println("boolean " + t);
        System.out.println("char[" + c + "]");
        System.out.println("byte " + b);
        System.out.println("short " + s);
        System.out.println("int " + i);
        System.out.println("long " + l);
        System.out.println("float " + f);
        System.out.println("double " + d);
        System.out.println("reference " + reference);
    }
    public static void main(String[] args) {
        new InitialValues().printInitialValues();
    }
}

输出:

Data type Initial value
boolean false
char[NUL]
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
reference null

可见尽管数据成员的初值没有给出,但它们确实有初值(char 值为 0,所以显示为空白)。所以这样至少不会出现"未初始化变量"的风险了。

在类里定义一个对象引用时,如果不将其初始化,那么引用就会被赋值为 null

指定初始化

怎么给一个变量赋初值呢?一种很直接的方法是在定义类成员变量的地方为其赋值。以下代码修改了 InitialValues 类成员变量的定义,直接提供了初值:

// housekeeping/InitialValues2.java
// Providing explicit initial values
public class InitialValues2 {
    boolean bool = true;
    char ch = 'x';
    byte b = 47;
    short s = 0xff;
    int i = 999;
    long lng = 1;
    float f = 3.14f;
    double d = 3.14159;
}

你也可以用同样的方式初始化非基本类型的对象。如果 Depth 是一个类,那么可以像下面这样创建一个对象并初始化它:

// housekeeping/Measurement.java
class Depth {}
public class Measurement {
    Depth d = new Depth();
    // ...
}

如果没有为 d 赋予初值就尝试使用它,就会出现运行时错误,告诉你产生了一个异常(详细见"异常"章节)。

你也可以通过调用某个方法来提供初值:

// housekeeping/MethodInit.java
public class MethodInit {
    int i = f();
    int f() {
        return 11;
    }
}

这个方法可以带有参数,但这些参数不能是未初始化的类成员变量。因此,可以这么写:

// housekeeping/MethodInit2.java
public class MethodInit2 {
    int i = f();
    int j = g(i);
    int f() {
        return 11;
    }
    int g(int n) {
        return n * 10;
    }
}

但是你不能这么写:

// housekeeping/MethodInit3.java
public class MethodInit3 {
    //- int j = g(i); // Illegal forward reference
    int i = f();
    int f() {
        return 11;
    }
    int g(int n) {
        return n * 10;
    }
}

显然,上述程序的正确性取决于初始化的顺序,而与其编译方式无关。所以,编译器恰当地对"向前引用"发出了警告。

这种初始化方式简单直观,但有个限制:类 InitialValues 的每个对象都有相同的初值,有时这的确是我们需要的,但有时却需要更大的灵活性。

目录
相关文章
|
3天前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
28 3
|
7天前
|
Java 编译器
Java Character 类
4月更文挑战第13天
|
8天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
12天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
13 0
|
12天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
16 0
|
14天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
22 9
|
14天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
30 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
|
15天前
|
存储 安全 Java
java多线程之原子操作类
java多线程之原子操作类
|
16天前
|
Java
Java中的异常类总结
Java中的异常类总结
|
16天前
|
Java
Java中的多线程实现:使用Thread类与Runnable接口
【4月更文挑战第8天】本文将详细介绍Java中实现多线程的两种方法:使用Thread类和实现Runnable接口。我们将通过实例代码展示如何创建和管理线程,以及如何处理线程同步问题。最后,我们将比较这两种方法的优缺点,以帮助读者在实际开发中选择合适的多线程实现方式。
23 4