【问题标题】:Java: When declaring objects or intsJava:声明对象或整数时
【发布时间】:2012-01-20 22:12:11
【问题描述】:

在java中创建对象(或任何东西)时,做的有什么区别,例如,

Dog d = new Dog();

而不是做

Dog d;

然后,用

完成它(有时在方法内部和开头)
d = new Dog();

第一个不是更简单更容易吗?为什么人们会采用第二种方式?

【问题讨论】:

    标签: java object declare


    【解决方案1】:

    考虑以下场景。假设Dog的构造函数可以抛出异常:

    try {
        Dog d = new Dog();    
    } catch(Exception ex) {
        // treat exception
    }
    
    d.bark();
    

    这不会编译,因为dtry 块之外不可见。你需要做的是:

    Dog d = null;
    try {
        d = new Dog();    
    } catch(Exception ex) {
        // treat exception
    }
    if(d != null) d.bark();
    

    还有很多其他类似的情况。例如,您可能有一个 if-else 块,其中 d 根据某些条件以不同方式初始化:

    Dog d = null;
    if(/* condition */)
        d = new Dog("Lassie");   
    } else {
        d = new Dog("Sam");
    }
    d.bark();
    

    【讨论】:

    • Dog d = null;Dog d; 有很大的不同。我相信 OP 会询问后一种形式。
    • @Tomasz Nurkiewicz:声明对象而不初始化它们绝不是一个好主意。
    • @Tudor,有时在不初始化对象的情况下声明一个对象是个好主意。声明为final 的对象只能设置一次,有时在声明时不知道需要设置什么。
    • @TomaszNurkiewicz,有什么区别?我以为Dog d; == null
    • @LouisWasserman:未初始化的 field 默认为 null。未初始化的局部变量没有默认值。 必须在使用前显式初始化。这与编译器无关。
    【解决方案2】:

    这个问题缺少一些重要的上下文。如果变量定义和使用在不同的范围内,则存在很大差异。例如:

    class A { 
      Dog d;
    
      void foo() { d = new Dog(); }
    }
    

    ...允许class A 的每个成员访问 Dog。

    如果用法在同一范围内,

    class A {
      void foo() {
         Dog d;
         d = new Dog();
      }
    }
    

    ...那么这是一个可读性问题,因为代码将在一两行中运行相同的代码。

    【讨论】:

      【解决方案3】:

      因为您在声明对象时并不总是知道如何构造它。 例如:

      Dog dog;
      if ("M".equals(sex)) {
          dog = new Dog("Medor");
      }
      else {
          dog = new Dog("Mirza");
      }
      dog.walk();
      

      【讨论】:

      • 这是需要final Dog dog = Dog.create("M") 或者至少是额外的本地方法的地方之一。
      • @TomaszNurkiewicz - 它只是乞求如果你有一种心态说延迟初始化本质上是不好的。我(一方面)对编写和阅读适当使用此功能的代码感到非常满意。
      • @StephenC:+1,我真的不知道通过延迟初始化你仍然可以使用final (final Dog dog;)!
      【解决方案4】:

      这只是声明一个引用(你说d 将具有Dog 类型):

      Dog d;
      

      这是创建一个新对象,并将其分配到引用变量d

      new Dog();
      

      您可以将其结合起来,因为您经常同时使用这两种方法,但并非总是如此。

      【讨论】:

        【解决方案5】:

        虽然习惯性地将声明和初始化分开并不是一个好主意

        • 在某些情况下您需要执行此操作(请参阅 try catch 示例),

        • 在某些情况下它可以提高代码的可读性(参见 Max Schmidt 的示例),

        • 在某些情况下,它会使您的代码更加健壮。

        为了说明最后一点,考虑修改 Max Schmidt 的示例:

        Dog d = null;
        if (input.equals("lab")) {
           d = new Labrador();
        } else if (input.equals("bull")) {
           d = new Bulldog();
        }
        d.walk();
        

        看到错误了吗?如果input 既不是"lab" 也不是"bull",那么当我们遛狗时,代码就会死掉。

        但是,如果我们删除 d 的初始化,那么编译器会告诉我们有一条通过代码的路径使 d 未初始化。如果我们注意,我们会在代码运行之前看到错误并修复它。

        【讨论】:

          【解决方案6】:

          原因很多。一个原因可能是初始化取决于运行时确定的条件。例如,

          Animal pet;
          ...
          if(input == 0) pet = new Dog();
          else pet = new Cat();
          ...
          pet.sleep();
          

          【讨论】:

          • 您的示例将无法编译,因为不能保证分配pet
          • @Steve Kuo 已编辑。这样可以编译吗?
          【解决方案7】:

          这是延迟初始化的粗略示例。在您的程序中,您可能永远不需要 Dog 对象的实际实例。在这些情况下,您可以简单地声明 Dog 引用,它不会消耗太多内存,然后在需要时对其进行初始化。

          【讨论】:

          • 还有@Tudor 所说的,非常相关。
          【解决方案8】:

          对象创建和对象声明。你可以阅读它here

          当您执行Dog d = new Dog(); 时,您正在声明一个Dog 类型的变量d,并使用new 运算符创建该变量。

          因此,您通常会在开始时声明您需要的变量,并仅在真正使用它们时创建它们。

          【讨论】:

            【解决方案9】:

            没有任何原因,这只是糟糕的编码习惯。由于在初始化之前不能使用d,所以提前声明它是没有意义的:

            Dog d;
            //...you cannot use `d` in any way! It won't compile
            d = new Dog();
            //now you can
            

            但是:

            Dog d = null;
            //...
            d = new Dog();
            

            这是有道理的,因为有人可能会检查 null(延迟初始化等)

            为了简单起见,您实际上应该更喜欢:

            final Dog d = new Dog();
            

            【讨论】:

              【解决方案10】:

              有时除了第二种方法之外别无他法,例如,如果狗是拉布拉多犬和斗牛犬的超类:

              Dog d;
              
              if (input == "lab"){
                d = new Labrador();
              }else if {
               d = new  Bulldog();
              }
              
              d.urinate():
              

              【讨论】:

                【解决方案11】:

                第二个可能在您有类似 try/catch 之类的东西将创建 Dog 的情况下更有用,创建 dog 实例不应停止该方法中的其他逻辑。如果你想在 try/catch 之后使用 dog 实例,否则继续你的逻辑。

                如果你在 try/catch 中使用第一个语法,你不能在外面使用它。

                try {
                    Dog d = new Dog();    
                } catch(Exception ex) {
                
                }
                
                d.methodCall();
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-01-18
                  • 2013-03-22
                  • 2020-09-06
                  • 2013-11-11
                  • 1970-01-01
                  • 2018-11-17
                  • 2012-02-26
                  • 1970-01-01
                  相关资源
                  最近更新 更多