继承是面向对象中的第二大主要特点,其核心本质在于可以将父类的功能一直延续下去。
观察以下代码,区别 之前学习的概念与现在程序的区别,比如:现在定义两个,一个是Person,一个是Student。
Person | Student |
---|---|
class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } | class Student{ private String name; private int age; private String school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } } |
通过以上两个简单代码对比,可发现程序出现大量重复,最为关键的是,学生也是属于一个人,两个类之间没有联系。之前所学习的概念不足以解决多个类之间的代码重复消除问题。
使用继承来实现父类代码的重用问题,程序中可以使用extends关键字实现继承操作的定义,语法:
--子类,也被称为派生类; --extends本质上属于继承概念,但是翻译为扩展、扩充 的意思; --父类本质上在Java成为超类(Super Class);
【举例】:继承的实现
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Student student = new Student();
student.setName("张三");
student.setAge(10);
System.out.println("姓名:"+student.getName()+",年龄:"+student.getAge());
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
}
由以上可知,子类继承了父类后,对于父类的支持方法不会减少,但是子类也可以进一步扩充属于自己的属性和方法。长江后浪推前浪就是这个道理~
【举例】:子类扩充方法
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Student student = new Student();
student.setName("张三");
student.setAge(10);
student.setSchool("家里蹲");
System.out.println("姓名:"+student.getName()+",年龄:"+student.getAge()+",学校:"+student.getSchool());
}
}
class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
由以上继承操作可以发现:
虽然继承的核心目的在于扩充类中的已有功能,但是也有限制,这些限制必须注意:
错误代码 | 正确代码 |
---|---|
class A{} class B{} class C extends A,B{} | class A{} class B extend A{} class C extends B{} |
【举例】:观察显式继承
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
B b = new B();
b.setName("张三");
System.out.println(b.getName());
}
}
class A{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class B extends A{
}
对于子类B有name属性,但是这个属性,子类B不能直接操作
由以上,此时name属于隐式继承,只能间接操作,或不能操作,而所有的setter方法属于显式继承,其可以直接调用。
【举例】:观察实例化过程
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
B b = new B();
}
}
class A{
public A() {
System.out.println("*****************");
}
}
class B extends A{
public B() {
System.out.println("=================");
}
}
如果现在非要为子类加上一个调用父类构造的标记,可以使用super()的形式,按如下加入,输出结构和以上是一样的。
class B extends A{
public B() {
super();//表示由子类构造调用父类构造,加不加实际上没什么区别
System.out.println("=================");
}
}
以上可以证明,在子类的构造方法中隐藏着super语句,但是在进行无参父类构造调用的时候,写上super是没有意义的,往往是在父类没有提供无参构造时使用。
以上,类A中没有无参构造方法,B中注释掉super还是会报错,此时使用隐藏的super并不合适,所以应该明确调用使用指定参数的构造方法,以下代码再次编译OK。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
B b = new B("张三");
}
}
class A{
public A(String name) {
System.out.println("*****************");
}
}
class B extends A{
public B(String name) {
super(name);//表示由子类构造调用父类构造,加不加实际上没什么区别
System.out.println("=================");
}
}
大多数情况下,父类一般都会提供有无参构造方法,这个时候可以在子类构造中不出现super语句,但是,若父类中没有提供无参构造方法,那么子类中就必须使用super()调用指定参数的构造方法。
【分析】:关于this() 与 super()的问题
之前学习的this()表示调用本类的其他构造方法,而super() 指由子类调用父类中指定 的构造方法,这两个语句都一定出现在首行,也就是说这两个语句不能同时出现。