java编程思想——抽象类和接口的详解(实例)

本文详细探讨了Java中的抽象类和接口,包括它们的概念、特点和实际应用场景。解释了为什么抽象类和接口不能被实例化,并通过适配器模式、模板设计、工厂设计、代理设计等模式阐述了它们的重要性。此外,还讨论了Java单继承的原因以及如何利用多态性进行实例化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、抽象类的概念和作用

1.抽象的定义

抽象是把多个事物的共性的内容抽取出来,本质就是把我们关注的内容抽取出来。(比如:宝马、奔驰都属于汽车,汽车是抽象出来的概念)

2.抽象类

Java中可以定义没有方法体的方法,该方法由其子类来具体的实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。

3.抽象方法的特点

(1)只有方法头没有方法体的方法称之为抽象方法。(即只有方法的声明,没有方法的实现)
(2)抽象方法用abstract关键字来修饰。
(3)抽象方法代表一种不确定的操作或行为。(由子类去具体实现)
(4)抽象方法不能被调用。

4.抽象类的特点

(1)定义中含有抽象方法的类叫做抽象类。
(2)抽象类用abstract关键字来修饰。
(3)抽象类代表一种抽象的对象类型。
(4)抽象类不能实例化。
(5)抽象类中可以有具体方法,可以没有抽象方法。(也就是说一个类中只要有一个方法是抽象方法那么这个类一定是抽象类,反过来,一个抽象类中可以没有抽象方法,可以带有具体
实现的方法),抽象方法用abstract修饰,普通方法不用abstract修饰
(6)一旦一个类中有抽象方法,那么这个类必须也要用abstract来修饰,代表这个类是抽象类,它是不能被实例化的。

抽象类和接口为什么不能被实例化的原因

二、理解抽象类和接口

用一个适配器的例子来理解抽象类和接口

没有使用适配器的时候,实现接口的类要实现接口的所有方法,即便只是对其中一个方法进行了实现

在这里插入图片描述

建立一个抽象类实现接口(适配器概念),再用抽象类的子类重写想要实现的方法

在这里插入图片描述

tips:对于接口,你需要继承接口里边所有的实现,而建立一个抽象类实现接口,那么可以用一个普通类实现这个抽象类就可以实现你需要的方法,方便了许多。

下面就是一个抽象类和接口引发的血案:

涉及到

1)掌握抽象类和接口的实例化操作。
2)掌握模板设计的作用。
3)掌握工厂设计模式的作用。
4)掌握代理设计模式的作用。
5)掌握适配器模式的作用。
6)掌握抽象类与接口的使用区别。

具体内容呢?
1、在java中,可以通过对象的多态性,为抽象类和接口实例化,这样再使用抽象类和接口的时候就可以调用本子类中所覆写过的方法。
  之所以抽象类和接口不能直接实例化,是因为其内部包含了抽象方法,抽象方法本身是未实现的方法,所以无法调用。
  通过对象多态性可以发现,子类发生了向上转型关系之后,所调用的全部方法,都是被覆写过的方法。如下:

abstract class A{    // 定义抽象类A
    public abstract void print() ;    // 定义抽象方法print()
};
class B extends A {    // 定义子类,继承抽象类
    public void print(){        // 覆写抽象方法
        System.out.println("Hello World!") ;
    }
};
public class AbstractCaseDemo01{
    public static void main(String args[]){
        A a = new B() ;        // 通过子类为抽象类实例化,向上转型。
        a.print() ;
    }
};
运行结果:
Hello World!

可以继续利用此概念,为接口实例化。

package com.zhijin;
interface A{    // 定义抽象类A
    public abstract void print() ;    // 定义抽象方法print()
};
class B implements A {    // 定义子类,继承抽象类
    public void print(){        // 覆写抽象方法
        System.out.println("Hello World!!!") ;
    }
};
public class ThisDemo06{
    public static void main(String args[]){
        A a = new B() ;        // 通过子类为抽象类实例化
        a.print() ;
    }
};

所以,如果想要使用抽象类和接口,则只能按照以上操作完成。
2、抽象类的实际使用场景–设计模式(模板设计)

super : 动物
子类:猫、狗

abstract class Animal{
    private String name ;        // 定义name属性
    private int age ;            // 定义age属性
    public Animal(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String getName(){
        return this.name ;
    }
    public int getAge(){
        return this.age ;
    }
    public void say(){        // 人说话是一个具体的功能
        System.out.println(this.getContent()) ;    // 输出内容
    }
    public abstract String getContent() ;    // 说话的内容由子类决定
};
class Cat extends Animal{
    private String call;
    public Cat(String name,int age,String call){
        super(name,age) ;    // 调用父类中的构造方法
        this.call= call ;
    }
    public String getContent(){
        return    " 姓名:" + super.getName() + 
                ";年龄:" + super.getAge() + 
                ";叫声:" + this.call;
    }
};
class Dog extends Animal{
    private String call ;
    public Dog (String name,int age,String call){
        super(name,age) ;    // 调用父类中的构造方法
        this.call= call;
    }
    public String getContent(){
        return    "姓名:" + super.getName() + 
                ";年龄:" + super.getAge() + 
                ";叫声:" + this.call ;
    }
};
public class AbstractCaseDemo02{
    public static void main(String args[]){
        Animal per1 = null ;    // 声明Animal 对象
        Animal per2 = null ;    // 声明Animal 对象
      per1 = new Cat("猫儿",2,"喵儿") ;    
        per2 = new Dog("小狗",10,"wangwang") ;    
        per1.call() ;    
        per2.call() ;  
    }
};
运行结果:
姓名:张三;年龄:2;喵儿
姓名:李四;年龄:10;wangwang

tips:抽象类就相当于一个模板,现实的模板:

在这里插入图片描述

3、接口的实际应用–制定标准

比如说“U盘和打印机都可以插在电脑上使用,因为他们都实现了USB标准的接口”

interface USB{        // 定义了USB接口
    public void start() ;    // USB设备开始工作
    public void stop() ;    // USB设备结束工作
}
class Computer{
    public static void plugin(USB usb){    // 电脑上可以插入USB设备,向上转型,这里就相当于一个接口,只有符合这个接口的标准的类的对象(即只有继承这个接口的类的对象),才能被这个方法调用。
        usb.start() ;
        System.out.println("=========== USB 设备工作 ========") ;
        usb.stop() ;
    }
};
class Flash implements USB{
    public void start(){    // 覆写方法
        System.out.println("U盘开始工作。") ;
    }
    public void stop(){        // 覆写方法
        System.out.println("U盘停止工作。") ;
    }
};
class Print implements USB{
    public void start(){    // 覆写方法
        System.out.println("打印机开始工作。") ;
    }
    public void stop(){        // 覆写方法
        System.out.println("打印机停止工作。") ;
    }
};
public class InterfaceCaseDemo02{
    public static void main(String args[]){
        Computer.plugin(new Flash()) ;
      Computer.plugin(new Print()) ;
    }
};
运行结果:
U盘开始工作。
=========== USB 设备工作 ========
U盘停止工作。
打印机开始工作。
=========== USB 设备工作 ========
打印机停止工作。

4、工厂设计模式–接口应用

interface Fruit{    // 定义一个水果接口
    public void eat() ;    // 吃水果
}
class Apple implements Fruit{
    public void eat(){
        System.out.println("** 吃苹果。") ;
    }
};
class Orange implements Fruit{
    public void eat(){
        System.out.println("** 吃橘子。") ;
    }
};
public class InterfaceCaseDemo03{
    public static void main(String args[]){
        Fruit f = new Apple() ;    // 实例化接口
        f.eat() ;
    }
};
运行结果:
吃苹果。

看起来上边的代码没有什么大问题,但是扩展性呢?
JVM工作原理:程序-》JVM(相当于客户端)-》操作系统。

问题的解决:客户端通过过渡端,得到特定子类的接口实例,返回接口实例给客户端,接口实例调用接口中的方法。
此时就涉及到了工厂模式

interface Fruit{    // 定义一个水果接口
    public void eat() ;    // 吃水果
}
class Apple implements Fruit{
    public void eat(){
        System.out.println("** 吃苹果。") ;
    }
};
class Orange implements Fruit{
    public void eat(){
        System.out.println("** 吃橘子。") ;
    }
};
class Factory{    // 定义工厂类
    public static Fruit getInstance(String className){ //注意这里的方法是static修饰的,因为在主方法中是Factory调用
        Fruit f = null ;
        if("apple".equals(className)){    // 判断是否要的是苹果的子类
            f = new Apple() ;
        }
        if("orange".equals(className)){    // 判断是否要的是橘子的子类
            f = new Orange() ;
        }
        return f ;
    }
};
public class InterfaceCaseDemo04{
    public static void main(String args[]){
        Fruit f = Factory.getInstance(”apple“) ;    // 实例化接口
        f.eat() ;
    }
};
运行结果:
**吃苹果

5、代理模式–接口应用
这里说的代理模式有很多种,讨债公司代理要讨债的人,江歌案中(日本律师代理江母),下面我们讲一下我们经常使用的代理服务器;

interface Network{  
    public void browse() ;    // 浏览
}
class Real implements Network{  //真实上网操作类
    public void browse(){
        System.out.println("上网浏览信息") ;
    }
};
class Proxy implements Network{  //代理类。
   private Network network ;    // 代理对象
    public Proxy(Network network){  //初始化,把真实对象传给代理对象,向上转型操作。
        this.network = network ;
    }
    public void check(){
        System.out.println("检查用户是否合法。") ;
    }
    public void browse(){
        this.check() ;
        this.network.browse() ;    // 调用真实的主题操作,这里调用的是真实类里的对象。
    }
};
public class ProxyDemo{
    public static void main(String args[]){
        Network net = null ;
        net  = new Proxy(new Real()) ;//  指定代理操作,这里两次向上转型操作,第一次向上是实例化代理类,
第二次向上转型是括号中,把真实类对象传入,以便在代理类中调用真实类中的方法。

        net.browse() ;    // 客户只关心上网浏览一个操作
    }
};
运行结果:
检查用户是否合法
上网浏览信息

5、适配器模式–上边刚开始的案例
在Java中,一个子类实现一个接口,则肯定在子类中复写此接口中全部抽象方法,那么这就造成提供的抽象方法过多,而实际不需要,那么我们会选择一个中间过渡(也就是适配器模式)

在这里插入图片描述

interface Window{        // 定义Window接口,表示窗口操作
    public void open() ;    // 打开
    public void close() ;    // 关闭
    public void activated() ;    // 窗口活动
    public void iconified() ;    // 窗口最小化
    public void deiconified();// 窗口恢复大小
}
abstract class WindowAdapter implements Window{
    public void open(){} ;    // 打开
    public void close(){} ;    // 关闭
    public void activated(){} ;    // 窗口活动
    public void iconified(){} ;    // 窗口最小化
    public void deiconified(){};// 窗口恢复大小
};
class WindowImpl extends WindowAdapter{
    public void open(){
        System.out.println("窗口打开。") ;
    }
    public void close(){
        System.out.println("窗口关闭。") ;
    }
};
public class AdapterDemo{
    public static void main(String args[]){
        Window win = new WindowImpl() ;
        win.open() ;
        win.close() ;
    }
};
运行结果:

窗口打开。
窗口关闭。

6、内部类的扩展

abstract class A{    // 定义抽象类
    public abstract void printA() ;    // 抽象方法
    interface B{    // 定义内部接口
        public void printB() ;    // 定义抽象方法
    }
};
class X extends A{    // 继承抽象类
    public void printA(){
        System.out.println("HELLO --> A") ;
    }
    class Y implements B{    // 定义内部类实现内部接口
        public void printB(){
            System.out.println("HELLO --> B") ;
        }
    };
};
public class InnerExtDemo01{
    public static void main(String args[]){
        A.B b = new X().new Y() ;  //参考前面内部类的知识,实现内部类实例的方法:外部类.内部类  内部类对象= 外部类对象.new  内部类
        b.printB() ;
    }
};
运行结果:
HELLO-->B

含有内部接口的抽象类的子类,必须也要定义内部类继承该接口。

interface A{    // 定义接口
    public void printA() ;    // 抽象方法
    abstract class B{    // 定义内部抽象类
        public abstract void printB() ;    // 定义抽象方法
    }
};
class X implements A{    // 实现接口
    public void printA(){
        System.out.println("HELLO --> A") ;
    }
    class Y extends B{    // 继承抽象类
        public void printB(){
            System.out.println("HELLO --> B") ;
        }
    };
};
public class InnerExtDemo02{
    public static void main(String args[]){
        A.B b = new X().new Y() ;
        b.printB() ;
    }
};

含有内部抽象类的接口,对于继承他的子类来说,除了要覆写接口中的抽象方法,还要专门定义一个内部类继承抽象类,并覆写全部抽象类。
 从开发中,一般不推荐,看起来这些代码有点混乱。

总结:

在这里插入图片描述


Tips:在开发中,一个类永远不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口,如果两个类同时可以使用的话,优先使用接口,避免单继承的局限性。

java类为什么是单继承?

1)抽象类和接口类的实例化,通过多态性(向上转型,向下转型)。
2)抽象类表示一个模板,接口表示一个标准。
3)常见的设计模式:模板设计,工厂设计,代理设计,适配器设计。


参考资料:

抽象类和接口的详解(实例)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值