目录
默认值是什么
默认值是在没有明确指定值的情况下,默认的初始值。
默认值存在意义:为生活和其它方面提供便利和效率,使我们在没有特殊需求时能够按照预设的规则和标准进行操作。(代码逻辑方面:避免了潜在的错误或不可预测的行为)
例:点外卖,第一步选择餐品,第二步选择口味,第三步下单。如果不选择口味,系统会默认选择一个口味进行补充。
Java中的默认值在成员变量声明时自动分配(初始化),如果你不显式地对变量进行赋值,他们将会具有这些默认值。
基本数据类型的默认值
byte byteValue; // 基本类型byte的默认值是0
short shortValue; // 基本类型short的默认值是0
int intValue; // 基本类型int的默认值是0
long longValue; // 基本类型long的默认值是0
float floatValue; // 基本类型float的默认值是0.0f
double doubleValue; // 基本类型double的默认值是0.0
char charValue; // 基本类型char的默认值是空字符('\u0000')
boolean booleanValue; // 基本类型boolean的默认值是false
基本数据类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
char | '\u0000'(null 字符) |
boolean | false |
PS:char默认值验证代码如下
private char c;
public static void main(String[] args) {
System.out.println((int) c); //输出结果为:0
System.out.println(c == '\u0000'); //输出结果为:true
}
引用数据类型的默认值
引用数据类型 | 默认值 |
---|---|
类实例 | null |
接口实例 | null (实际上接口不能直接实例化) |
数组 | null |
字符串(String ) | null (String 是对象引用类型) |
自定义类 | null |
包装类(如Integer 、Double 等) | null (包装类是对象引用类型) |
普通引用类型
Object value; // 只定义变量类型,引用默认值为null
//调用value.方法会编译不通过
Object value1 = null; // 定义变量类型,并赋值为null 这种方式也叫延迟实例化
//调用value1.方法会报:(空指针异常)Exception in thread "main" java.lang.NullPointerException
Object value2 = new Object(); // 实例化对象,值为该对象的引用地址
//正常运行(但需要注意,如果通过if(value2 != null)判断的话是不会起作用的,应该该对象已经被实例化了)
数组
数组的默认值规则并没有改变。无论是对象类型的数组还是基本数据类型的数组,其默认值都与数组的元素类型有关。
//基本数据类型的数组
int[] array = new int[5]; // 初始化一个长度为5的整数数组
//引用数据类型的数组
String[] array = new String[5]; // 初始化一个长度为5的字符串数组
元素默认值:
- 对象类型的数组(如
String[]
,Integer[]
, 自定义类的数组等),数组中的每个元素都会被初始化为null
。这是因为对象引用类型的默认值就是null
。 - 基本数据类型的数组(如
int[]
,double[]
,boolean[]
等),数组中的每个元素会被初始化为该基本数据类型的默认值。
全局变量为什么能使用默认值
全局变量通常指的是类的成员变量(无论是静态的还是非静态的)。
代码示例
public static char c;
public static void main(String[] args) {
System.out.println((int) c); //输出结果为:0
}
逻辑层面
成员变量声明后,不管有没有对其进行显式初始化,Java虚拟机都会自动给它初始化为默认值。
设计层面
-
对象模型的一致性:在Java中,类的成员变量(全局变量)是对象状态的一部分。为了保持对象模型的一致性和完整性,Java设计为这些变量提供默认值。这样,无论开发者是否显式初始化这些变量,对象都有一个确定的初始状态。
-
简化内存管理:在对象创建时,为其成员变量分配内存并设置默认值是一个相对简单且一致的过程。如果不设置默认值,Java虚拟机(JVM)将需要更复杂的逻辑来确定如何处理未初始化的内存区域,这会增加JVM实现的复杂性。
-
避免未定义行为:如果不为全局变量提供默认值,那么在访问未初始化的变量时,可能会遇到未定义的行为。这可能导致程序崩溃、数据损坏或其他不可预测的结果。通过提供默认值,Java减少了这种风险,使得程序的行为更加可预测和稳定。
-
向后兼容性:Java的设计考虑了与早期版本的兼容性。在Java的早期版本中,全局变量就已经有默认值了。为了保持向后兼容性,Java在后续版本中继续沿用了这一设计。
-
开发者便利性:虽然开发者通常应该显式初始化他们的变量,但提供默认值可以作为一种安全网,防止因疏忽而导致的错误。此外,在某些情况下,开发者可能确实希望使用变量的默认值,而不是立即为其分配一个特定的值。
总结:
Java为了保持对象模型的一致性、简化内存管理、避免未定义行为、保持向后兼容性以及提供开发者便利性。然而,开发者仍然应该谨慎地处理全局变量的初始化,以确保程序的正确性和可靠性。
大白话总结:
全局变量就像家里的东西,一直都有。给它们默认值就像给东西一个初始状态,这样用起来更方便,也更清楚它们现在是什么。全局变量与整个程序紧密相关,默认值能更好地支持程序运行。所以,Java设计时就这么定了。
PS:虽然全局变量有默认值,但这并不意味着开发者应该依赖这些默认值。在实际编程中,为了代码的清晰性、可读性和可维护性,开发者通常应该显式地初始化他们的全局变量,并赋予它们有意义的初始值。
局部变量为什么不能使用默认值
代码示例
public static void main(String[] args) {
int i;
System.out.println(i);
}
运行代码会报未初始化异常错误。
逻辑层面
局部变量声明后,Java虚拟机不会自动的为他初始化默认值,因此局部变量必须进行显式初始化才能被使用。
设计层面
主要原因与局部变量的生命周期和初始化机制有关
-
生命周期与作用域:局部变量仅在声明它的代码块(如方法或循环)内有效,一旦离开这个作用域,它们就不再存在。这意味着局部变量的生命周期相对短暂,且它们的可见性仅限于特定的代码块。与此不同,全局变量(或类的成员变量)的生命周期通常与对象的生命周期一致,且在整个类中都可见。由于局部变量的这种短暂性和局限性,Java设计者不认为为它们提供默认值是有必要的。
-
初始化和赋值:局部变量在声明时必须显式初始化,这是Java语言规范的一部分。这种设计鼓励开发者在使用局部变量之前明确赋予它们值,从而避免潜在的错误和不确定性。相比之下,全局变量可以在没有显式初始化的情况下被赋予默认值,这是因为它们与类的定义紧密相关,且其初始化过程更为复杂和灵活。
-
内存管理与效率:局部变量在每次方法调用时都会被创建和销毁,而全局变量则与对象或类相关联,其生命周期更长。如果为局部变量提供默认值,那么每次创建局部变量时都需要进行额外的内存操作来设置这些默认值,这会增加不必要的内存开销和性能损耗。
-
代码清晰性与可读性:要求局部变量显式初始化有助于提高代码的清晰性和可读性。通过查看代码,开发者可以明确地知道每个局部变量的来源和初始值,这有助于理解和维护代码。如果局部变量有默认值,那么可能会引入一些不易察觉的错误,因为开发者可能会忘记显式地赋予它们特定的值。
总结:
Java强调局部变量的短暂性和局限性、鼓励显式初始化以提高代码质量、减少内存开销以及提高代码的可读性和可维护性。
大白话总结:
局部变量是临时的,用完就没了。给它们默认值就像租东西时被强制塞东西,既麻烦又浪费。局部变量用之前最好自己明确赋值,这样不容易出错,也更清晰。所以,Java设计时就不给局部变量默认值了。