Java的继承与多态

1.Java类的继承

类继承的实现

Java语言中实现类的继承用到extends关键字
格式:[public] class SubClass extends SuperClass //类体定义

类继承的几点说明:

  • 子类继承父类中的非private的成员变量与方法
  • 定义类时不加extends关键字,则默认为Object类的直接子类
  • Java仅支持单重继承

方法覆盖(重写)

子类中可以定义与父类中名字、参数列表、返回值类型都相同的方法,这时子类方法称为覆盖或重写了父类的方法

为防止覆盖方法时写错方法头,可在方法前加==@Override==注解,表示其后方法必须覆盖父类的一个方法,如果注解后方法没有覆盖父类的方法,编译器将给出错误。

关于方法覆盖的注意事项:

  • 父类的private方法不能覆盖,如果子类定义了一个方法在父类中是private的,则这是两个不相关的方法。
  • 父类中的static方法可以被继承,但不可以覆盖,如果子类定义了一个相同的方法,则父类中的方法被隐藏,但仍可以通过类名.方法名()调用
public class class1 {
   public static void method1(){
       System.out.println(666);
   }
}
public class class2 extends class1{
   
}
public class class3 {
   public static void main(String[] args) {
      class2.method1(); // 输出666
   }
}

super关键字

子类中可以使用super关键字来引用当前对象的父类对象,应用场景可能为如下3种情况

  1. 在子类中调用父类被覆盖的方法,格式:super.methodName([paramlist])
  2. 子类调用父类构造方法 super([paramlist])
  3. 在子类中调用父类被隐藏的成员变量 super.variableName

调用父类构造方法

子类构造方法

子类不能继承父类的构造方法,java语言规定,在创建子类对象时,必须先创建该类的所有父类,因此,在编写子类的构造方法时,必须保证他能调用父类的构造方法,
调用父类的构造方法有两种方式

  1. 使用super关键字
    super指直接父类的构造方法,不能通过super调用间接父类的构造方法,如super.super()是不合法的
  2. 调用父类默认构造方法
    子类构造方法若没有使用super调用父类构造方法,则编译器会自动在子类的构造方法第一句加上super(),即调用父类无参构造,若父类中没有无参构造,则编译器会报错.
public class class1 {
   public class1(int a){
       
   }
}
public class class2 extends class1{
   public class2(){ //此处产生编译错误,默认super()时找不到父类的空参构造。

   }
}

构造方法的调用过程

任何情况下,创建一个类的实例,将会沿着继承链调用所有父类的构造方法,叫做构造方法链,创建子类对象时,系统首先调用所有父类的构造方法,包括根类Object类的构造方法.

2.封装性 访问修饰符

类访问权限

  1. public修饰,可被任何其他类使用
  2. 缺省修饰仅能被同一包中的类使用

类成员访问权限

  1. private修饰:私有成员只能被这个类本身访问,外界不能访问(最体现对象的封装性)。
  2. 缺省:一般称为包可访问,成员可被类本身和同包中类访问。
  3. protected修饰:成员可被类本身、同包类。以及子类(包括同包与不同包)访问。
  4. public修饰:可被任何其他类访问,前提是该类是可访问的。

3.防止类扩展和方法覆盖

  1. final修饰类
    一个类使用final修饰,该类成为最终类,最终类不能被继承,尝试继承最终类会发生编译错误,例如
   final class A{
    
}
   class B extends A{   //这里发生错误
    
   }

定义final类隐含定义了其中的所有方法都是final都,因此类不能被继承,也不能覆盖其中的方法。
2. final修饰方法
如果一个方法被final修饰,则该方法不能被子类覆盖,否则发生编译错误,例如

class A{
    public final void method(){}
}   
class B extends A{
    public void method(){}  //此处发生编译错误
}
  1. final修饰变量
    变量被final修饰,则为常值变量,一旦赋值变不能改变
    编译时常量:使用static final组合定义类常量,编译器可以将该变量带入任何用到他的表达式中,减轻运行时负担。
    尝试改变final变量会产生编译错误,例如
class Test{
    public static final int size = 50;
    public void methodA(final int i){
        i = i + 1; // 该语句产生编译错误,不能改变final变量值
    }
}

注意:如果final修饰一个引用变量,表示该变量的引用(地址)不能改变,一旦引用被初始化指向一个对象,就无法使他指向另一个对象,但对象本身是可以改变的,java没有提供任何机制使对象本身保持不。

4.抽象类

抽象类是包含抽象方法的类,类前用abstract修饰
定义抽象方法需要在方法前加上abstract修饰符,抽象方法只有方法的声明,没有实现,包含抽象方法的类必须定义为抽象类。
抽象方法的声明后用分号结束,而不需要大括号。

public abstract class Shape(){
    String name;
    public Shape(){}
    public Shape(String name){
        this.name = name;
    }
    public abstract double getArea();
    public abstract double getPerimeter();
}

抽象类中可以定义非抽象方法,可以创建抽象类的子类,子类还可以是抽象类,只有非抽象的子类才能使用new创建该类的对象,抽象类中可以没有抽象方法,但仍需要被子类继承才能实例化。
注意:因abstract类必须被继承而final类不能被继承,所以两个修饰符不能在定义类时同时使用。

5.对象转换与多态(重点)

对象转换

子类是父类的特殊化,每个子类的实例都是父类的实例,但反过来不成立,子类和父类对象在一定条件下可以相互转换,成为对象转换或造型,有自动转换和强制转换之分。

  • 向上转换(自动):子类(类或接口对象) -> 父类(直接或间接)
    可以将任何对象转换为继承链中任何一个父类对象,包括Object
  • 向下转换(强制): 转换运算符"()"
public class CastDemo{
   public static void main(String[] args) {
      Employee emp = new Employee();
      Person p = emp;   //自动类型转换
      emp = (Employee) p;   //强制类型转换
   }
}

注意:不是任何情况下都可以进行强转,例如

public class Example{
   public static void main(String[] args) {
      Person p = new Person();
      Employee employee = (Employee) p; //不能把父类对象强制转换为子类对象 
   }
}

提醒:

  • 上述代码要将父类转换为子类对象,代码编译时没有错误,但运行时会抛出ClassCastException异常
  • 将父类对象转换为子类,必须要求父类对象是由子类构造方法生成的(包括子类型向上转型为父类型).
  • 当将一个子类对象转换为父类对象时,该引用可以调用重写父类的或从父类继承的方法,这些方法都不是父类的方法,但它不再能看到子类中的特有的方法。

instanceof运算符

用于测试一个实例是否是某种类型或其父类的实例 格式:variable instanceof TypeName。 该表达式返回逻辑值

public class E{
   public static void main(String[] args) {
      Fruit fruit = new Apple();
      Orange orange = new Orange();
      fruit instanceof Fruit;   //true
      fruit instanceof Orange;  //false
      orange instanceof Fruit;  //true
      orange instanceof Orange; //true
   }
}

多态与动态绑定

java语言支持两种类型的多态:

  1. 静态多态:也称编译时多态,通过方法重载实现。
  2. 动态多态:也称运行时多态,通过方法覆盖(重写)实现。

将方法调用与方法体关联起来称方法绑定。
程序执行前绑定叫前期绑定,如C语言的函数调用
程序运行时根据对象类型进行绑定,称后期绑定动态绑定。Java除static和final方法都是动态绑定。

对重载的方法,Java运行时系统根据传递给方法的参数个数与类型确定调用哪个方法,
对覆盖的方法,运行时系统根据对象类型决定调用哪个方法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值