3.2 抽象类

文章介绍了Java中抽象类和抽象方法的概念,包括它们的定义、格式、特点以及使用场景。通过示例展示了如何创建抽象类,子类如何继承并实现抽象方法。还提供了构造函数和成员测试的练习,强调了抽象类不能实例化,但可以有构造方法供子类使用,以及静态成员在多态中的行为。


1.概念

Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法.
Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类

注意:

  1. 如果一个类含有抽象方法,那么它一定是抽象类,但是一个抽象类中,可以没有抽象方法;
  2. 抽象类中的方法实现交给子类来完成;

2.格式

权限修饰符  abstract  返回值类型  方法名   (参数列表);

3.特点

  1. abstract 可以修饰方法或者类
  2. 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
  3. 抽象类中可以没有抽象方法
  4. 如果类中有抽象方法,那么该类必须定义为一个抽象类
  5. 子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写
  6. 多用于多态中
  7. 抽象类不可以被实例化

4.抽象入门案例

package partTwo;

public class AbstractDemo {
    public static void main(String[] args) {
        //5.创建对象进行测试
        /* 抽象类不可以被创建对象
         * 可以创建多态对象进行测试*/
        // Animal7 a = new Animal7();  // 会报错
        Animal7 a = new Pig3();
        a.eat();  //调用的是父类的普通方法
        a.fly();  //调用的是抽象父类的声明,普通子类的具体实现
        a.fly2();  //调用的是抽象父类的声明,普通子类的具体实现
    }
}
//1.创建父类
/* 1.如果一个类中包含了抽象方法,那么这个类必须被声明成抽象类
 * 抽象类:被abstract关键字修饰的类*/

abstract class Animal7 {
    //2.创建抽象方法
    /* 2.被abstract修饰的方法是抽象方法,并且抽象方法没有方法体*/
    public abstract void fly();

    public abstract void fly2();

    //3.创建抽象类里的普通方法
    /* 3.抽象类里可以有:全普 / 全抽 / 半普 / 半抽 ,方法不做限制*/
    public void eat() {
        System.out.println("吃啥都行");
    }

    public void play() {
        System.out.println("玩啥都行");
    }
}
//4.创建Animal的子类Pig
/* 4.当一个子类继承了一个抽象父类之后,有俩种解决方案:
 * 方案一:变成抽象类,“躺平”,我也不实现,继续抽象
 * 方案二:实现抽象父类中所有的抽象方法,“父债子偿”*/
//4.1 使用方案一
// abstract class Pig extends Animal{  //方案一
//报错:Class 'Pig' must either be declared abstract or implement abstract method 'fly()' in 'Animal'}
//4.2 使用方案二
class  Pig3 extends Animal7 {
    @Override
    public void fly() {
        System.out.println("我爸的债我终于还清了,我家的猪终于飞起来了~");
    }
    @Override
    public void fly2() {
        System.out.println("抽象父类的所有抽象方法都需要实现,子类才能是普通子类");
    }
}

5.练习:抽象类构造函数测试

抽象类中的构造函数通常在子类对象实例化时使用

package partTwo;
/* 本类用于测试抽象类中构造函数的使用
 * 抽象类中是否有构造方法?
 * 既然抽象类不能实例化,为什么要有构造方法?
 * 不是为了自己使用,是为了子类创建对象时使用super*/
public class AbstractDemo2 {
    public static void main(String[] args) {
        //5.测试抽象类能否实例化、
        // Animal2 a = new Animal2();  //抽象类不可以被实例化

        //6.创建子类对象进行测试
        Pig6 p = new Pig6();
    }
}

//1.创建抽象父类
abstract class Animal8{
    //2.创建构造方法
    public Animal8(){
        System.out.println("我是Animal2抽象类的无参构造");
    }
}

//3.创建子类
class Pig6 extends Animal8{
    public Pig6(){
        System.out.println("我是pig2的无参构造");
    }
}
  1. 抽象类中可以有构造方法
  2. 其构造方法是为了给子类创建对象时使用的

6.练习:抽象类成员测试

package partTwo;
/* 本类用作抽象类中的成员测试*/
public class AbstractDemo3 {
public static void main(String[] args) {
        //可以创建抽象类对象吗?  不可以
        //Animal9 animal9 = new Animal9();

        //可以创建实现抽象类子类的对象吗?  可以,只要子类不是抽象类
        Tiger tiger = new Tiger();

        //创建多态
        Animal9 animal = new Tiger();

        System.out.println(animal.sum);   //输出100,静态成员随着类的加载而加载,谁调用就返回谁的
        System.out.println(animal.age);   //输出11,静态成员随着类的加载而加载,谁调用就返回谁的
        System.out.println(animal.name);   //输出peiqi,静态成员随着类的加载而加载,谁调用就返回谁的

        animal.get();   //输出乔治,子类没有重写父类方法,所以还是调用父类方法
        animal.get2();   //输出佩奇,子类没有重写父类方法,所以还是调用父类方法
        animal.get3();   //输出喜羊羊,子类没有重写父类方法,所以还是调用父类方法

        animal.eat();   //输出父类干饭人,子类没有重写父类方法,所以还是调用父类方法
        animal.eat2();  //输入子类重写方法
        animal.eat3();  //输入子类重写方法
        //animal.eat4();    会报错,多态对象不能使用子类的特有功能,因为它认为自己是父类型
        //animal.eat5();    会报错,多态对象不能使用子类的特有功能,因为它认为自己是父类型
    }
}
// 创建抽象父类
abstract class Animal9{
    /* 1.抽象类中可以定义成员变量吗?   可以*/
    int sum = 11;
    /* 2.抽象类中可以定义静态变量吗?   可以*/
    static int age = 11;
    /* 3.抽象类中可以定义成员常量吗?   可以*/
    final String name = "peiqi";
    /* 4.抽象类中可以有普通方法吗?   可以*/
    public void eat(){
        System.out.println("父类干饭人");
    }
    /* 5.抽象类中可以都是普通方法吗?   可以*/
    /* 6.抽象类中可以有抽象方法吗?   可以*/
    /* 7.抽象类中可以都是抽象方法吗?   可以*/
    public abstract void eat2();
    public abstract void eat3();

    public void get() {
        System.out.println("乔治");
    }
    public void get2() {
        System.out.println("佩奇");
    }
    /* 8.抽象类中有静态方法吗?   可以*/
    public static void get3(){
        System.out.println("喜羊羊");
    }
}

//2.创建子类
//abstract class eat extends Animal3{  }  //抽象子类创建方法
class Tiger extends Animal9{  //普通子类创建方法

    int num = 2;
    static int age = 2;

    final String name = "老虎精";


    //重写父类的抽象方法
    @Override
    public void eat2() {
        System.out.println("哎呦我去");
    }
    @Override
    public void eat3() {
        System.out.println("哎呀妈呀");
    }

    public static void eat4(){
        System.out.println("静静的吃");
    }

    public void eat5(){
        System.out.println("普通的吃");
    }
}

abstract注意事项:
抽象方法要求子类继承后必须重写。
那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。

  1. private:被私有化后,子类无法重写,与abstract相违背。
  2. static:静态优先于对象存在,存在加载顺序问题。
  3. final:被final修饰后,无法重写,与abstract相违背。
### Java 抽象类与接口的区别 #### 一、概念区分 抽象类是在面向对象编程中的一种特殊形式的类,它允许部分方法没有具体的实现。这些未实现的方法被称为抽象方法。任何包含一个或多个抽象方法的类必须被声明为抽象类[^1]。 接口则是一种完全抽象化的类,其中所有的方法默认都是公共的和抽象的(除非是静态方法或者默认方法)。接口主要用于定义一组行为规范而不涉及具体实现细节[^2]。 ```java // 定义一个简单的抽象类 abstract class Animal { public abstract void makeSound(); } // 定义一个简单的接口 interface Flyable { void fly(); // 默认public和abstract } ``` #### 二、语法差异 - **构造器**:抽象类可以拥有带参数甚至无参的构造函数;而接口不允许有构造函数。 - **成员变量**:抽象类可具有私有的字段和其他访问修饰符限定的属性;接口内的所有字段均为`static final`类型的常量,默认情况下也是这样设置的。 - **多继承支持度**:Java 类只能够单重继承自另一个父类,但是它可以同时实现多个不同接口。这意味着如果两个独立开发团队各自创建了自己的功能模块作为接口,则第三方开发者可以通过让自己的新类去实现这两个接口来轻松组合这两种能力[^3]。 #### 三、应用场景分析 ##### 3.1 接口的应用场景 当希望表达某种特定的能力时,比如飞行(`Flyable`) 或者 可打印 (`Printable`) ,应该优先考虑使用接口。因为这代表了一种“能做什么”的契约关系而不是“是什么样的实体”。此外,在设计大型系统架构的时候,利用接口可以让各个组件之间解耦合程度更高,便于后期维护扩展[^4]。 ##### 3.2 抽象类的应用场景 对于那些共享相同基础逻辑但又存在某些个性化操作需求的情况来说,采用抽象类会更加合适。例如动物王国里各种生物都会发出声音这一共通特性就可以放在 `Animal` 这个抽象基类里面统一处理,而对于每一种具体物种而言如何发声则是由各自的派生类负责完成的具体工作。 ```java class Dog extends Animal implements Flyable { // 错误示范, 假设狗不会飞 @Override public void makeSound() { System.out.println("Bark"); } @Override public void fly() { throw new UnsupportedOperationException("Dogs cannot fly!"); } } ``` 上述例子展示了错误地尝试使犬科动物具备飞翔能力的情形——实际上这是违反常识的设计决策。因此在实际项目实践中应当谨慎选择适用哪种方式以达到最佳效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值