目录
前言
上篇文章讲了类和对象,本篇就来讲述Java中的继承和多态,这两个也是非常重要的内容。
1. 继承
1.1 为什么需要继承
下面请看两段代码:
public class Cat {
private int age;
private String name;
public Cat(String name) {
this.name = name;
}
public void eat() {
System.out.println("Cat eat");
}
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
public Cat() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Dog {
private int age;
private String name;
public Dog(String name) {
this.name = name;
}
public void eat() {
System.out.println("Dog eat");
}
public Dog(int age, String name) {
this.age = age;
this.name = name;
}
public Dog() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
可以看到,这两个类的重复内容非常的多,如果能够提取共性,就可以解决这种问题,这时候就需要继承了。
1.2 继承的概念
继承是面向对象编程中的重要概念,它允许一个类(子类)基于另一个类(父类)来构建。在继承中,子类会继承父类的属性和方法,同时可以添加新的属性和方法,或者重写父类的方法。比如,狗和猫的的共性都是动物。狗类和猫类都可以继承动物类。
1.3 继承语法
修饰符 class 子类 extends 父类{
//...
}
将上面的例子进行修改:
public class Animal {
private int age;
private String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name+"吃饭");
}
public void sleep() {
System.out.println(name+"睡觉");
}
public Animal(int age, String name) {
this.age = age;
this.name = name;
}
public Animal() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Cat extends Animal {
public void mew(){
System.out.println(getName()+"喵喵喵");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println(getName() + "汪汪汪");
}
}
public class Extend {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("旺财"); //子类可以直接使用父类的方法
dog.eat();
dog.sleep();
dog.bark();
Cat cat = new Cat();
cat.setName("加菲");
cat.eat();
cat.sleep();
cat.mew();
}
}
运行结果:
可以看到,代码量小了很多。
同时也可以看出来,子类可以访问父类的成员变量和成员方法。
1.4 super关键字
如果有子类的成员变量或者成员方法和父类的相同, 就需要super关键字。
1.4.1 super调用父类的构造方法
在子类的构造方法中使用 super() 来调用父类的构造方法。如果子类的构造方法没有显式调用父类的构造方法,Java会自动调用父类的无参构造方法。
class Animal {
Animal() {
System.out.println("父类构造器");
}
}
class Dog extends Animal {
Dog() {
super(); // 调用父类的构造方法
System.out.println("子类构造器");
}
}
1.4.2调用父类的方法
在子类中使用 super.methodName() 来调用父类的方法。
class Animal {
void eat() {
System.out.println("动物在吃饭");
}
}
class Dog extends Animal {
void eat() {
super.eat(); // 调用父类的eat方法
System.out.println("狗在吃饭");
}
}
1.4.3 访问父类的属性:
在子类中使用 super.variableName 来访问父类的属性。
class Animal {
String name = "Animal";
}
class Dog extends Animal {
String name = "Dog";
void displayName() {
System.out.println(super.name); // 访问父类的name属性
System.out.println(name); // 访问子类的name属性
}
}
1.5 final关键字
在Java中,final 是一个关键字,用于表示不可改变的。final 关键字可以用来修饰类、方法和变量。
注意:在方法中,final 关键字可以和 static 关键字一起使用,表示静态最终方法,不可被重写。
final 变量通常用大写字母命名,多个单词之间用下划线分隔,例如 MAX_VALUE
1.5.1 修饰类
当一个类被声明为 final 时,表示该类是最终类,不能被继承。
final class FinalClass {
// 类的内容
}
1.5.2 修饰方法
当一个方法被声明为 final 时,表示该方法是最终方法,子类不能重写(在多态这一节会讲到)该方法。
class ParentClass {
final void finalMethod() {
// 方法的内容
}
}
1.5.3 修饰变量
当一个变量被声明为 final 时,表示该变量是一个常量,只能被赋值一次。
final int constantValue = 10;
使用 final 关键字可以增加代码的安全性和可靠性,防止意外修改和继承。
2.多态
2.1 多态的概念
多态(Polymorphism)是面向对象编程中的重要概念,它允许不同类的对象对同一消息做出响应,即同一操作作用于不同的对象上会产生不同的行为
2.2 多态的条件
多态一般有如下条件:
继承:多态性基于类与子类之间的继承关系。子类继承父类的方法,可以重写(Override)父类的方法
重写(Override):子类重写父类的方法,方法名、参数列表和返回类型必须与父类中被重写的方法一致。重写的方法不能比父类方法的访问权限更严格。
父类引用指向子类对象:通过父类的引用来指向子类的对象,即向上转型。这样可以根据实际对象类型来调用方法。
运行时绑定:在运行时确定调用哪个方法,即动态绑定。当父类引用指向子类对象时,根据实际对象类型来调用方法。
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。
class Animal {
public void sound() {
System.out.println("动物的声音");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("狗汪汪汪");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("猫喵喵喵");
}
}
public class AnimalExample {
public static void main(String[] args) {
Animal animal1 = new Dog(); // 父类引用指向子类对象
Animal animal2 = new Cat(); // 另一个父类引用指向另一个子类对象
animal1.sound(); // 调用子类 Dog 的 sound() 方法
animal2.sound(); // 调用子类 Cat 的 sound() 方法
}
}
在这个例子中,我们创建了一个 Animal 类作为父类,以及两个子类 Dog 和 Cat。在 main 方法中,我们使用父类 Animal 的引用分别指向 Dog 和 Cat 的对象,然后调用它们的 sound() 方法。这展示了多态性的特性,同一方法调用根据对象的实陋类型而有不同的行为。
2.3 重写
重写(Override)是面向对象编程中的一个重要概念,它允许子类重新定义(覆盖)父类中的方法。当子类重写父类的方法时,子类中的方法会覆盖父类中同名的方法,从而实现多态性。
重写的规则如下:
方法名、参数列表和返回类型必须与父类中被重写的方法完全相同。
子类重写的方法不能比父类方法的访问权限更严格。例如,如果父类中的方法是 public,那么子类中重写的方法不能是 private。
子类方法不能比父类方法抛出更宽泛的异常。如果父类方法抛出异常,子类方法可以不抛出异常,但不能抛出更宽泛的异常。
重写的主要目的是为了在子类中提供特定于子类的实现,从而允许不同类型的子类对象以不同的方式响应相同的方法调用。这样可以实现多态性,使得程序更加灵活和可扩展。
2.4 向上转型和向下转型
2.4.1 向上转型
向上转型(Upcasting)是面向对象编程中的一个重要概念,指的是将子类的实例赋值给父类类型的引用变量。这种转型是安全的,因为子类对象可以视作父类对象,而且可以访问父类中定义的方法和属性。
特点:
子类对象赋值给父类引用:通过向上转型,可以将子类实例赋值给父类类型的引用变量,如下所示:
ParentClass obj = new ChildClass();
下面有个例子:
class Animal {
public void makeSound() {
System.out.println("发出声音");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
public void wagTail() {
System.out.println("摇尾巴");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
public void purr() {
System.out.println("咕噜咕噜");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.makeSound(); // 输出 "汪汪汪"
myCat.makeSound(); // 输出 "喵喵喵"
// 无法直接调用子类特有的方法,因为是用父类引用指向子类对象
// myDog.wagTail(); // 编译错误
// myCat.purr(); // 编译错误
}
}
在这个例子中,我们创建了 Animal 类作为父类,以及 Dog 和 Cat 作为 Animal 类的子类。在主程序中,我们使用 Animal 类型的引用变量分别引用了 Dog 和 Cat 类型的对象。通过向上转型,我们可以调用 Animal 类中定义的 makeSound 方法,实现了多态性的效果。
需要注意的是,尽管我们用 Animal 类型的引用变量引用了 Dog 和 Cat 类型的对象,但我们无法直接调用子类特有的方法(如 wagTail 和 purr),因为这些方法是子类特有的,而 Animal 类型的引用变量无法直接访问子类特有的方法。
2.4.2 向下转型
向下转型(Downcasting)是将父类类型的引用变量转换为子类类型的引用变量的过程。这种转型需要在编译时确定类型,并且需要确保实际对象的类型是转换后的类型,否则会导致 ClassCastException 异常。
class Animal {
public void makeSound() {
System.out.println("发出声音");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪");
}
public void wagTail() {
System.out.println("摇尾巴");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
// 向下转型并使用 instanceof 进行类型检查
if (myDog instanceof Dog) {
Dog myActualDog = (Dog) myDog;
myActualDog.wagTail(); // 可以调用子类特有的方法
} else {
System.out.println("无法转型");
}
}
}
这段Java代码定义了一个Animal类和一个Dog类,其中Dog类是Animal类的子类。在Main类的main方法中,创建了一个Animal对象myDog,并用Dog类实例化它。然后通过向下转型和使用instanceof运算符进行类型检查,将myDog转型为Dog类的实例myActualDog,并调用了Dog类特有的方法wagTail()。
这段代码展示了面向对象编程中的继承和多态的概念。继承允许子类继承父类的属性和方法,而多态性允许同一个方法在不同子类中表现出不同的行为。在这里,Dog类重写了Animal类的makeSound()方法,并添加了自己的方法wagTail(),实现了多态性。
总结
以上就是继承和多态的内容了,希望大家看完之后能够对他们有更深入的了解。