继承
举个简单的例子《西虹市首富》中的王多鱼从他的二爷那里继承的财产这就叫继承而在Java中的继承又是怎样的呢?
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了 由简单到复杂的认知过程。
继承主要解决的问题是:共性的抽取,实现代码复用
继承的语法
在Java中如果要表示类之间的继承关系,需要借助extends关键字
class 父类{
... //成员变量、成员方法
}
class 子类 extends 父类{
... //类体
}
public class Father {
public String name;
public int age;
public String gender;
public void show(){
System.out.println("姓名:"+name);
System.out.println("年龄:"+age);
System.out.println("性别:"+gender);
}
}
class Son extends Father{
}
class Family{
public static void main(String[] args) {
Son son=new Son();
son.name="张三";
son.age=11;
son.gender="男";
son.show();
}
}
此时我们并没有在Son类中给任何成员变量和方法,却可以通过实例化对象Son来访问Father类中的成员变量和方法,这里Son就是继承了Father中的成员变量和方法
父类成员的访问
当成员变量和成员方法不同名的时候
public class Father {
public String name="杰瑞";
public int age=41;
public String gender="男";
public void sayhello(){
System.out.println("大家好!我是父亲杰瑞");
}
}
class Son extends Father{
public void saybye(){
System.out.println("再见!");
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
son.sayhello();
son.saybye();
System.out.println("姓名:"+son.name+" 年龄:"+son.age+" 性别:"+son.gender);
}
}
成员方法和变量没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时 再到父类中找,如果父类中也没有则报错
当成员变量和成员方法同名的时候
public class Father {
public String name="杰瑞";
public int age=41;
public String gender="男";
public void sayhello(){
System.out.println("大家好!我是父亲杰瑞");
}
public void saybye(){
System.out.println("再见!");
}
}
class Son extends Father{
public String name="莫迪";
public int age=12;
public void sayhello(){
System.out.println("大家好!我是儿子莫迪");
}
public void show(){
System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender);
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
son.sayhello();
son.saybye();
son.show();
}
}
在子类方法中 或者 通过子类对象访问成员时: 如果访问的成员变量子类中有,优先访问自己的成员变量。
如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
如果访问的成员变量与父类中成员变量同名,则优先访问自己的
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找
super关键字和函数的覆盖
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,在Java中专门提供了一个super关键字用于访问父类的成员
public class Father {
public String name="杰瑞";
public int age=41;
public String gender="男";
public void sayhello(){
System.out.println("大家好!我是父亲杰瑞");
}
public void saybye(){
System.out.println("再见!");
}
}
class Son extends Father{
public String name="莫迪";
public int age=12;
public void sayhello(){
System.out.println("大家好!我是儿子莫迪");
}
public void show(){
super.sayhello();
System.out.println("姓名:"+super.name+" 年龄:"+super.age+" 性别:"+gender);
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
son.sayhello();
son.saybye();
son.show();
}
}
此时成员方法同名的时候我们通过super关键字就可以访问到父类成员的方法和变量了
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容,这就是覆盖
public class Father {
public String name="杰瑞";
public int age=41;
public String gender="男";
public void sayhello(){
System.out.println("大家好!我是父亲杰瑞");
}
public void saybye(){
System.out.println("再见!");
}
}
class Son extends Father{
public String name="莫迪";
public int age=12;
public void sayhello(){
System.out.println("大家好!我是儿子莫迪");
}
public void show(){
System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender);
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
son.sayhello();
son.show();
}
}
这里就重写了name,age,sayhello成员变量和方法同时沿用了父类gender的属性
子类构造方法
public class Father {
public Father(){
System.out.println("大家好!我是父亲杰瑞");
}
}
class Son extends Father{
public Son (){
System.out.println("大家好!我是儿子莫迪");
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
}
}
在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法,因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整
注意:
- 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
- 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
- 在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
- super(…)只能在子类构造方法中出现一次,并且不能和this同时出现
super和this
super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那他们之间有什么区别呢?
相同点
- 都是Java中的关键字
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
不同点
- this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
- 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现
- 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有
final关键字
final关键字可用于修饰类、变量和方法,它有“无法改变”或者“最终”的含义,因此被final修饰的类、变量和方法将具有以下特性:
final可以修饰类,方法,变量 final修饰的类不可以被继承 final修饰的方法不可以被覆盖
final修饰的变量是一个常量,只能被赋值一次
为什么要用final修饰变量,其实,在程序中如果一个数据是固定的。那么直接使用这个数据就可以了,但是这种阅读性差,所以应该给数据起个名称。而且这个变量名称的值不能变化,所以加上final固定
public final class Father {
public Father(){
System.out.println("大家好!我是父亲杰瑞");
}
}
class Son extends Father{
public Son (){
System.out.println("大家好!我是儿子莫迪");
}
}
class Family{
public static void main(String[] args) {
Son son=new Son();
}
}
此时被final关键字修饰的类是无法被继承的
public class Number {
public static void main(String[] args) {
final int a = 10;
a=20;
System.out.println(a);
}
}
被final修饰的常量是无法修改的
继承的优点
继承过来的字段和方法,可以像任何其他字段和方法一样被直接使用;
在子类中可以声明一个与父类中同名的新字段或静态方法,从而“隐藏”父类中的字段或方法; 可以在子类中声明一个在父类中没有的新字段和方法;
可以在子类中编写一个父类当中具有相同名的新实例方法,这称为“方法重写”或“方法覆盖”;
可以在子类中编写一个调用父类构造方法的子类构造方法,既可以隐式地实现,也可以通过使用关键字super来实现
代码执行顺序
父类静态代码块 > 子类静态代码块 > main()方法 > 父类代码块 > 父类构造方法 > 子类代码块 > 子类构造方法