Pythonのオブジェクトは、Pythonの辞書とほとんど同じです。Test
およびの各インスタンスは、宣言するクラスの本体のコードと割り当てSubclass
によって更新されるディクショナリと考えることができます。__init__
あなたが書いたコードが次のように機能しているのを想像することができます:
class Test(object):
item = 0 # self['item'] = 0
def __init__(self):
print(self.item) # print(self['item'])
def test(self):
print(self.item) # print(self['item'])
class Subclass(Test):
item = 1 # self['item'] = 1
s = Subclass() # Test.__init__({})
s.test()
Pythonはダックタイピングを使用item
しているので、インスタンスを持っているものは何でもプロパティの一部にすぎません。実際にアイテムを宣言する必要はなく、値を割り当てるだけであることに注意してください。これが、サブクラスの値を「オーバーライド」できる理由です。実際には、同じフィールドの古い値を上書きしているだけだからです。したがって、あなたが与えた例では、item
inSubclass
は実際にはinをオーバーライドしていません。むしろ、それらはPythonオブジェクトインスタンスの同じフィールドです。item
Test
Javaでは、フィールドは実際には特定のクラスに属しています。コードに実際にフィールドの2つの宣言があることに注意してくださいint item
。1つはinでTest
、もう1つはinSubclass
です。を再宣言すると、実際には元のフィールドがシャドウイングint item
されます。一言で言えばJavaを参照してください:3.4.5。詳細については、スーパークラスフィールドのシャドウイングを参照してください。Subclass
あなたがあなたの例で何をしようとしているのか正確にはわかりませんが、これはより慣用的なJavaアプローチです:
public class Test {
private int item;
public Test() {
this(0); // Default to 0
}
public Test(int item) {
setItem(item);
test();
}
public void test() {
System.out.println(getItem());
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.test();
}
public void setItem(int item) {
this.item = item;
}
public int getItem() {
return item;
}
}
class Subclass extends Test {
public Subclass() {
super(1); // Default to 1
}
}
の値がitem
、単純な割り当てではなく、コンストラクター引数を介して設定されていることに注目してください。また、どのようになっているか、それにアクセスするためのゲッターとセッターitem
のメソッドがあるprivate
ことに注意してください。これは、よりJavaスタイルのカプセル化です。
これは多くのコードのように見えますが、優れたIDE(EclipseやIntelliJなど)は多くのコードを自動生成します。それでもボイラープレートがたくさんあると思うので、Scalaが好きですが、それはまったく別の議論です。
編集:
私の投稿は非常に長くなり、ゲッターとセッターを紹介したかった理由がわかりませんでした。重要なのは、フィールドへのアクセスをカプセル化することで、Pythonで行っていたようなことを実行できるということです。
public class Test {
// Same as above . . .
}
class Subclass extends Test {
private int subclassItem = 1;
public int getItem() {
return subclassItem;
}
public void setItem(int item) {
this.subclassItem = item;
}
}
これで、item
フィールドへのすべてのアクセスがゲッターとセッターを介して行われるため、フィールドは事実上オーバーライドされ、それらは新しいフィールドを指すようにオーバーライドされました。ただし、これでも、期待した0 1
ものではなく、出力が生成されます。1 1
この奇妙な動作は、コンストラクター内から印刷しているという事実に起因しています。つまり、オブジェクトは実際にはまだ完全に初期化されていません。this
これは、構築中にコンストラクターの外部に参照が渡された場合に特に危険です。これは、外部コードが不完全なオブジェクトにアクセスする可能性があるためです。