Java和Python中继承的区别
执行的Python代码:Java和Python中继承的区别,java,python,inheritance,Java,Python,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() 给出: 1 1 0 0 执行的模拟Java代码: public class Test
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()
给出:
1
1
0
0
执行的模拟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;
}
给出:
1
1
0
0
显然,从基类(Test)继承的Java方法也使用基类的成员变量。Python方法使用派生类(子类)的成员变量
问题是:有没有办法在Java中实现与Python相同或至少相似的行为?使用,而不是重新定义字段:
public class Test {
int item = 0;
...
}
public class Subclass extends Test {
{
item = 1;
}
}
注意:根据您的包结构,您可能希望将
项声明为。Python中的对象与Python中的字典非常相似。您可以将测试
和子类
的每个实例看作是一个字典,由您声明的类体中的\uuuuu init\uuuuuu>代码和赋值更新。您可以想象您编写的代码是这样工作的:
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使用duck类型,因此item
只是您碰巧拥有的实例的一些属性。请注意,您实际上不必声明项,只需指定一个值即可。这就是为什么您能够“覆盖”子类中的值,因为您实际上只是覆盖同一字段的旧值。因此,在您给出的示例中,子类
中的项
实际上并没有覆盖测试中的项
;相反,它们是Python对象实例中的同一字段
在Java中,字段实际上属于特定的类。请注意,在代码中,实际上有两个字段int item
的声明:一个在Test
中,另一个在子类中。在子类
中重新声明int项
时,实际上是在隐藏原始字段。有关更多信息,请参阅
我不确定您想用示例做什么,但这是一种更惯用的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,但这是一个完全不同的讨论
编辑:
我的帖子太长了,以至于我忘了为什么我要引进能手和二传手。要点是,通过封装对字段的访问,您可以执行与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
这种奇怪的行为源于这样一个事实:您正在从构造函数中打印,这意味着对象实际上尚未完全初始化。如果在构造过程中将此
引用传递到构造函数外部,这尤其危险,因为它可能导致外部代码访问不完整的对象。您可以重载超类构造函数,以将测试中的项
字段初始化为0:
public class Test {
int item = 0;
Test(){
System.out.println(this.item);
}
Test(int item) {
this.item = item;
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 {
public Subclass() {
super(1);
}
}
@flep这是Java中实现与python类似结果的入侵性最小的方法,您可以创建一个构造函数来初始化项
,但是根据OP的需要,这个解决方案也可以工作。太好了!二传手和接球手都很痛苦,但效果很好。