一、Java继承
继承是面向对象编程中非常强大的一种机制,首先它可以复用代码,例如当大家让Student从Person继承时,Student就获得了Person的所有功能,大家只需要为Student编写新增的功能。Java使用extends关键字来实现继承:
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
class Student extends Person {
// 不要重复name和age字段or方法,只需要定义新增score字段/方法:
private int score;
public int getScore() { … }
public void setScore(int score) { … }
}
如上所示可见,通过继承,Student只需要编写额外的功能,不再需要重复Person代码。注意到我们在定义Person的时候,没有写extends。在Java中,没有明确写extends的类,编译器会自动加上extends Object。所以,任何类,除了Object,都会继承自某个类。
二、Java:super
super关键字表示父类(超类)。子类引用父类的字段时,可以用super。但是,在某些时候,就必须使用super。大家来看一个栗子:
class Person {
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
protected int score;
public Student(String name, int age, int score) {
this.score = score;
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student("Xiao Ming", 12, 89);
}
}
Java结果如下:
运行上面的代码,会得到一个编译错误,大致意思是在Student的构造方法中,无法调用Person的构造方法,为什么会出现这个错误呢?
这是因为在Java中,任何子类的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地显式调用父类的构造方法,若父类没有默认的构造方法,就会编译报错!因为,好的解决办法或者说良好的写法就是,子类必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。
这里还顺带引出了另一个问题:即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。
正确代码如下,增加一行super():
class Person {
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
protected int score;
public Student(String name, int age, int score) {
super(name, age); // 增加一行,调用父类的构造方法
this.score = score;
}
}
public class java1 {
public static void main(String[] args) {
Student s = new Student("LiLei", 12, 89);
System.out.print( s.name + " " + s.age +" "+ s.score+" ");
}
}
Java结果如下:
三、Python继承
Python与C++、Java一样,也是支持面向对象(OOP)的动态语言的编程语言,因此同样具有面向对象的三大特性:封装、继承、多态。但Python又有一些极具Python自身特色的不同之处,今天微微老师就来和大家讨论一下,Python的继承、__init__初始化、super方法,也许大家之前会用,知道要这么写才能运行程序,否则会报错,但是为什么要这么写,可能想不明白,看完本文,期待能彻底搞清楚了。
大家先来看一个栗子,先写了一个父类Parent及父类的__init__构造函数,然后写了一个子类Child继承父类Parent,也写了子类的__init__构造函数:
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
#子类继承父类
class Child(Parent):
#子类中没有显示调用父类的初始化函数
def __init__(self):
print("call __init__ from Child class")
接下来,将子类Child实例化,看看效果,打印输出什么结果:
#将子类实例化
c = Child()
Python结果如下:
如上图所示的输出结果,不难看出,我们将子类实例化并没有调用父类的构造函数,只是调用了子类的构造函数。由于在子类中没有显示调用父类的初始化函数,则父类的属性不会被初始化,因而此时调用子类中name属性会报错不存在: AttributeError: ‘Child’ object has no attribute ‘name’
四、Python:super
当在Python中出现继承的情况时,一定要注意初始化函数_init_的行为:
1. 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。
2. 如果子类定义了自己的初始化函数,而在子类中没有显式调用父类的初始化函数,则父类的属性不会被初始化。
3. 如果子类定义了自己的初始化函数,在子类中显式调用父类,子类和父类的属性都会被初始化。
因此,Python继承正确而良好的写法,应该是下面代码这样:
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
#子类继承父类
class Child(Parent):
def __init__(self):
print("call __init__ from Child class")
super(Child,self).__init__("小小明")
p = Parent('小明')
c = Child()
print(p.name)
print(c.name)
如上面代码,子类定义了自己的初始化函数,并使用super方法显式调用父类__init__,则子类和父类的属性都会被初始化。
发表评论 取消回复