[英]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中執行變量的方法:
鑒於您有以下情況:
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;
}
}
總結一下:
它的好處是:
對於那個丟失的點,請考慮以下代碼:
{
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.