简体   繁体   English

构造函数(Java)

[英]Constructor (Java)

I wonder if it's a big error (in small one class Java program) when I define variable in a class level rather that using the constructor? 当我在类级别定义变量而不是使用构造函数时,我想知道这是一个很大的错误(在小型Java程序中)? Can we do that? 我们可以这样做吗?

The method body will be the same in both cases. 在两种情况下,方法体都是相同的。

Many thanks! 非常感谢!

eg. 例如。

public class test{

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

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

    /...../

}

You mean 你的意思是

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

instead of 代替

public class Foo {
    private String test;

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

I actually prefer the first method, it is much cleaner. 我其实更喜欢第一种方法,它更清洁。 If you know the value ahead of time and it's a constant, you should set the value as you define it. 如果您提前知道该值并且它是常量,则应在定义时设置该值。 No reason not to from a technical standpoint, and it looks much cleaner. 没有理由不从技术的角度来看,它看起来更清洁。

Update 更新

Given the code sample you add, what you're doing is fine. 鉴于您添加的代码示例,您正在做的事情很好。 One thing to consider is that your constants should be final . 要考虑的一件事是你的常数应该是final In your case they should likely be private static final int . 在你的情况下,他们应该是private static final int

If you mean (as jcm said): 如果你的意思是(如jcm所说):

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

instead of (small edit here): 而不是(小编辑在这里):

public class Foo {
    private String test;

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

If it's a constant , then make it a constant. 如果它是常数 ,那么使它成为常数。 If it isn't, then its value is dependent on the runtime sequence, and I'd plump for the second of those, not the first. 如果不是,那么它的值取决于运行时序列,并且我会为第二个而不是第一个丰满。 I'm not a fan of initializing at declaration-time, it means I have to look at too many places for values. 我不是宣传时初始化的粉丝,这意味着我必须看太多值的地方。 As a matter of style (and this is style, not substance, for the most part), I prefer to declare declarations and assign assignments, not inter-mix the two. 作为一种风格问题(这是风格,而不是实质,大多数情况下),我更喜欢宣布声明和分配作业,而不是混合两者。 Constants are a different thing. 常数是另一回事。

But in a small one-class application, it's not like it matters much. 但在一个小型的一流应用程序中,它并不重要。

Edit : Allowing for your updated code example, which uses class fields rather than instance fields, I probably wouldn't do that at all. 编辑 :允许更新的代码示例,它使用类字段而不是实例字段,我可能根本不会这样做。 (And the question kind of doesn't make sense any more; constructors have nothing to do with static fields.) FWIW, I would generally initialize static fields at declaration time because anything else is very uncommon, even though there are things called "static initializers" you can use when order is important: (并且问题类型没有任何意义;构造函数与静态字段无关。)FWIW,我通常会在声明时初始化静态字段,因为其他任何东西都非常罕见,即使有些东西叫做“静态”初始化程序“您可以在订单重要时使用:

static int foo;
static int bar;

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

But in my experience, their use is rare enough that the least surprising thing is just to initialize the statics at declaration time. 但根据我的经验,它们的使用非常罕见,最不令人惊讶的事情就是在声明时初始化静力学。

它没有任何区别。

Actually, 其实,

if these attributes should have a default value, and your class have more than one constructor, may be a good idea do initiate these variables in "class level", since you may forget to set value of some of these variables. 如果这些属性应该有一个默认值,并且你的类有多个构造函数,那么在“类级别”中启动这些变量可能是个好主意,因为你可能忘记设置其中一些变量的值。

Of course, you could create a method to start these varibles, but even so, you could forget to call this method from some of your constructors. 当然,您可以创建一个方法来启动这些变量,但即便如此,您也可能忘记从某些构造函数中调用此方法。

So, in this sense, this could be considered a good practice. 因此,从这个意义上说,这可以被认为是一种很好的做法。

Do you mean doing something like this? 你的意思是做这样的事吗?

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

If that's what you mean, I see nothing wrong with doing that, it's equivalent to initializing it in the constructor. 如果这就是你的意思,我认为这样做没有错,它相当于在构造函数中初始化它。

Based on your edits, looks like you are really asking about whether it is OK to use static variables. 根据您的编辑,看起来您真的在询问是否可以使用静态变量。 (I note with @TJ that you don't have a constructor at all in your example program!) (我注意到@TJ你的示例程序中根本没有构造函数!)

My answer to that is: 我的答案是:

  • In general, static variables are bad style and a bad idea. 一般来说,静态变量是糟糕的风格和坏主意。

  • In a small application consisting of a single class, it won't make much difference ... unless you later decide to reuse the class in something larger. 在一个由单个类组成的小应用程序中,它不会有太大的区别......除非你后来决定在更大的类中重用该类。

On the other hand, static constants are not bad style; 另一方面,静态常量也不错; eg 例如

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

A rewrite of your example that eliminates the static variables would look something like this: 重写你的例子,消除静态变量看起来像这样:

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 */
    }

    /* ... */
}

The advantage of this over the original version is that you can now safely reuse the Test2 class in other contexts. 与原始版本相比,它的优势在于您现在可以在其他上下文中安全地重用Test2类。 For example this will work: 例如,这将工作:

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

where this is likely to be buggy due to static coupling: 由于静态耦合,这可能是错误的:

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

There's some good advice in other comments about scoping of variables. 关于变量范围的其他评论中有一些很好的建议。 I have another related remark. 我有另一个相关的评论。 I often notice developers getting confused with instance/static variables due to starting off with the main(String arg) method. 我经常注意到开发人员因为使用main(String arg)方法开始而与实例/静态变量混淆。 Because this method is static, one tends to not bother with creating an instance, and ends up with only static methods and fields. 因为这个方法是静态的,所以人们往往不会为创建实例而烦恼,最终只会使用静态方法和字段。 This is no problem for a tiny piece of test code, but as soon as you need multiple classes and an Object-Oriented design, it becomes a nuisance very quickly. 对于一小段测试代码来说,这不是问题,但只要您需要多个类和面向对象的设计,它就会很快变得麻烦。

A useful way to avoid this would be to not start off with the main method, but with a unit test: 避免这种情况的有效方法是不要从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); 
    }
}

Remember to put tests in a separate source directory, ie src/test/java vs src/main/java for your application code. 记得将测试放在一个单独的源目录中,即src / test / java vs src / main / java作为应用程序代码。 This makes it easier to run and deploy your application code separately and follows the Maven 2 default layout. 这样可以更轻松地单独运行和部署应用程序代码,并遵循Maven 2默认布局。

Then your class could look like this (slightly modified to suit my explanation): 然后你的班级看起来像这样(稍作修改以适合我的解释):

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);            
    }    
}

Now just run your unit test. 现在就开始进行单元测试了。 In Eclipse, right-click on the class MyAppTest and choose "Run as JUnit test". 在Eclipse中,右键单击MyAppTest类并选择“Run as JUnit test”。 In this way you will start off on the right Object-Oriented foot. 通过这种方式,您将从正确的面向对象的脚开始。

If you later want to make your application executable, you can either add a main method to MyApp, or create a small bootstrap class to do the work: 如果以后想要使应用程序可执行,可以向MyApp添加main方法,或者创建一个小型引导类来完成工作:

public class MyAppStarter {

    public static void main(String[] args) {

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

The nice thing of this solution is that you can keep the parsing of commandline arguments and other operational details of starting your application separated from the business code. 这个解决方案的好处是你可以将命令行参数的解析和启动应用程序的其他操作细节与业务代码分开。

As a style note, if you're talking about instance variables and where you should initialize those - if in the constructor or in the declaration, I usually prefer initializing in the constructor only what's passed to the constructor (or that are dependent of those parameters), and initializing in the declaration what is not. 作为样式注释,如果您正在讨论实例变量以及应该在哪里初始化它们 - 如果在构造函数或声明中,我通常更喜欢在构造函数中初始化传递给构造函数的内容(或者依赖于这些参数的内容) ),并在声明中初始化什么不是。 I think it's cleaner that way. 我认为这样更干净。

Here is how I do variables in Java: 以下是我在Java中执行变量的方法:

  1. everything is final unless it proves that it cannot be. 一切都是最终的,除非它证明它不可能。
  2. nothing is initialized when it is declared unless it has to be (only those used in switch are done differently) 声明它时,没有任何内容被初始化,除非它必须是(只有在开关中使用的那些不同)
  3. every variable has as small a scope (this includes visibility) as possible 每个变量都具有尽可能小的范围(这包括可见性)

Given that you have the following cases: 鉴于您有以下情况:

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;
     } 
}

To summarize: 总结一下:

  • constants are always UPPER_CASE 常量总是UPPER_CASE
  • class variables are always mixedCase 类变量总是mixedCase
  • constants are always initialized in a static block unless they are used in a switch (compiler requirement) 常量总是在静态块中初始化,除非它们在交换机中使用(编译器要求)
  • class variables are always initialized in a static block 类变量总是在静态块中初始化
  • instance variables are always mixedCase 实例变量总是mixedCase
  • instance variables where the value is known at compile time are initialized in an instance block 在编译时已知值的实例变量在实例块中初始化
  • instance variables where the value is not known at compile time are initialized in the constructors 在编译时未知值的实例变量在构造函数中初始化

The has the benefits of: 它的好处是:

  • can read values from a file (say properties file) since the initialization happens in the static ore 因为初始化发生在静态矿石中,所以可以读取文件中的值(比如属性文件)
  • instance block where you can do things like open the file 实例块,您可以在其中执行打开文件等操作
  • since they are mostly final the compiler will let you know when you forget to initialize them 因为它们大部分是最终的,编译器会在你忘记初始化时告诉你
  • since they are mostly final you have a better chance of having immutable classes which is a safer way to code 因为它们大多是最终的,所以你有更好的机会拥有不可变的类,这是一种更安全的编码方式
  • you have a few well defined places to look for where variables get their values 你有一些明确定义的地方来寻找变量得到它们的价值的地方
  • you can more easily make changes to variable initialization later without screwing it up 您可以更轻松地更改变量初始化,而无需将其搞砸

For that lost point, consider the following code: 对于那个丢失的点,请考虑以下代码:

{
    int x = 0;    

    // this line added later
    x = 7;
}

Why set x to 0 and then to 7 without ever using the 0 (this is a simple case, some are more expensive at runtime). 为什么在没有使用0的情况下将x设置为0然后设置为7(这是一个简单的情况,有些在运行时更昂贵)。 If x was marked as final the person changing it to 7 would realize that they have to get rid of setting it to the pointless 0. 如果x被标记为final,则将其更改为7的人将意识到他们必须摆脱将其设置为无意义的0。

I have been programming in this sort of way since using C/C++ professionally starting in about 1993 (for Java since 1995), and it has served me well. 自从1993年开始专业地使用C / C ++(1995年以来的Java)以来,我一直在以这种方式进行编程,并且它对我有用。

I'm assuming your question is essentially whether it is more proper to assign a default/initial value at the class variable's declaration or in a constructor. 我假设你的问题基本上是在类变量的声明或构造函数中分配默认/初始值是否更合适。 If that's the case, as most of the responses have indicated, it mostly boils down to a style preference. 如果是这种情况,正如大多数回复所指出的那样,它主要归结为风格偏好。

In my experience, I've found that assigning a default value at the class-level declaration makes the code generally more readable and makes the management of the class's constructors a little more manageable. 根据我的经验,我发现在类级声明中分配默认值使代码通常更具可读性,并使类的构造函数的管理更易于管理。 (ie you don't have to a) worry about setting the value in multiple places if your class as multiple constructors or b) worry about creating a generic initialization method that must be called from each constructor). (即,您不必担心如果您的类作为多个构造函数或b)担心创建必须从每个构造函数调用的通用初始化方法,则在多个位置设置值。

There is really no harm in setting the default/initial value of a class variable in the constructor and for small single-constructor classes, the merits of either choice are more or less equal. 在构造函数中设置类变量的默认/初始值确实没有坏处,对于小的单构造函数类,任一选择的优点都或多或少相等。 However if your anticipate the class may grow over time, I would find assigning the value at the declaration would make enhancement of the class a little easier. 但是,如果你预期课程可能会随着时间的推移而增长,我会发现在声明中分配值会使课程的增强更容易一些。

an one-off little program of only main() method? 一个只有main()方法的一次性小程序? why not. 为什么不。

but a better way is to put it inside 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