聊聊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();
    }
}


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


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


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

相关文章
|
4天前
|
Java Apache Maven
Java将word文档转换成pdf文件的方法?
【10月更文挑战第13天】Java将word文档转换成pdf文件的方法?
15 1
|
8天前
|
Java 编译器
Java“返回类型为 void 的方法不能返回一个值”解决
在 Java 中,如果一个方法的返回类型被声明为 void,那么该方法不应该包含返回值的语句。如果尝试从这样的方法中返回一个值,编译器将报错。解决办法是移除返回值语句或更改方法的返回类型。
|
8天前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
14 1
|
8天前
|
Java
让星星⭐月亮告诉你,Java synchronized(*.class) synchronized 方法 synchronized(this)分析
本文通过Java代码示例,介绍了`synchronized`关键字在类和实例方法上的使用。总结了三种情况:1) 类级别的锁,多个实例对象在同一时刻只能有一个获取锁;2) 实例方法级别的锁,多个实例对象可以同时执行;3) 同一实例对象的多个线程,同一时刻只能有一个线程执行同步方法。
9 1
|
5天前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第6天】Java零基础教学篇,手把手实践教学!
12 0
|
4天前
|
安全 Java UED
Java中的多线程编程:从基础到实践
本文深入探讨了Java中的多线程编程,包括线程的创建、生命周期管理以及同步机制。通过实例展示了如何使用Thread类和Runnable接口来创建线程,讨论了线程安全问题及解决策略,如使用synchronized关键字和ReentrantLock类。文章还涵盖了线程间通信的方式,包括wait()、notify()和notifyAll()方法,以及如何避免死锁。此外,还介绍了高级并发工具如CountDownLatch和CyclicBarrier的使用方法。通过综合运用这些技术,可以有效提高多线程程序的性能和可靠性。
|
4天前
|
缓存 Java UED
Java中的多线程编程:从基础到实践
【10月更文挑战第13天】 Java作为一门跨平台的编程语言,其强大的多线程能力一直是其核心优势之一。本文将从最基础的概念讲起,逐步深入探讨Java多线程的实现方式及其应用场景,通过实例讲解帮助读者更好地理解和应用这一技术。
22 3
|
8天前
|
Java 调度 UED
深入理解Java中的多线程与并发机制
本文将详细探讨Java中多线程的概念、实现方式及并发机制,包括线程的生命周期、同步与锁机制以及高级并发工具。通过实例代码演示,帮助读者理解如何在Java中有效地处理多线程和并发问题,提高程序的性能和响应能力。
|
6天前
|
缓存 安全 Java
使用 Java 内存模型解决多线程中的数据竞争问题
【10月更文挑战第11天】在 Java 多线程编程中,数据竞争是一个常见问题。通过使用 `synchronized` 关键字、`volatile` 关键字、原子类、显式锁、避免共享可变数据、合理设计数据结构、遵循线程安全原则和使用线程池等方法,可以有效解决数据竞争问题,确保程序的正确性和稳定性。
13 2
|
7天前
|
存储 安全 Java
Java-如何保证线程安全?
【10月更文挑战第10天】