聊聊java中的多继承,解决Java8接口default方法多继承冲突问题【享学Java】(上)

简介: 聊聊java中的多继承,解决Java8接口default方法多继承冲突问题【享学Java】(上)

前言


众所周知,Java是一种面向对象的只允许单继承的语言,这是每个Java程序员从业者都知道定理。

本文的目的,主要从两个方面来思考Java单继承的这个问题:


  1. 为什么Java类被设计为只能单继承?
  2. 怎样曲线实现多继承的效果?


Java类为何设计为只能单继承?


我们都知道Java的主要设计者是James Gosling,下面我引用它的一段话来对Java语言进行定义:


Java是一种简单的,面向对象的,分布式的,解释型的,健壮的,安全的,架构中立的,可移植的,高性能的,支持多线程的,动态语言。


该定义中和本文有关的一个关键词是:简单的。这个特性被放在了定义的第一位置,可见它的重要性。


首先我用一个最为直观的例子来举例说明多继承带来的问题:


class Father {
    public void eat() {
        System.out.println("爸爸吃饭方式...");
    }
}
class Mother {
    public void eat() {
        System.out.println("妈妈吃饭方式...");
    }
}
// 加入多继承是被允许的
class Son extends Father, Mother {
}

假如上面的实例是编译不抱错的,那么请问下面测试代码会输入什么?


public class Main {
    public static void main(String[] args) {
        new Son().eat();
    }
}


是不是顿时脑袋puzzle了?可能有的小伙伴会说打印Father类的呀,因为extends的时候Father在前,Mother在后。当然这是一种语言设计的解决方案,但是作为一个高级语言简单的通过这种顺序去控制这么重要的一个特性,显然我认为是不明智的


在Java中,类是结构性的,如上示例的多继承会造成结构上的混乱,这也是多继承带来的非常著名的菱形继承问题。

上过大学的(开玩笑的)应该多多少少都了解点C++,它也是面向对象的语言,但是它支持多继承。这里其实是有一定的历史变迁的原因的:


  • C++语言是1983年由贝尔实验室的Bjarne Stroustrup在C语言的基础上推出的
  • Java语言是1995年由James Gosling共同正式推出的


Java整整延后了10+年时间,那可不要更高级一下吗。另外C++在使用过程中其实门槛是比较高的,其中一个重要原因就是它多继承的设计,让使用者(特别特别是新手)会经常掉入这个陷阱,即使它也提出了相应的解决办法。


请小伙伴理解这个高级的深刻含义,作为程序员对高级、底层等词汇的理解应该是更加深刻的


对比之下,Java就吸取了教训,本着简单的原则,舍弃了C++中的多继承,从而也使得了Java更具有安全性和健壮性


因此如上例子实际会编译报错:


image.png


为何Java类继承(实现)多个接口没有问题呢?


其实关于这一点,我个人认为Java语言在使用层面上已经做得很友好了。它把多个接口不叫继承extends,而叫实现implements,一下子从概念上就非常有区分度了,可谓对初学者非常之友好。


interface SmallEat {
    public void eat();
}
interface BigEat {
    public void eat();
}
class Son implements SmallEat, BigEat {
    @Override
    public void eat() {
        System.out.println("儿子自己的吃饭方式...");
    }
}


这个例子是能够正常编译通过,正常work的。对于为何接口为何能多继承解释如下:


  1. Java接口是行为性的,也就是说接口只是定义某个行为的名称
  2. 具体的实现动作,都在实现类本身这里。


因此,即使继承(实现)的多个接口中出现了同名的方法名,实现类中也有且只会有一个实现。所以并不会出现结构混乱的情况。

为何接口可以多继承extends接口?


通过上面的阐述,相信这个问题的答案也就迎刃而解了。


Java类如何实现多继承的效果?


这里可以先举个例子:我们知道JavaScript的对象是不支持继承的,但是它却可以通过扩展原型链(propertype)的方式来实现继承类似的效果。


同样本节想解决的问题是,Java是不支持多继承的,那若我就是想要双亲呢?

下面用一个经典的例子来阐述如何解决双亲问题:


class Father {
    public int strong(){
        return 9;
    }
}
class Mother {
    public int kind(){
        return 8;
    }
}


一个父亲和一个母亲,父亲的强壮指数是9,母亲的温柔指数是8。现在若生了一个儿子Son,理论上它应该是这样的:既有父亲的强壮,也有母亲的温柔。用代码可以表述双亲如下


class Son {
    //通过继承增强父亲的行为属性:比父亲更强壮
    private class Father_1 extends Father {
        @Override
        public int strong() {
            return super.strong() + 1;
        }
    }
    //增强母亲的行为属性:没有母亲温柔
    private class Mother_1 extends Mother {
        @Override
        public int kind() {
            return super.kind() - 2;
        }
    }
    //===============public对外暴露Son自己的行为===============
    public int getStrong() {
        return new Father_1().strong();
    }
    public int getKind() {
        return new Mother_1().kind();
    }
}


儿子继承了父亲,变得比父亲更加强壮;同时也继承了母亲,只不过温柔指数下降了,我举的这个例子是不是也非常符合现实啊,哈哈。


此方案用到了一个基础知识点:内部类可以继承一个与外部类无关的类,保证了内部类的独立性,从而达到高内聚的编码规范


说明:其实有多种方式都能实现类似的效果,本文我介绍的是我认为是使用更接近多继承思维来解决问题~

目录
打赏
0
0
0
0
37
分享
相关文章
|
17天前
|
Java 抽象类与接口在 Java17 + 开发中的现代应用实践解析
《Java抽象类与接口核心技术解析》 摘要:本文全面剖析Java抽象类与接口的核心概念与技术差异。抽象类通过模板设计实现代码复用,支持具体方法与状态管理;接口则定义行为规范,实现多态支持。文章详细对比了两者在实例化、方法实现、继承机制等方面的区别,并提供了模板方法模式(抽象类)和策略模式(接口)的典型应用示例。特别指出Java8+新特性为接口带来的灵活性提升,包括默认方法和静态方法。最后给出最佳实践建议:优先使用接口定义行为规范,通过抽象类实现代码复用,合理组合两者构建灵活架构。
32 2
|
3月前
|
Java Lambda 表达式:以 Foo 接口为例深入解析
本文深入解析了 Java 8 中 Lambda 表达式的用法及其背后的函数式接口原理,以 `Foo` 接口为例,展示了如何通过简洁的 Lambda 表达式替代传统匿名类实现。文章从 Lambda 基本语法、函数式接口定义到实际应用层层递进,并探讨默认方法与静态方法的扩展性,最后总结常见误区与关键点,助你高效优化代码!
84 0
Java多线程基础
本文主要讲解多线程相关知识,分为两部分。第一部分涵盖多线程概念(并发与并行、进程与线程)、Java程序运行原理(JVM启动多线程特性)、实现多线程的两种方式(继承Thread类与实现Runnable接口)及其区别。第二部分涉及线程同步(同步锁的应用场景与代码示例)及线程间通信(wait()与notify()方法的使用)。通过多个Demo代码实例,深入浅出地解析多线程的核心知识点,帮助读者掌握其实现与应用技巧。
|
5月前
|
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
294 60
【Java并发】【线程池】带你从0-1入门线程池
|
3月前
|
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
本文涉及InheritableThreadLocal和TTL,从源码的角度,分别分析它们是怎么实现父子线程传递的。建议先了解ThreadLocal。
128 4
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
|
2月前
|
java 多线程异常处理
本文介绍了Java中ThreadGroup的异常处理机制,重点讲解UncaughtExceptionHandler的使用。通过示例代码展示了当线程的run()方法抛出未捕获异常时,JVM如何依次查找并调用线程的异常处理器、线程组的uncaughtException方法或默认异常处理器。文章还提供了具体代码和输出结果,帮助理解不同处理器的优先级与执行逻辑。
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
90 0
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
164 23

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问