java基础之继承和多态

java基础之继承和多态
一、继承实现代码的复用1. 继承的本质与定义1.1 继承的意义1.1.1 实现代码的复用上回文章中说过Java中使用类和对象来进行对所有事务的描述类经过实例化之后形成一个个的对象但是事务存在共同特征时则可以使用继承来实现代码的复用例如当定义了一个动物类的时候动物们都会吃饭和睡觉你就可以定义吃饭和睡觉的方法在动物类中而当你想再定义一个猫的类和狗的类时你也需要定义吃饭和睡觉类这时候如果再次定义就会显得代码的利用率很低那么我们就可以使用继承因为猫和狗也都会睡觉和吃饭那么我们就可以把猫和狗类定义为动物类的子类此时就可以少写重复的代码下面代码就可以说明// 定义动物父类 class Animal { private String name; // 动物名称 private int age; // 动物年龄 // 构造方法 public Animal(String name, int age) { this.name name; this.age age; } // 吃饭方法所有动物都会吃饭 public void eat() { System.out.println(name 正在吃东西...); } // 睡觉方法所有动物都会睡觉 public void sleep() { System.out.println(name 正在睡觉...); } }// 定义猫类继承自动物类 class Cat extends Animal { // 构造方法 public Cat(String name, int age) { super(name, age); // 调用父类的构造方法 } // 猫类特有的方法 public void meow() { System.out.println(getName() 喵喵叫...); } }// 定义狗类继承自动物类 class Dog extends Animal { // 构造方法 public Dog(String name, int age) { super(name, age); // 调用父类的构造方法 } // 狗类特有的方法 public void bark() { System.out.println(getName() 汪汪叫...); } }首先定义了一个动物类动物类有一个吃饭方法和一个睡觉方法然后定义第二个类猫类此时可以对动物类进行继承此时猫类也有吃饭类和睡觉类了还可以在此基础上再定义猫特有的类猫叫为喵喵喵然后定义第三个类狗类此时可以对动物类进行继承此时狗类也有吃饭类和睡觉类了还可以在此基础上再定义狗特有的类狗叫为汪汪汪那么上述就实现了代码的复用1.1.2 比较符合现实逻辑还是上述的例子动物类作为父类而猫和狗作为子类本来就比较符合is - a 的关系动物作为父类而猫类作为子类子类本身就继承了父类所有的财产属性和方法1.1.3 改代码方便新增功能简单在修改父类时只需要修改父类所有的子类就会跟着变化比如在动物类这个代码中只需要新增加会移动这个功能那么猫和狗两个类就都会跟着进行修改也会有这两个方法而不需要手动进行添加了子类继承很轻松当需要新增子类鸟时那么只需要在子类中新增独特的方法会飞即可不需要再从头写吃饭睡觉会移动这些方法了1.2 继承的语法和定义在java中表示继承时需要使用entends关键字来实现父类中只需要进行定义子类中所共有的方法与属性public class Animal { // 成员变量 protected String name; protected int age; // 构造方法 public Animal(String name, int age) { this.name name; this.age age; } // 方法 public void eat() { System.out.println(name 正在吃东西...); } public void sleep() { System.out.println(name 正在睡觉...); } }在定义子类时需要使用extends关键字在子类类名后面加上extends关键字 父类名字即可然后在子类中加入子类特有的属性和方法即可子类也可以叫做派生类其他内容后面会进行介绍public class Cat extends Animal { // 子类特有的属性 private String furColor; // 子类构造方法 public Cat(String name, int age, String furColor) { super(name, age); // 调用父类的构造方法 this.furColor furColor; } // 子类特有的方法 public void meow() { System.out.println(name 喵喵叫...); } }1.2.1注意事项子类继承父类之后必须要添加自己特有的成员变量或方法体现出与父类的不同2.继承机制核心特性2.1单继承原则Java中支支持单继承即一个子类只能有一个父类而不能有多个父类而一个父类可以有多个子类单继承可以避免子类从多个父类继承相同方法引发歧义2.2成员继承规则2.2.1 子类中访问父类的成员变量子类和父类不存在同名成员变量此时可以正常进行访问class Base { int a; int b; } class Derived extends Base { int c; public void method(){ a 10;//访问父类继承下来的a b 20;//访问父类继承下来的b c 30;//访问自己的c } }子类和父类存在同名变量时那么此时会优先访问子类中的变量class Base { int a; int b; int c; } class Derived extends Base { int a; int b; public void method(){ a 100;//访问父类继承下来的a b 101;//访问父类继承下来的b c 102;//访问自己的c } }说明子类方法或者通过子类对象访问成员时如果访问的变量子类中有则优先访问子类中的如果没有则访问继承下来的如果父类也没有那么就会编译报错如果时同名那么优先访问子类中的2.2.2子类中访问父类的成员方法成员方法名不同方法没有同名时在子类方法中或通过子类对象访问时则优先访问自己的自己的找不到再去父类中去找方法名字相同时方法名字相同时在子类方法中或者通过子类对象访问时则会访问自己的说明通过子类对象访问父类与子类中的不同名方法时优先在子类中找找到就访问找不到就到父类中找通过子类对象访问父类和子类的同名方法时如果父类和子类的同名方法的参数列表不同那么可以根据不同的参数选择合适的进行访问2.3 访问修饰符在父类和子类中public子类完全继承可直接访问​protected子类在同包或子类范围内可访问​default包访问同包子类可访问不同包子类不可访问​private子类无法直接继承可通过父类 public 方法间接访问3.super关键字3.1 super关键字的作用主要是用于当父类和子类中存在相同名称的成员时以前说过当在子类方法中访问父类的同名成员时由于会优先访问子类的成员所以想要解决这个问题就需要super关键字来解决super关键字的作用就是在子类方法中访问父类的成员class Base{ int a; int b; public void methodA() { System.out.println(Base中的方法A被调用); } public void methodB() { System.out.println(Base中的方法B被调用); } } class Derived extends Base { //与父类中的变量同名且同类型 int a; int b; public void methodA() { System.out.println(Derived中的方法A被调用); } public void methodB() { System.out.println(Derived中的方法B被调用); } public int getSuperA() { return super.a; } public int getSuperB() { return super.b; } public void methodC() { a 100; // 子类的 a b 101; // 子类的 b super.a 200; // 父类的 a super.b 201; // 父类的 b } } public class Test { public static void main(String[] args) { Derived derived new Derived(); Base base new Base(); derived.methodC(); int a derived.a; int b derived.b; int c derived.getSuperA(); int d derived.getSuperB(); System.out.println(a b c d); } }这段代码就能够说明super关键字的作用当进行输出后就能发现super关键字可以在子类方法中访问父类的同名成员3.2 注意事项super关键字只能在非静态方法中使用super关键字位于普通方法中只有确定了对象之后才知道要访问哪个父类对象的成员通过super(参数) 的形式就可以调用父类指定构造方法super() 的形式只能出现在第一行super()只能在子类构造方法中出现一次并且不能和this同时出现在多层继承中super始终直接指向直接父类而不是“ 爷爷 ” 类super关键字不能用于直接访问父类的私有成员只能访问public和protected若子类实现了多个接口且接口有同名默认方法需显式指定调用哪个接口的方法。3.3.父子类构造方法在子类对象构造前需要先调用父类的构造方法对父类初始化然后才会执行子类构造方法这是由于子类中包含所有的父类的非私有成员和子类自身的成员所以如果直接初始化子类对象可能导致仍然有父类中的成员处于未初始化状态但还分为以下两种情况3.3.1当父类构造方法没有形参时这是第一中情况当父类构造方法中没有参数时此时系统会自动在子类构造方法中隐式调用super()来自动对父类进行初始化class Base { public Base() { System.out.println(Base()); } } class Derived extends Base { public Derived() { //此时系统会默认调用父类中的构造方法 super() System.out.println( Derived()); } } public class Test { public static void main(String[] args) { Derived d new Derived(); } }3.3.2当父类构造方法无形参时如果父类中有参数那么此时就无法自动调用此时就需要手动写出来class Base { public Base(int a) { System.out.println(Base()); } } class Derived extends Base { public Derived() { super(10); System.out.println( Derived()); } } public class Test { public static void main(String[] args) { Derived d new Derived(); } }3.4 this关键字和super关键字的区别相同点只能在非静态成员方法中使用用来访问非静态成员在构造方法调用时必须是构造方法中的第一条语句并且不能同时存在不同this是当前对象的引用指向当前对象包括从父类继承下来的而super相当于是子类对象中从父类中继承下来的部分的引用final关键字修饰类表示不能被继承二.多态1. 什么是多态多态是java的特性之一简单的来说同一件事情发生在不同对象身上时就会有不同的结果拿现实一个例子来说明当我们出行时根据不同的环境需要使用不同的交通工具比如可以选择坐轮船出门也可以选择坐飞机出门1.1多态实现的条件必须要在继承体系下子类必须要对父类中的方法进行重写通过父类的引用调用重写的方法class Animal { String name; int age; public Animal(String name, int age) { this.name name; this.age age; } public void eat() { System.out.println(name 吃饭); } } class cat extends Animal { public cat(String name, int age) { super(name, age); } Override public void eat() { System.out.println(name 吃鱼); } } class dog extends Animal { public dog(String name, int age) { super(name, age); } Override public void eat() { System.out.println(name 吃骨头); } }上面就是一个例子可以体现多态一个吃的行为可以在不同对象中发挥不同的作用当对象为猫时就是吃鱼当对象为狗时就是吃骨头2.重写2.1 什么是方法的重写方法的重写发生在继承下父类中有一个方法子类通过相同的签名方法名、参数列表、返回类型重新实现父类的方法以改变其行为典型的场景就是父类不满足子类的要求比如上述例子中当我们在定义动物类时还无法知道动物的具体行为比如我们只能知道动物可以叫而却不知道动物具体的叫声那么当我们在定义猫子类时就可以对动物叫声这个类进行重写猫可以改为喵喵2.2 方法重写的规则2.2.1方法签名必须一致方法名相同子类重写方法的方法名必须和父类中被重写的方法完全一样参数列表相同参数的个数类型和顺序必须完全一致2.2.2返回类型要兼容可以类型不同但必须是有父子关系的2.2.3 访问修饰符限制访问修饰符不能更严格访问权限不能⽐⽗类中被重写的⽅法的访问权限更低。例如如果⽗类⽅法被public修饰则⼦类 中重写该⽅法就不能声明为 protected父类被staticprivate修饰的方法构造方法都不能重写2.3 重写和重载的区别特性方法重写Override方法重载Overload定义子类重新实现父类的方法同一个类中定义多个同名但参数不同的方法发生范围必须存在继承关系或实现接口同一个类内部也可发生在父子类中但本质仍为同一个类的多个版本方法签名方法名、参数列表、返回类型必须完全相同Java 5 允许协变返回方法名相同但参数列表类型、顺序、数量必须不同返回类型必须相同或为子类类型协变返回可不同访问权限不能比父类更严格如父类是protected子类需为protected或public可不同静态方法不能重写静态方法静态方法属于类子类若定义同名静态方法属于隐藏父类方法可重载静态方法Override 注解推荐使用强制编译器检查重写规则避免拼写错误可选用于明确标识重载方法核心目的实现多态让子类改变或扩展父类的方法行为提供多个同名但参数不同的方法增强方法的灵活性2.4 动态绑定和静态绑定静态绑定也称为前期绑定(早绑定)即在编译时根据⽤⼾所传递实参类型就确定了具体调⽤那个⽅ 法。典型代表函数重载。动态绑定也称为后期绑定(晚绑定)即在编译时不能确定⽅法的⾏为需要等到程序运⾏时才能 够确定具体调⽤那个类的⽅法。2.5 向上转型和向下转型2.5.1 向上转型将子类对象隐式转换为父类类型语法格式父类类型 对象名 new 子类类型()class Animal { public void sound() { System.out.println(动物叫); } } class Dog extends Animal { Override public void sound() { System.out.println(汪汪); } public void bark() { System.out.println(犬吠); } } public class Test { public static void main(String[] args) { // 向上转型 Animal animal new Dog(); // 父类引用指向子类对象 animal.sound(); // 输出汪汪动态绑定到子类方法 // animal.bark(); // 编译错误父类引用无法访问子类特有的方法 } }向上转型之后只能够调用父类中的方法但是方法的内容是子类的方法而且不能调用子类特有的方法2.5.2向下转型将父类引用强制转换为子类类型需显式使用强制类型转换语法。子类类型 引用变量 (子类类型) 父类引用;主要作用 需要使用子类特有的方法时

最新新闻

日新闻

周新闻

月新闻