一、类的继承
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或基类,子类会自动拥有父类所有可继承的属性和方法。
基本概念和语法
在 Java 中,继承通过 extends
关键字实现。子类可以继承父类的字段和方法,同时可以添加新的字段和方法,或者重写父类的方法。
// 父类(基类)
class Animal {
String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 方法
public void eat() {
System.out.println(name + " is eating.");
}
}
// 子类(派生类)
class Dog extends Animal {
// 子类可以定义自己的字段
private String breed;
// 子类必须调用父类的构造方法
public Dog(String name, String breed) {
super(name); // 调用父类的构造方法
this.breed = breed;
}
// 子类可以重写父类的方法
@Override
public void eat() {
System.out.println(name + " the " + breed + " is eating.");
}
// 子类可以定义自己的方法
public void bark() {
System.out.println(name + " is barking.");
}
}
继承的关键点:
1. 父类与子类
- 父类(基类)是被继承的类,它定义了通用的特征和行为。
- 子类(派生类)通过
extends
关键字扩展父类,可以继承父类的属性和方法,并可以添加自己的属性和方法。
2. 构造方法
子类的构造方法可以调用父类的构造方法,使用 super()
关键字调用父类的构造方法。如果没有显式调用,Java 编译器会默认调用父类的无参构造方法(如果存在)。
3. 方法重写
子类可以重写(Override)父类的方法,以提供特定于子类的实现。使用 @Override
注解可以帮助编译器检查是否正确覆盖了父类的方法。
4. 访问控制
子类可以访问父类的非私有字段和方法,而私有字段和方法对子类不可见。
5. 单继承
Java 不支持多重继承,即一个类只能直接继承自一个类。但是可以通过接口实现多重继承的效果。
继承的优势和用途:
- 代码复用:可以通过继承来避免代码重复,提高代码的复用性和可维护性。
- 多态性:通过方法重写和动态绑定,实现多态,提高了代码的灵活性和扩展性。
- 层次结构:可以使用继承建立类之间的层次关系,使得代码结构更加清晰和组织有序。
注意:在Java中提供了一个Object类,它是所有类的父类,也是唯一一个没有父类的类,每个类都直接或间接继承自该类。
二、final关键字
final关键字可用于修饰类、变量和方法,它有“不可更改”或者“最终”的含义。因此被final修饰的类、变量和方法将具有以下特性:
1. final修饰的类不能被继承
2. final修饰的方法不能被子类重写
3. final修饰的变量(成员变量和局部变量)是常量,只能赋值一次
三、抽象类和接口
抽象类
抽象类(Abstract Class)是用来定义具有某些抽象方法的类,这些方法由其子类来实现。
1. 抽象类的定义
在Java中,可以使用 abstract
关键字来声明抽象类。抽象类不能被实例化,即不能直接创建抽象类的对象。其目的是为了被继承,子类需要实现抽象类中的抽象方法。
// 抽象类
abstract class Shape {
// 抽象方法(没有方法体)
public abstract void draw();
// 普通方法(可以有方法体)
public void display() {
System.out.println("Displaying shape.");
}
}
// 继承抽象类的具体子类
class Circle extends Shape {
// 实现抽象方法
@Override
public void draw() {
System.out.println("Drawing circle.");
}
}
class Rectangle extends Shape {
// 实现抽象方法
@Override
public void draw() {
System.out.println("Drawing rectangle.");
}
}
2. 抽象方法
抽象方法是没有具体实现的方法,只有方法签名(包括方法名、参数列表和返回类型)。抽象方法用 abstract
关键字声明,且不能包含方法体。
3. 抽象类的特性
- 抽象类可以包含普通的具体方法(有方法体),这些方法可以被子类直接继承或重写。
- 抽象类本身不能被实例化,即不能使用
new
关键字创建抽象类的对象。
4. 子类实现抽象方法
任何继承自抽象类的子类,都必须实现(Override)父类中的所有抽象方法,除非子类也声明为抽象类。
5. 抽象类的作用
- 提供了一种模板或者规范,帮助组织和管理代码结构。
- 强制性地要求子类实现特定的方法,以确保继承关系中的一致性和约束性。
6. 使用抽象类的场景:
- 模板设计模式:抽象类可以定义一组方法的骨架,具体的实现延迟到子类中。
- 多态性:通过抽象类和方法的多态特性,实现对不同子类对象的统一调用。
- 约束和约定:强制子类实现特定方法,确保子类具备某些通用功能或行为。
注意:包含抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法。
接口
接口的特点:
1. 接口中的变量都是常量,在声明时需要提供初始值(接口是常量存放最佳地点)。
2. 接口中的方法默认都是公有抽象方法。
3. jdk1.8以后接口中可以包含默认方法和静态方法。default和static修饰的方法。
4. 接口没有构造方法,不能直接创建对象,需要通过实现类进行构建。
接口的定义:
public interface 接口名称{
}
接口可以继承接口 :
public interface A{
}
public interface B{
}
public interface C extends A,B{
}
//java类实现接口后,要实现接口中的所有抽象方法
//否则该类要修改为抽象类
public class Demo implements A,B{
}
接口的分类 :
1. 单功能接口:接口中的方法功能单一,只包含一类功能;单一职责。
2. 多功能接口:接口中的功能比较多。
3. 标识接口:空接口,只作为标记使用java.io.Serializable,就是一个开关。
4. 常量接口:只包含一组常量。
四、多态
多态(Polymorphism)是面向对象编程中的一个重要概念,指的是同一个方法调用在不同的对象上可以有不同的行为表现。这是通过方法重写(Override)和动态绑定(Dynamic Binding)实现的。
多态的基本概念
在Java中,多态性主要通过以下两种形式实现:
1. 编译时多态(静态多态)
也就是方法重载(Overloading)。它是编译时多态的一种表现,指的是在同一个类中,方法名相同但参数列表不同的多个方法。编译器根据方法调用时传递的参数类型和数量来决定调用哪个方法。
class Calculation {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
在上述例子中,根据参数的类型(int
或 double
),编译器会决定调用适合的方法。
2.运行时多态(动态多态)
也就是方法重写(Override)。它和对象的继承结构是运行时多态的基础,指的是同一个方法调用可以在不同的子类对象上表现出不同的行为。Java中实现运行时多态性的关键是方法重写和动态绑定。
// 父类
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
// 子类
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("Cat meows");
}
}
在上述例子中,Animal
类有一个 sound()
方法,Dog
和 Cat
类分别重写了这个方法以定义自己的声音行为。当你调用 sound()
方法时,具体调用哪个子类的方法取决于对象的实际类型。
实现多态的条件
- 继承:必须有继承关系,子类继承父类。
- 方法重写:子类必须重写父类中的方法,实现自己特定的行为。
- 父类引用指向子类对象:通过父类类型的引用指向子类对象,可以实现方法的动态绑定。
多态的优势和用途
- 简化代码:通过多态,可以减少重复的代码,提高代码的可维护性和灵活性。
- 扩展性:易于扩展和修改,通过添加新的子类实现新的行为。
- 接口和抽象类的应用:接口和抽象类与多态结合,能够定义更高层次的抽象和规范。