87

根据我的参考,原始类型具有默认值,而对象为空。我测试了一段代码。

public class Main {
    public static void main(String[] args) {
        int a;
        System.out.println(a);
    }
}

该行将System.out.println(a);是指向变量的错误avariable a might not have been initialized而在给定的引用中,integer将具有0默认值。但是,使用下面给定的代码,它实际上会打印0.

public class Main {
    static int a;
    public static void main(String[] args) {
        System.out.println(a);
    }
}

第一个代码可能出现什么问题?类变量的行为与局部变量不同吗?

4

10 回答 10

86

在第一个代码示例中,a是一个main方法局部变量。方法局部变量在使用前需要初始化。

在第二个代码示例中,a是类成员变量,因此它将被初始化为默认值。

于 2013-10-02T06:48:13.957 回答
69

更仔细地阅读您的参考资料:

默认值

声明字段时并不总是需要赋值。 已声明但未初始化的字段将由编译器设置为合理的默认值。一般来说,此默认值将为零或空,具体取决于数据类型。然而,依赖这样的默认值通常被认为是糟糕的编程风格。

下表总结了上述数据类型的默认值。

. . .

局部变量略有不同;编译器永远不会为未初始化的局部变量分配默认值。如果您无法在声明它的地方初始化局部变量,请确保在尝试使用它之前为其分配一个值。访问未初始化的局部变量将导致编译时错误。

于 2013-10-02T15:45:26.473 回答
22

这些是涉及的主要因素:

  1. 成员变量(默认OK)
  2. 静态变量(默认OK)
  3. final 成员变量(未初始化,必须在构造函数上设置)
  4. 最终静态变量(未初始化,必须在静态块 {} 上设置)
  5. 局部变量(未初始化)

注意 1:您必须在每个已实现的构造函数上初始化最终成员变量!

注意2:您必须在构造函数本身的块内初始化最终成员变量,而不是调用另一个初始化它们的方法。例如,这是无效的:

private final int memberVar;

public Foo() {
    // Invalid initialization of a final member
    init();
}

private void init() {
    memberVar = 10;
}

注 3:数组是 Java 中的对象,即使它们存储原语。

注意 4:当你初始化一个数组时,它的所有项目都设置为默认值,与成员或本地数组无关。

我附上了一个代码示例,介绍了上述案例:

public class Foo {
    // Static and member variables are initialized to default values

    // Primitives
    private int a; // Default 0
    private static int b; // Default 0

    // Objects
    private Object c; // Default NULL
    private static Object d; // Default NULL

    // Arrays (note: they are objects too, even if they store primitives)
    private int[] e; // Default NULL
    private static int[] f; // Default NULL

    // What if declared as final?

    // Primitives
    private final int g; // Not initialized. MUST set in the constructor
    private final static int h; // Not initialized. MUST set in a static {}

    // Objects
    private final Object i; // Not initialized. MUST set in constructor
    private final static Object j; // Not initialized. MUST set in a static {}

    // Arrays
    private final int[] k; // Not initialized. MUST set in constructor
    private final static int[] l; // Not initialized. MUST set in a static {}

    // Initialize final statics
    static {
        h = 5;
        j = new Object();
        l = new int[5]; // Elements of l are initialized to 0
    }

    // Initialize final member variables
    public Foo() {
        g = 10;
        i = new Object();
        k = new int[10]; // Elements of k are initialized to 0
    }

    // A second example constructor
    // You have to initialize final member variables to every constructor!
    public Foo(boolean aBoolean) {
        g = 15;
        i = new Object();
        k = new int[15]; // Elements of k are initialized to 0
    }

    public static void main(String[] args) {
        // Local variables are not initialized
        int m; // Not initialized
        Object n; // Not initialized
        int[] o; // Not initialized

        // We must initialize them before use
        m = 20;
        n = new Object();
        o = new int[20]; // Elements of o are initialized to 0
    }
}
于 2015-12-26T18:01:05.493 回答
10

在声明原始类型值时,有几件事情要记住。

他们是:

  1. 在方法中声明的值不会被赋予默认值。
  2. 声明为实例变量或静态变量的值将分配默认值,即 0。

所以在你的代码中:

public class Main {
    int instanceVariable;
    static int staticVariable;
    public static void main(String[] args) {
        Main mainInstance = new Main()
        int localVariable;
        int localVariableTwo = 2;
        System.out.println(mainInstance.instanceVariable);
        System.out.println(staticVariable);
       // System.out.println(localVariable); // Will throw a compilation error
        System.out.println(localVariableTwo);
    }
}
于 2017-07-19T00:49:49.983 回答
3

是的,实例变量将被初始化为默认值。对于局部变量,需要在使用前进行初始化:

public class Main {

    int instaceVariable; // An instance variable will be initialized to the default value

    public static void main(String[] args) {
        int localVariable = 0; // A local variable needs to be initialized before use
    }
}
于 2013-10-02T06:47:57.947 回答
2

局部变量没有默认值。如果没有通过某种方式分配值,它们的初始值是未定义的。在你可以使用局部变量之前,它们必须被初始化。

在类级别(作为成员,即作为字段)和方法级别声明变量时有很大的不同。

如果您在类级别声明一个字段,它们会根据其类型获得默认值。如果您在方法级别或作为块声明变量(表示 {} 内的任何代码),则不会获得任何值并保持未定义,直到它们以某种方式获得一些起始值,即分配给它们的一些值。

于 2017-07-05T05:41:37.303 回答
1

在 Java 中,默认初始化仅适用于类成员的实例变量。

它不适用于局部变量。

于 2014-01-22T12:07:30.603 回答
1

所有成员变量都必须加载到堆中,因此在创建类实例时必须使用默认值初始化它们。

如果是局部变量,它们不会被加载到堆中。它们存储在堆栈中,直到它们被使用。这是在 Java 7 之前,所以我们需要显式地初始化它们。

于 2013-10-02T06:48:36.600 回答
0

我编写了以下函数来返回原始或数字的默认表示0 或 false :

/**
 * Retrieves the default value 0 / false for any primitive representative or
 * {@link Number} type.
 *
 * @param type
 *
 * @return
 */
@SuppressWarnings("unchecked")
public static <T> T getDefault(final Class<T> type)
{
    if (type.equals(Long.class) || type.equals(Long.TYPE))
        return (T) new Long(0);
    else if (type.equals(Integer.class) || type.equals(Integer.TYPE))
        return (T) new Integer(0);
    else if (type.equals(Double.class) || type.equals(Double.TYPE))
        return (T) new Double(0);
    else if (type.equals(Float.class) || type.equals(Float.TYPE))
        return (T) new Float(0);
    else if (type.equals(Short.class) || type.equals(Short.TYPE))
        return (T) new Short((short) 0);
    else if (type.equals(Byte.class) || type.equals(Byte.TYPE))
        return (T) new Byte((byte) 0);
    else if (type.equals(Character.class) || type.equals(Character.TYPE))
        return (T) new Character((char) 0);
    else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE))
        return (T) new Boolean(false);
    else if (type.equals(BigDecimal.class))
        return (T) BigDecimal.ZERO;
    else if (type.equals(BigInteger.class))
        return (T) BigInteger.ZERO;
    else if (type.equals(AtomicInteger.class))
        return (T) new AtomicInteger();
    else if (type.equals(AtomicLong.class))
        return (T) new AtomicLong();
    else if (type.equals(DoubleAdder.class))
        return (T) new DoubleAdder();
    else
        return null;
}

当底层 SQL 查询返回 null 而不是 0 时,我在休眠 ORM 投影查询中使用它。

/**
 * Retrieves the unique result or zero, <code>false</code> if it is
 * <code>null</code> and represents a number
 *
 * @param criteria
 *
 * @return zero if result is <code>null</code>
 */
public static <T> T getUniqueResultDefault(final Class<T> type, final Criteria criteria)
{
    final T result = (T) criteria.uniqueResult();

    if (result != null)
        return result;
    else
        return Utils.getDefault(type);
}

关于 Java的许多不必要的复杂事情之一,使其使用起来不直观。为什么实例变量用默认值 0 初始化但局部变量不是不合逻辑的。类似于为什么枚举没有内置标志支持和更多选项。与 C# 相比,Java lambda 是一场噩梦,不允许类扩展方法也是一个大问题。

Java 生态系统提出了为什么它不可能的借口,但我作为用户/开发人员我不关心他们的借口。我想要简单的方法,如果他们不解决这些问题,他们将来会松懈,因为 C# 和其他语言不会等待让开发人员的生活更简单。自从我每天使用 Java 以来,看到过去 10 年的衰落真是令人难过。

于 2021-02-06T19:41:50.850 回答
-1

在第一种情况下,您将“int a”声明为局部变量(在方法内声明)并且局部变量没有获得默认值。

但是实例变量被赋予静态和非静态的默认值。

实例变量的默认值:

整数 = 0

浮动,双 = 0.0

参考变量=空

char = 0(空格字符)

布尔 = 假

于 2021-01-18T12:52:19.640 回答