Java中的默认值和初始化

时间:2013-10-02 06:46:29

标签: java initialization global-variables default-value local-variables

基于我的reference,原始类型具有默认值,而对象为空。我测试了一段代码。

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

System.out.println(a);将是指向a变量variable a might not have been initialized的错误,而在给定参考中,integer0作为默认值。但是,使用下面给出的代码,它实际上会打印0

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

第一个代码可能出错? class instance 变量的行为是否与局部变量不同?

10 个答案:

答案 0 :(得分:62)

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

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

答案 1 :(得分:59)

仔细阅读reference

  

默认值

     

声明字段时,并不总是需要指定值。   声明但未初始化的字段将设置为a   编译器合理默认。一般来说,这是默认的   将为零或null,具体取决于数据类型。依靠这样的   但是,默认值通常被认为是错误的编程   风格。

     

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

     

。 。 。

     

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

答案 2 :(得分:14)

这些是主要因素:

  1. 成员变量(默认确定)
  2. 静态变量(默认确定)
  3. 最终成员变量(未初始化,必须在构造函数上设置)
  4. 最终的静态变量(未初始化,必须在静态块{}上设置)
  5. 局部变量(未初始化)
  6. 注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 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 usage
            m = 20;
            n = new Object();
            o = new int[20]; //elements of o are initialized to 0
        }
    }
    

答案 3 :(得分:6)

在声明基本类型值时,需要注意几点。

他们是:

  1. 不会为方法内声明的值分配默认值。
  2. 声明为实例变量或静态变量的值将分配默认值0。
  3. 所以在你的代码中:

    .canvasInfo {
      margin: 0 auto;
      width: 500px;
    }
    
    .hr {
      margin: 10px 0;
      border-bottom: 1px solid red;  
    }
    
    .canvasInfo__block {
      position: relative;
      overflow: auto;
      width: 400px;
      height: 120px;
      border: 2px solid red;
    }
    
    .canvasInfo__block2 {
      position: relative;
      overflow: visible;
      height: 300px;
      width: 300px;
      margin-left: auto;
      margin-right: auto;
      border: 2px solid blue;
    }
    
    .grayBlock {
      width: 50px;
      height: 50px;
      background-color: gray;
      position: absolute;
      top: 0px;
      left: -20px;
      z-index: -1;
    }
    .row {
      border: 1px solid gray;
      position: relative;
    }
    .circle
    {
      position: relative;
      width: 10px;
      height: 10px;
      display: inline-block;
      border-radius: 60px;
      box-shadow: 0px 0px 2px #000;
      span {
        margin-left: 20px;
      }
    }
    

答案 4 :(得分:2)

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

public class Main {
      int instaceVariable; // Instance variable will be initalized to default value
    public static void main(String[] args) {
        int localVariable = 0; // Local Variable Need to initalize before use
    }
}

答案 5 :(得分:1)

局部变量不会获得默认值。它们的初始值是未定义的,没有通过某种方式分配值。在使用局部变量之前,必须初始化它们。

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

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

答案 6 :(得分:0)

所有成员变量都必须加载到堆中,因此在创建类的实例时必须使用默认值初始化它们。在局部变量的情况下,它们不会被加载到堆中,它们被存储在堆栈中,直到它们在java 7之前被使用,因此我们需要显式初始化它们。

答案 7 :(得分:0)

在java中,默认初始化仅适用于类成员的实例变量 它不适用于局部变量。

答案 8 :(得分: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# 和其他语言不会等待让开发人员的生活变得更简单。它只是悲伤地看到的下降在过去的10年,因为我与Java的日常工作。

答案 9 :(得分:-1)

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

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

实例变量的默认值:

整数 = 0

浮动,双精度 = 0.0

引用变量 = null

char = 0(空格字符)

布尔值 = 假