面向对象一个非常重要的特性,继承特性,当看到了这个extends,似乎就可以很大程度上确定了,这是oop语言,那么问题来了:
1,为什么要有继承?
2,继承有哪些限制?
3,子类的实例化的具体过程
4,方法的覆写
5,super关键字的作用
-那么首先得知道,什么是继承。然后再说为什么要有继承。
没比较就没伤害,先看看不使用继承的代码,然后再和继承的代码比较下,就发现了为什么要有继承了。
class Person{ // 定义Person类
private String name ; // 定义name属性
private int age ; // 定义age属性
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
};
class Student{ // 定义Student类
private String name ; // 定义name属性
private int age ; // 定义age属性
private String school ; // 定义school属性
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public void setSchool(String school){
this.school = school ;
}
public String getSchool(){
return this.school ;
}
};
1,开篇的第一个问题—>为什么要有继承?
问题:
直观的发现,1,代码重复率太高了。2,从逻辑关系上来说,学生也是人,不应该将他们写成两个独立的类。
解决方案:
当然是使用继承,继承的出现就是为了解决这样的问题的。
继承:子类继承父类,可以扩展已有类的功能。可以把父类中的非私有的内容拿过来,在子类中继续使用。准确的说,父类中public的或者default(就是不加权限修饰符的),可以直接在子类中使用,protected的,子类和父类需要在一个包下才可以使用,对于父类中private的,子类是看不到的,无法直接使用这些private功能,但是可以通过想办法,比如设置setter以及getter的方法访问这些私有的内容。
继承也叫扩展,子类也称为派生类。
class Person{ // 定义Person类
private String name ; // 定义name属性
private int age ; // 定义age属性
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
};
class Student extends Person{ // 定义Student类
// 此处不添加任何的代码
};
public class ExtDemo02{
public static void main(String arsg[]){
Student stu = new Student() ;// 实例化子类对象
stu.setName("张三") ; // 此方法在Student类中没有明确定义
stu.setAge(30) ;
System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() ) ;
}
};
Stuent继承了Person,虽然在Person中没有写任何代码,但是可以使用Person类中的功能。
可以把父类中的内容拿过来,直接在子类中使用,这样一来,子类和父类相比如果有一些重复的内容,就不用重复定义了。
class Person{ // 定义Person类
private String name ; // 定义name属性
private int age ; // 定义age属性
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
};
class Student extends Person{ // 定义Student类
private String school ; // 定义school属性
public void setSchool(String school){
this.school = school ;
}
public String getSchool(){
return this.school ;
}
};
public class ExtDemo03{
public static void main(String arsg[]){
Student stu = new Student() ;// 实例化子类对象
stu.setName("张三") ; // 此方法在Student类中没有明确定义
stu.setAge(30) ;
stu.setSchool("清华大学") ;
System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool() ) ;
}
};
这样的代码看起来,似乎就清爽多了,子类扩展了父类的功能。
2,开篇的第二个问题—->继承的限制:
限制1:
Java中,不能多重继承,但是可以多层继承。
多重继承:
class A{
};
class B{
};
class C extends A,B{ // 错误,同时继承了两个父类
};
多层继承:
class A{
};
class B extends A{
};
class C extends B{
};
类的继承关系,一般是通过类图来描述。
限制2:
不让直接访问,如果一定要访问呢?必然是可以的,可以通过想办法,间接进行访问。
3,开篇第三个问题:子类对象的实例化具体过程。
子类在实例化的时候,会默认调用父类中的无参构造方法,如果希望调用有参数构造,则必须在子类中明确声明,就是使用关键字super(x,x,x);
class Person{ // 定义Person类
private String name ; // 定义name属性
private int age ; // 定义age属性
public Person(){
System.out.println("父类Person中的构造。") ;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
};
class Student extends Person{ // 定义Student类
private String school ; // 定义school属性
public Student(){
super() ; // 默认隐藏
System.out.println("子类Student中的构造。") ;
}
public void setSchool(String school){
this.school = school ;
}
public String getSchool(){
return this.school ;
}
};
public class InstanceDemo{
public static void main(String arsg[]){
Student stu = new Student() ;// 实例化子类对象
stu.setName("张三") ; // 此方法在Student类中没有明确定义
stu.setAge(30) ;
stu.setSchool("清华大学") ;
System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool() ) ;
}
};
代码执行顺序—>先走了父类的构造然后走了子类自己的构造。
4,开篇第四个问题:方法的覆写,还有属性的覆盖。
4.1方法的覆写:
class Person{ // 定义父类
void print(){ // 默认的访问权限
System.out.println("Person --> void print()。") ;
}
};
class Student extends Person{ // 定义继承关系
public void print(){
System.out.println("Student --> void print()。") ;
}
};
public class OverrideDemo03{
public static void main(String args[]){
Student s = new Student() ;
s.print() ;
}
};
这里打印出了覆写过的子类的方法的内容,因为子类中覆写了父类中的方法,但是如果子类中没有覆写父类中的方法,则会直接去父类中去寻找这个方法。
那么问题来了,我子类中覆写了父类中的方法,但是,此时我实例化了子类的对象,正常情况,调用的是子类中覆写过的方法,但是,因为继承的原因,我子类中肯定也是继承了父类中的这个方法的,问题是:我就是想访问这个继承过来的父类中的方法,该怎么办呢?
问题:
既然子类中继承了父类中的方法,子类中又覆写了父类中的这个方法,实例化了子类对象,虽然正常情况是访问了子类中的这个方法,但是我就是倔强就是要访问父类中的这个方法,就是倔强的要使用这个子类对象访问从父类中继承过来的那个父类中的方法,该怎么处理呢?
解决方案:
必然是有解决办法的了:super关键字就是可以解决这样的问题。super关键字就是表示,直接从子类访问父类中的内容,
正常情况,子类对象访问一个方法,如果子类中有这个方法,则直接调用,如果子类中没有这个方法,就会去父类中去寻找,如果父类中也没有,就会报错了。
所以,这个调用的先后优先级就一幕了然了。
super关键字,就是明确表示了,这个方法来自父类,或者说,使用super调用一个方法,就是表示,告诉编译器,直接去父类中去查找这个方法,不要去子类中去查找了。
class Person{ // 定义父类
void print(){ // 默认的访问权限
System.out.println("Person --> void print()。") ;
}
};
class Student extends Person{ // 定义继承关系
public void print(){
super.print() ; // 访问父类中被子类覆写过的方法
System.out.println("Student --> void print()。") ;
}
};
public class OverrideDemo03{
public static void main(String args[]){
Student s = new Student() ;
s.print() ;
}
};
问题:有这样一个问题,继承自父类的内容,是需要考虑权限的,那么对于父类中的private权限的方法,子类中给扩大权限写一个同名方法,这算是覆写么?
答案是否定的,这根本不算覆写,
可以这么想,如果说,父类中明确说了这个东西要私有,私有什么意思,就是说,只能我自己知道,其他人不能知道,既然如此,就算子类继承了,也看不到(至少不能直接看到),的确是这个逻辑,如果,私有的东西都被继承过去,都被子类直接看到了,那父类根本没有隐私了,这不符合逻辑,也不符合代码设计。
代码1:
class Person{ // 定义父类
private void print(){ // 私有的访问权限
System.out.println("Person --> void print()。") ;
}
public void fun(){ // 定义一个fun方法
this.print() ; // 调用print()方法
}
};
class Student extends Person{ // 定义继承关系
void print(){ // 覆写父类中的方法
System.out.println("Student --> void print()。") ;
}
};
public class OverrideDemo04{
public static void main(String args[]){
Student s = new Student() ;
s.fun() ;
}
};
这里的fun方法中的this,可以理解为本类,就是Person类,这个类中的方法就是这个私有的print方法咯,所以是只是打印了这个私有方法中的输出语句。但是,实际上,这个this还是传入的是student这个对象,只是,父类中有这个private的print方法,他的优先级比子类中的优先级更高,所以被调用,打印出来了,而子类中的print方法没有被打印,
就是说,父类中private了,子类中虽然有同名方法,但是并不是被覆写,所以,没有去调用,没有打印出来
代码2
class Person{ // 定义父类
void print(){ // default的访问权限
System.out.println("Person --> void print()。") ;
}
public void fun(){ // 定义一个fun方法
this.print() ; // 调用print()方法
}
};
class Student extends Person{ // 定义继承关系
void print(){ // 覆写父类中的方法
super.print() ; // 访问父类中被子类覆写过的方法
System.out.println("Student --> void print()。") ;
}
};
public class OverrideDemo04{
public static void main(String args[]){
Student s = new Student() ;
s.fun() ;
}
};
这里的this是,当前调用这个fun方法的对象student对象。调用的是子类覆写过的方法。
4.2属性的覆盖:
方法的覆写要求较多,比如方法名,参数类型,返回值类型全部必须一致,还有权限的要求;但是属性的覆盖要求就很简单了,在子类中声明了与父类同名的属性就可以实现属性覆盖。
当然这个覆盖的,父类中的属性,也是可以访问到,通过super关键字就可以访问他。
5,开篇第五个问题:super关键字的作用。
super关键字表示从子类调用父类中的指定操作,就是说通过子类对象,访问父类中的属性,方法,构造方法。
this和super都要出现在首行,所以,肯定不能同时出现,构造也不能循环调用,
总结:
1,继承的主要目的:扩展类的功能。
2,Java中一个类只能继承一个父类。
3,Java不允许多重继承,但是允许多层继承。
4,方法覆写与重载的区别。
5,子类对象实例化过程:先调用父类构造方法,再调用子类构造。
6,super与this的区别。
继承的学习总结。