Python 中的对象与 Python 中的字典非常相似。Test
您可以将and的每个实例视为由您声明的类主体中的代码和分配Subclass
更新的 Dictionary 。__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 — 您只需分配一个值。这就是为什么您能够“覆盖”子类中的值的原因——因为您实际上只是覆盖了同一字段的旧值。因此,在您给出的示例中,item
inSubclass
实际上并没有覆盖item
in Test
;相反,它们是 Python 对象实例中的同一个字段。
在 Java 中,字段实际上属于特定的类。请注意,在您的代码中,您实际上有两个字段声明int item
:一个 inTest
和一个 in Subclass
。当您重新声明int item
in 时,Subclass
您实际上是在隐藏原始字段。请参阅Java 简述:3.4.5。阴影超类字段以获取更多信息。
我不确定你想用你的例子做什么,但这是一种更惯用的 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
有一个getter和setter方法来访问它。这是更多 Java 风格的封装。
这似乎是很多代码,但一个好的 IDE(例如 Eclipse 或 IntelliJ)会为您自动生成很多代码。不过,我仍然认为这是很多样板,这就是我更喜欢 Scala 的原因——但这是一个完全不同的讨论。
编辑:
我的帖子太长了,以至于我忘记了为什么要介绍 getter 和 setter。关键是通过封装对字段的访问,您可以做一些更像 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
字段已被有效地覆盖,因为对其的所有访问都是通过 getter 和 setter 完成的,并且这些已被覆盖以指向新字段。但是,这仍然会导致0 1
输出而不是1 1
您所期望的。
这种奇怪的行为源于您从构造函数中打印的事实——这意味着对象实际上还没有完全初始化。如果在构造期间将引用传递到构造函数之外,这尤其危险,this
因为它可能导致外部代码访问不完整的对象。