繁体   English   中英

构造函数(Java)

[英]Constructor (Java)

当我在类级别定义变量而不是使用构造函数时,我想知道这是一个很大的错误(在小型Java程序中)? 我们可以这样做吗?

在两种情况下,方法体都是相同的。

非常感谢!

例如。

public class test{

    static int column1 = 0;
    static int column2 = 1;

    public static void main(String[] args){
    // do something with variables, no return
    }

    /...../

}

你的意思是

public class Foo {
    private String test = "Hello";
    ...
}

代替

public class Foo {
    private String test;

    public Foo() {
        test = "Hello";
    }
}

我其实更喜欢第一种方法,它更清洁。 如果您提前知道该值并且它是常量,则应在定义时设置该值。 没有理由不从技术的角度来看,它看起来更清洁。

更新

鉴于您添加的代码示例,您正在做的事情很好。 要考虑的一件事是你的常数应该是final 在你的情况下,他们应该是private static final int

如果你的意思是(如jcm所说):

public class Foo {
    private String test = "Hello";
    ...
}

而不是(小编辑在这里):

public class Foo {
    private String test;

    public Foo() {
        this.test = "Hello";
    }
}

如果它是常数 ,那么使它成为常数。 如果不是,那么它的值取决于运行时序列,并且我会为第二个而不是第一个丰满。 我不是宣传时初始化的粉丝,这意味着我必须看太多值的地方。 作为一种风格问题(这是风格,而不是实质,大多数情况下),我更喜欢宣布声明和分配作业,而不是混合两者。 常数是另一回事。

但在一个小型的一流应用程序中,它并不重要。

编辑 :允许更新的代码示例,它使用类字段而不是实例字段,我可能根本不会这样做。 (并且问题类型没有任何意义;构造函数与静态字段无关。)FWIW,我通常会在声明时初始化静态字段,因为其他任何东西都非常罕见,即使有些东西叫做“静态”初始化程序“您可以在订单重要时使用:

static int foo;
static int bar;

// Static initializer
static {
    foo = 7;
    bar = foo + 1;
}

但根据我的经验,它们的使用非常罕见,最不令人惊讶的事情就是在声明时初始化静力学。

它没有任何区别。

其实,

如果这些属性应该有一个默认值,并且你的类有多个构造函数,那么在“类级别”中启动这些变量可能是个好主意,因为你可能忘记设置其中一些变量的值。

当然,您可以创建一个方法来启动这些变量,但即便如此,您也可能忘记从某些构造函数中调用此方法。

因此,从这个意义上说,这可以被认为是一种很好的做法。

你的意思是做这样的事吗?

public class MyClass
{
    private int _someInt = 13;
    private String _someString = "I'm a string.";
}

如果这就是你的意思,我认为这样做没有错,它相当于在构造函数中初始化它。

根据您的编辑,看起来您真的在询问是否可以使用静态变量。 (我注意到@TJ你的示例程序中根本没有构造函数!)

我的答案是:

  • 一般来说,静态变量是糟糕的风格和坏主意。

  • 在一个由单个类组成的小应用程序中,它不会有太大的区别......除非你后来决定在更大的类中重用该类。

另一方面,静态常量也不错; 例如

static final int COLUMN_1 = 0;
static final int COLUMN_2 = 1;

重写你的例子,消除静态变量看起来像这样:

public class Test2 {

    private int column1 = 0;
    private int column2 = 1;

    public static void main(String[] args) {
        new Test2.run(args);
    }

    private void run(String[] args) {
        /* do something with the variables */
    }

    /* ... */
}

与原始版本相比,它的优势在于您现在可以在其他上下文中安全地重用Test2类。 例如,这将工作:

for (int i = 1; i < 10; i++) {
    // call "new Test2().run(args)" in a new thread
}

由于静态耦合,这可能是错误的:

for (int i = 1; i < 10; i++) {
    // call "test.main(args)" in a new thread
}

关于变量范围的其他评论中有一些很好的建议。 我有另一个相关的评论。 我经常注意到开发人员因为使用main(String arg)方法开始而与实例/静态变量混淆。 因为这个方法是静态的,所以人们往往不会为创建实例而烦恼,最终只会使用静态方法和字段。 对于一小段测试代码来说,这不是问题,但只要您需要多个类和面向对象的设计,它就会很快变得麻烦。

避免这种情况的有效方法是不要从main方法开始,而是使用单元测试:

import junit.framework.Assert;
import junit.framework.TestCase;

public class MyAppTest extends TestCase {

    public void testCreateMessage() {

        MyApp myApp = new MyApp("Always write a Te");            
        String message= myApp.createMessage("stackoverflow");   
        assertEquals("Always write a Test", message); 
    }
}

记得将测试放在一个单独的源目录中,即src / test / java vs src / main / java作为应用程序代码。 这样可以更轻松地单独运行和部署应用程序代码,并遵循Maven 2默认布局。

然后你的班级看起来像这样(稍作修改以适合我的解释):

public class MyApp {

    // constants always like this
    private static final int COLUMN_ONE = 0;
    private static final int COLUMN_TWO = 1;

    // make instance variables final if possible
    private final String name;

    public MyApp(String name) {
        this.name = name;
    }

    public void String createMessage(String arg) {
        return name + arg.charAt(COLUMN_ONE) + arg.charAt(COLUMN_TWO);            
    }    
}

现在就开始进行单元测试了。 在Eclipse中,右键单击MyAppTest类并选择“Run as JUnit test”。 通过这种方式,您将从正确的面向对象的脚开始。

如果以后想要使应用程序可执行,可以向MyApp添加main方法,或者创建一个小型引导类来完成工作:

public class MyAppStarter {

    public static void main(String[] args) {

        MyApp myApp = new MyApp(args[0]);
        System.out.println(myApp.createMessage("!!"));
    }
}

这个解决方案的好处是你可以将命令行参数的解析和启动应用程序的其他操作细节与业务代码分开。

作为样式注释,如果您正在讨论实例变量以及应该在哪里初始化它们 - 如果在构造函数或声明中,我通常更喜欢在构造函数中初始化传递给构造函数的内容(或者依赖于这些参数的内容) ),并在声明中初始化什么不是。 我认为这样更干净。

以下是我在Java中执行变量的方法:

  1. 一切都是最终的,除非它证明它不可能。
  2. 声明它时,没有任何内容被初始化,除非它必须是(只有在开关中使用的那些不同)
  3. 每个变量都具有尽可能小的范围(这包括可见性)

鉴于您有以下情况:

public class Foo 
{
    // constants must always be immutable (no changeable state)
    public static final String EXTERNAL_CONSTANT;
    private static final String INTERNAL_CONSTANT;

    public static final int EXTERNAL_CONSTANT_USED_IN_SWITCH = 1;
    private static final int INTERNAL_CONSTANT_USED_IN_SWITCH = 2; 

     // no public variables that can be modified
     private static int internalClassVariable;

     static
     {
         EXTERNAL_CONSTANT = "Hello";
         INTERNAL_CONSTANT = "World";
     }

     private final List<String> constantsMustBeStaticAndFinal;
     private int instanceVariable;

     {
         constantsMustBeStaticAndFinal = new ArrayList<String>();
     }

     public Foo(final int parametersAreAlwaysFinal)
     {
         final int localVariable;

         locatlVariable   = parameterAreALwaysFinal * 10;
         instanceVariable = localVariable;
     } 
}

总结一下:

  • 常量总是UPPER_CASE
  • 类变量总是mixedCase
  • 常量总是在静态块中初始化,除非它们在交换机中使用(编译器要求)
  • 类变量总是在静态块中初始化
  • 实例变量总是mixedCase
  • 在编译时已知值的实例变量在实例块中初始化
  • 在编译时未知值的实例变量在构造函数中初始化

它的好处是:

  • 因为初始化发生在静态矿石中,所以可以读取文件中的值(比如属性文件)
  • 实例块,您可以在其中执行打开文件等操作
  • 因为它们大部分是最终的,编译器会在你忘记初始化时告诉你
  • 因为它们大多是最终的,所以你有更好的机会拥有不可变的类,这是一种更安全的编码方式
  • 你有一些明确定义的地方来寻找变量得到它们的价值的地方
  • 您可以更轻松地更改变量初始化,而无需将其搞砸

对于那个丢失的点,请考虑以下代码:

{
    int x = 0;    

    // this line added later
    x = 7;
}

为什么在没有使用0的情况下将x设置为0然后设置为7(这是一个简单的情况,有些在运行时更昂贵)。 如果x被标记为final,则将其更改为7的人将意识到他们必须摆脱将其设置为无意义的0。

自从1993年开始专业地使用C / C ++(1995年以来的Java)以来,我一直在以这种方式进行编程,并且它对我有用。

我假设你的问题基本上是在类变量的声明或构造函数中分配默认/初始值是否更合适。 如果是这种情况,正如大多数回复所指出的那样,它主要归结为风格偏好。

根据我的经验,我发现在类级声明中分配默认值使代码通常更具可读性,并使类的构造函数的管理更易于管理。 (即,您不必担心如果您的类作为多个构造函数或b)担心创建必须从每个构造函数调用的通用初始化方法,则在多个位置设置值。

在构造函数中设置类变量的默认/初始值确实没有坏处,对于小的单构造函数类,任一选择的优点都或多或少相等。 但是,如果你预期课程可能会随着时间的推移而增长,我会发现在声明中分配值会使课程的增强更容易一些。

一个只有main()方法的一次性小程序? 为什么不。

但更好的方法是把它放在主要内部

public class test{
  public static void main(String[] args){
    int column1 = 0;
    int column2 = 1;
    // do something with variables, no return
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM