Override是面向对象语言的一个特性,在基类定义一个函数/方法,在子类中,重写这个函数/方法,将其表现为另一个形式,从而在继承后,完成多态。而类属性实际上也可以重写。在子类中定义同样名称的类属性,比如a,调用a时,就看不到基类的a了。
下面我们分别用Java和Python做一个说明,设计一个基类和一个子类,并重写一个属性和一个方法。
Java 文件名:SubClass.java
class BaseClass{ int a = 1; public void accessOwner(){System.out.println("base.a="+a);} } public class SubClass extends BaseClass{ int a = 2; @Override public void accessOwner(){ System.out.println("sub.a="+a); super.accessOwner(); } public void accessSuper(){System.out.println("super.a="+super.a);} public static void main(String args[]){ SubClass sc1 = new SubClass(); sc1.accessOwner(); //a=2 换行 base.a=1 System.out.println(); sc1.accessSuper(); //super.a=1 } }
输出为:
1. sub.a=2 2. base.a=1 3. 4. super.a=1
Python
class BaseClass(): a = 1 @classmethod def test(cls): print("base.a=%d"%cls.a) class SubClass(BaseClass): a = 2 @classmethod def test(cls): print("sub.a=%d 注意这里的a已经是子类的a" % cls.a) super(SubClass, cls).test() #now in base:1 in Python 2 or 3 super().test() #同样输出now in base:1 only in Python 3 print("调用基类的a %d" % super().a) def check(self): print("check a=%d %d"% (self.a, id(self.a))) @classmethod def __test__(self): print("hello class method") @staticmethod def staticfunc(): print("static函数不调用类变量和实例变量,定义时不用self") BaseClass.test() print() SubClass.test() c = SubClass() print("Sub.__test__") SubClass.__test__() #调用静态方法示例 SubClass.staticfunc() #可以用类名调用静态方法 c.staticfunc() #可以用实例调用静态方法 #调用实例 print("修改实例的a并且加一个属性b:") c.check() c.a = 99 c.b = 66 print(c.a,c.b) c.check() print("SubClass的a仍然是:%d %d"% (SubClass.a,id(SubClass.a)))
输出:
base.a=1 sub.a=2 注意这里的a已经是子类的a base.a=2 base.a=2 调用基类的a 1 Sub.__test__ hello class method static函数不调用类变量和实例变量,定义时不用self static函数不调用类变量和实例变量,定义时不用self 修改实例的a并且加一个属性b: check a=2 140727241862944 99 66 check a=99 140727241866048 SubClass的a仍然是:2 140727241862944
Python的类属性在类方法中的调用和Java有点不同,如果使用子类的类方法test调用类属性a,需要传一个参数cls给方法,这时,cls.a就是子类的值了。如果只写a或者硬是写一个self.a,都会被认为没有定义。实际上,cls也可以换为self,在这个方法定义中效果是一样的,如果把subClass中的cls全部换成self,会看到一样的输出。
Python的类属性a在实例中被重新定义后,就会生成一个新的id,用一个新指针去指向它,这跟新加一个属性没太大区别了。
上述例子中,原来的类属性a id是140727241862944,重新定义后,再次调用SubClass.a可以看到仍然是这个值。但是,实例去调用a,id已经变了。