use*_*790 7 python java inheritance
执行的Python代码:
class Test(object):
item = 0
def __init__(self):
print(self.item)
def test(self):
print(self.item)
class Subclass(Test):
item = 1
s = Subclass()
s.test()
Run Code Online (Sandbox Code Playgroud)
得到:
1
1
Run Code Online (Sandbox Code Playgroud)
执行类比Java代码:
public class Test {
int item = 0;
Test(){
System.out.println(this.item);
}
void test(){
System.out.println(this.item);
}
public static void main(String[] args){
Subclass s = new Subclass();
s.test();
}
}
class Subclass extends Test {
int item = 1;
}
Run Code Online (Sandbox Code Playgroud)
得到:
0
0
Run Code Online (Sandbox Code Playgroud)
显然,从基类继承的Java方法(Test)也使用基类的成员变量.Python方法使用派生类(Subclass)的成员变量.
问题:有没有办法在Java中实现相同或至少类似的行为?
Python 中的对象与 Python 中的字典非常相似。您可以将Test
和的每个实例视为一个字典,该字典由您声明的类主体中的代码和赋值Subclass
进行更新。__init__
您可以想象您编写的代码的工作原理如下:
class Test(object): \n item = 0 # self[\'item\'] = 0\n\n def __init__(self):\n print(self.item) # print(self[\'item\'])\n\n def test(self):\n print(self.item) # print(self[\'item\'])\n\nclass Subclass(Test): \n item = 1 # self[\'item\'] = 1\n\ns = Subclass() # Test.__init__({})\ns.test() \n
Run Code Online (Sandbox Code Playgroud)\n\nPython 使用鸭子类型,因此item
它只是您碰巧拥有实例的任何属性的一些属性。请注意,您实际上不必声明item \xe2\x80\x94,只需分配一个值即可。这就是为什么您能够“覆盖”子类\xe2\x80\x94 中的值,因为您实际上只是覆盖同一字段的旧值。因此,在您给出的示例中,initem
实际上Subclass
并没有覆盖in ;相反,它们是 Python 对象实例中的相同字段。item
Test
在Java中,字段实际上属于特定的类。请注意,在代码中实际上有两个字段声明:int item
一个 inTest
和一个 in Subclass
。当您重新声明int item
in时Subclass
,您实际上是在隐藏原始字段。请参阅Java 简介:3.4.5。关注超类字段以获取更多信息。
我不确定你到底想用你的例子做什么,但这是一种更惯用的 Java 方法:
\n\npublic class Test {\n\n private int item;\n\n public Test() {\n this(0); // Default to 0\n }\n\n public Test(int item) {\n setItem(item);\n test();\n }\n\n public void test() {\n System.out.println(getItem());\n }\n\n public static void main(String[] args) {\n Subclass s = new Subclass();\n s.test();\n }\n\n public void setItem(int item) {\n this.item = item;\n } \n\n public int getItem() {\n return item;\n }\n\n}\n\nclass Subclass extends Test {\n\n public Subclass() {\n super(1); // Default to 1\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n请注意 的值item
是如何通过构造函数参数而不是简单的赋值来设置的。另请注意item
,private
现在有一个getter和setter方法来访问它。这是更多Java风格的封装。
这看起来像是很多代码,但是一个好的 IDE(例如 Eclipse 或 IntelliJ)会自动为您生成大量代码。我仍然认为它有很多样板,这就是为什么我更喜欢 Scala\xe2\x80\x94,但这是一个完全不同的讨论。
\n\n编辑:
\n\n我的帖子太长了,以至于我忘记了为什么要引入 getter 和 setter。重点是,通过封装对字段的访问,您可以做一些更像 Python 中的事情:
\n\npublic class Test {\n // Same as above . . .\n}\n\nclass Subclass extends Test {\n\n private int subclassItem = 1;\n\n public int getItem() {\n return subclassItem;\n }\n\n public void setItem(int item) {\n this.subclassItem = item;\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n现在,该item
字段已被有效覆盖,因为对它的所有访问都是通过 getter 和 setter 完成的,并且这些已被覆盖以指向新字段。但是,这仍然会导致0 1
输出而不是1 1
您期望的结果。
这种奇怪的行为源于这样一个事实:您是从构造函数 xe2x80x94 中打印的,这意味着该对象实际上尚未完全初始化。如果在构造期间将引用传递到构造函数外部,则这尤其危险,this
因为它可能导致外部代码访问不完整的对象。