抽象类

抽象类

abstract 修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。

  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类

  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的通过多态来实例对象

  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的,

  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

在面向对象编程中,抽象类是一个不能直接实例化的类,它通常作为其他类的基类,提供通用的接口和部分实现。抽象类的主要目的是为继承它的子类提供一个模板,确保所有子类都实现特定的功能。

主要特点:

  1. 不能实例化:抽象类不能被直接实例化。你不能创建抽象类的对象,必须通过继承它的子类来实例化。
  2. 可以包含抽象方法:抽象类可以包含抽象方法(方法声明没有实现),这些方法需要在子类中实现。抽象方法在抽象类中只定义方法签名(包括方法名、参数列表和返回类型),而没有方法体。
  3. 可以有已实现的方法:除了抽象方法,抽象类还可以包含已实现的方法,这些方法可以被子类继承和重用,或者被子类覆盖(重写)。
  4. 可以有成员变量:抽象类可以包含成员变量,允许它在多个子类中共享一些数据。
  5. 可以继承其他类:抽象类可以继承其他类,并且可以实现接口。

抽象类的定义与使用

假设我们有一个动物类 Animal,我们希望定义一个通用的行为,但不希望直接实例化 Animal 类,而是让它的子类具体实现某些特性。

package com.oop.demo09;

public class Test {
    public static void main(String[] args) {
        //new Animal(); //抽象类的实例不是直接new 而是通过多态 父类(抽象类)的引用指向子类的实例
        Animal d1 = new Dog();//通过子类将父类(抽象类中的抽象方法)实现且必须全部实现 否则就将子类也声明成抽象类
        System.out.println(d1.num);
        System.out.println(d1.num_float);
        d1.breath();//父类的引用 直接调用自己的方法(子类没有重写)
        d1.sound();//子类实例 用重写过的抽象类中抽象方法
        Animal c1 = new Cat();
        System.out.println(c1.num);
        System.out.println(c1.num_float);
        c1.breath();//父类的引用 直接调用自己的方法(子类没有重写)
        c1.sound();//子类实例 用重写过的抽象类中抽象方法
    }
}

abstract class Animal {
    public static int num = 123;
    public float num_float=123.456f;
    //抽象类中可以定义属性
    public void breath(){   //抽象类可以定义普通方法
        System.out.println("他在呼吸!");
    }
    public abstract void sound(); //只有方法的声明,没有方法体

    //new Animal();//抽象类不能直接实例化,得借助子类进行实例化(多态)
    //new Dog();//也不能在抽象类里面实例对象

}
class Dog extends Animal{
    public void sound(){
        System.out.println("Bark!");//在子类中将抽象方法具体实现
    }
}
class Cat extends Animal{
    public void sound(){
        System.out.println("Miao Miao!");
    }
}

抽象类中可以有:

1. 定义属性

抽象类可以定义属性(成员变量),这些属性可以是静态的(static)或实例的。它们可以被继承到子类中。

public static int num = 123;  // 静态属性
public float num_float = 123.456f;  // 实例属性
  • num 是一个静态属性,可以直接通过 Animal 类名访问,并且是所有 Animal 类型(包括继承类)共享的。
  • num_float 是一个实例属性,每个 Animal 的实例都有自己的副本,子类实例也可以访问该属性。

2. 定义普通方法

抽象类可以定义普通(已实现)的方法,子类可以继承并直接使用这些方法,也可以选择覆盖(重写)。

public void breath() {  
    System.out.println("他在呼吸!");
}
  • breath 是一个普通方法,定义在抽象类 Animal 中。它不需要在子类中重写,子类可以直接继承并调用它。

3. 定义抽象方法

抽象类中可以定义抽象方法,这些方法没有方法体,必须由子类实现。

public abstract void sound(); // 抽象方法,要求子类必须实现
  • sound 是一个抽象方法,在 Animal 类中没有实现,子类 DogCat 必须实现这个方法。

4. 构造方法

抽象类可以有构造方法,但它不能直接实例化。在构造方法中,你可以初始化一些共享的成员或执行其他必要的初始化操作。

abstract class Animal {
    public Animal() {
        System.out.println("动物类构造方法");
    }
    // 其他代码
}
  • Animal 类可以包含构造方法,尽管我们不能直接实例化抽象类,但可以在子类实例化时调用父类的构造方法。

5. 静态方法

抽象类也可以有静态方法(static),这些方法只能通过类名访问,而不依赖于实例。

abstract class Animal {
    public static void staticMethod() {
        System.out.println("这是抽象类的静态方法");
    }
}
  • 你可以通过 Animal.staticMethod() 来调用静态方法,而不需要创建实例。

6. 接口实现

抽象类可以实现接口。这样,抽象类就可以强制要求所有子类实现接口中的方法,同时又可以提供一些默认的实现。

java复制代码interface Eater {
    void eat();
}

abstract class Animal implements Eater {
    // 可以不实现接口方法,留给子类去实现
    public abstract void sound();
}

总结:在您的代码中,抽象类的以下特性已经体现出来:

  • 可以定义成员变量(静态和实例变量)。
  • 可以定义普通方法(有方法体的方法)静态方法和非静态方法。
  • 可以定义抽象方法(没有方法体的方法,要求子类实现)。
  • 可以包含构造方法
  • 子类必须实现抽象类中的所有抽象方法,除非子类本身也是抽象类。

但是,抽象类可以有更多的功能,如:

  • 静态方法。
  • 可以实现接口。
  • 可以包含常量(public static final)等。

抽象类中的属性只能是常量吗?

不,抽象类中的属性不仅仅可以是常量,它也可以是普通的实例变量(非常量)。抽象类中的属性可以是:

  1. 实例变量(非常量)
  2. 静态变量(常量或非常量)
  3. 常量public static final

1. 实例变量(非常量)

抽象类可以定义实例变量(成员变量),这些变量属于类的实例。每个继承该抽象类的子类对象都有自己独立的副本。子类可以直接访问这些变量,或者通过重写的方法来访问和修改它们。

abstract class Animal {
    public float num_float = 123.456f;  // 实例变量
}
  • num_float 是实例变量,每个实例(包括子类的实例)都有这个变量的副本。子类可以直接访问它。

2. 静态变量(常量或非常量)

抽象类也可以包含静态变量,这些变量属于类本身而不是类的实例。所有通过该类或子类访问这个变量时,都访问的是相同的内存位置。

abstract class Animal {
    public static int num = 123;  // 静态变量
}
  • num 是静态变量,所有 Animal 类及其子类共享这个变量。你可以通过 Animal.num 来访问它。

3. 常量public static final

常量是指一旦被赋值就不能改变的变量。常量通常是静态的,意味着它们是属于类的,而不是某个实例的。常量在抽象类中使用时一般都加上 public static final 修饰符。

abstract class Animal {
    public static final String TYPE = "动物";  // 常量
}
  • TYPE 是一个常量,public static final 表示它是类级别的,且值不可更改。它被所有继承 Animal 类的子类共享。
package com.oop.demo09;

public class Test {
    public static void main(String[] args) {
        //new Animal(); //抽象类的实例不是直接new 而是通过多态 父类(抽象类)的引用指向子类的实例
        Animal.eat();//通过类名直接引用抽象类中的静态方法
        Animal d1 = new Dog();//通过子类将父类(抽象类中的抽象方法)实现且必须全部实现 否则就将子类也声明成抽象类
        System.out.println(d1.num);
        System.out.println(d1.num_float);
        d1.breath();//父类的引用 直接调用自己的方法(子类没有重写)
        d1.sound();//子类实例 用重写过的抽象类中抽象方法
        Animal c1 = new Cat();
        System.out.println(c1.num);
        System.out.println(c1.num_float);
        c1.breath();//父类的引用 直接调用自己的方法(子类没有重写)
        c1.sound();//子类实例 用重写过的抽象类中抽象方法
    }
}

abstract class Animal {
    //抽象类中可以定义属性  静态的 非静态的都可以
    public static int num = 123;
    public float num_float=123.456f;
   //抽象类可以定义构造器
    public Animal(){

    }
    //抽象类可以定义静态方法
    public static void eat(){
        System.out.println("他在吃东西!");
    }
    public void breath(){   //抽象类可以定义实例方法
        System.out.println("他在呼吸!");
    }

    public abstract void sound(); //只有方法的声明,没有方法体

    //new Animal();//抽象类不能直接实例化,得借助子类进行实例化(多态)
    //new Dog();//也不能在抽象类里面实例对象

}
class Dog extends Animal{
    public void sound(){
        System.out.println("Bark!");//在子类中将抽象方法具体实现
    }
}
class Cat extends Animal{
    public void sound(){
        System.out.println("Miao Miao!");
    }
}

输出结果:

他在吃东西!
123
123.456
他在呼吸!
Bark!
123
123.456
他在呼吸!
Miao Miao!
posted @ 2025-01-13 22:21  panghuhu~  阅读(68)  评论(0)    收藏  举报