JAVA冷知识JAVA居然支持多继承吗?让我们用内部类去实现吧
写在前面JAVA冷知识 ,今天和小伙伴分享的是通过内部类的方式实现 JAVA的多继承 一个 Demo 和JDK源码 中的具体场景部分内容参考 《编写高质量代码(改善Java程序的151个建议)》《Effective Java》中文版第3版 博文理解有误的地方小伙伴留言私信一起讨论
与亲近之人不要说气话,不要说反话,不要不说话。——烽火戏诸侯 《剑来》
众多周知,对于面向对象语言来讲,JAVA是不支持多继承的,只支持单继承,但是提供了接口来补偿。
在实际的项目中,接口更多的用于行为的委托,把类本身一些是共性但又是特定的行为委托给一个接口的具体实现,当然接口也可以用于属性的委托,对象结构型的设计模式大都采用接口的方式来实现对对象内部组成的注册和操作
如果实现java的多继承,其实很简单,关键是对于内部类的特征的掌握,内部类可以继承一个与外部类无关的类,保证了内部类天然独立性,根据这个特性从而实现一个类可以继承多个类的效果
下面我们看一个Demo,声明父母两个接口,实现父母两个类,看如何通过内部类来继承父母类,而不是通过,接口委托的方式, 一个Demo
父亲接口 package com.liruilong; /** * @Project_name: workspack * @Package: com.liruilong * @Description: 父亲接口 * @Author: 1224965096@qq.com * @WeChat_Official_Accounts: 山河已无恙 * @blog: https://liruilong.blog.csdn.net/ * @Date: 2022/2/12 2:48 */ public interface Father { /** * @return: int * @Description 强壮的行为 * @author LiRuilong * @date 2022/2/12 2:49 **/ int strong(); }
父亲实现类 package com.liruilong; /** * @Project_name: workspack * @Package: com.liruilong * @Description: 父亲类 * @Author: 1224965096@qq.com * @WeChat_Official_Accounts: 山河已无恙 * @blog: https://liruilong.blog.csdn.net/ * @Date: 2022/2/12 2:51 */ public class FatherImpl implements Father { static public String height = "身体超高"; /** * @return: int * @Description 强壮值 * @author LiRuilong * @date 2022/2/12 2:51 **/ @Override public int strong() { return 8; } }
母亲接口 package com.liruilong; /** * @Project_name: workspack * @Package: com.liruilong * @Description: 母亲接口 * @Author: 1224965096@qq.com * @WeChat_Official_Accounts: 山河已无恙 * @blog: https://liruilong.blog.csdn.net/ * @Date: 2022/2/12 2:50 */ public interface Mother { /** * @return: int * @Description 温柔的行为 * @author LiRuilong * @date 2022/2/12 2:50 **/ int Kind(); }
母亲实现类 package com.liruilong; /** * @Project_name: workspack * @Package: com.liruilong * @Description: 母亲类 * @Author: 1224965096@qq.com * @WeChat_Official_Accounts: 山河已无恙 * @blog: https://liruilong.blog.csdn.net/ * @Date: 2022/2/12 2:51 */ public class MotherImpl implements Mother{ static public String pretty = "脸蛋特别漂亮"; /** * @return: int * @Description 温柔值 * @author LiRuilong * @date 2022/2/12 2:51 **/ @Override public int Kind() { return 8; } }
OK,准备工作做好了, 看我们如何实现。 package com.liruilong; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: 孩子类 * @Author: 1224965096@qq.com * @WeChat_Official_Accounts: 山河已无恙 * @blog: https://liruilong.blog.csdn.net/ * @Date: 2022/2/12 13:16 */ public class Son extends FatherImpl implements Mother { static Logger logger = Logger.getAnonymousLogger(); MotherSpecial motherSpecial = new MotherSpecial(); @Override public int strong() { return super.strong() + 1; } @Override public int Kind() { return motherSpecial.Kind(); } @Override public String toString() { return "Son{" + "height=" + height +"," + "pretty=" + MotherSpecial.pretty + "}"; } public class MotherSpecial extends MotherImpl { @Override public int Kind() { return super.Kind() - 1; } } public static void main(String[] args) { Son son = new Son(); logger.info(son.toString()); logger.info(son.strong()+""); logger.info(son.Kind()+""); } }
我们用内部类继承一个外部类无关的类,实现了 Son 类的多继承Bad level value for property: .level Bad level value for property: java.util.logging.ConsoleHandler.level Can""t set level for java.util.logging.ConsoleHandler 二月 12, 2022 2:02:06 下午 com.liruilong.Son main 信息: Son{height=身体超高,pretty=脸蛋特别漂亮} 二月 12, 2022 2:02:06 下午 com.liruilong.Son main 信息: 9 二月 12, 2022 2:02:06 下午 com.liruilong.Son main 信息: 7 Process finished with exit code 0
这里只是讨论这样的写法,我个人认为,这种方法有些 鸡肋 。这种方式实现的多继承 ,完全可以通组合 的方式来实现,我们简单分析一下优缺点优缺点分析优点:
通过内部类的方式,把继承关系控制在类的内部,理论上 比通过组合的方式更加安全 ,代码可读性要好一点。
更符合设计原则中的 迪米特法则 ,又称最少知道原则(Demeter Principle),一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。缺点:
首先通过继承的方式实现, 打破了类的封装性 ,子类依赖于其超类中特定功能的实现细节。 超类的实现有可能会随着发行版本的不同而有所变化,如果真的发生了变化,即使子类的代码完全没有改变,但是子类可能会遭到破坏因而,子类必须要跟着其超类的更新而演变,除非超类是专门为了扩展而设计的,并且具有很好的文挡说明 。
其次,通过这样的方式实现的,不符合常态思想,尤其内部类同名的情况,容易被忽略某些特性(见JDK源码)。 JDK源码中的运用
关于通过内部类来实现 java多继承 的JDK 场景,我们简单分析一下asListList integers = Arrays.asList(1, 2, 3);
这个代码小伙伴们一定不陌生,这里通过 Arrays 工具类来生成一个List ,但是这里的List 并不是真正的ArrayList ,而是在Arrays工具类 内部定义的一个继承了AbstractList的静态内部类ArrayList ,这里java通过内部类的方式巧妙的实现了。 ....... @SafeVarargs @SuppressWarnings("varargs") public static List asList(T... a) { return new ArrayList<>(a); } /** * @serial include */ private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } .................
但是这里同样需要注意的是 通过内部类实现多继承要考虑其类的特殊性 :
这样生成的 List 调用add 方法会抛不支持的操作的异常 ,基于Arrays 的ArrayList 是一个静态私有内部类,除了Arrays能访问以外,其他类都不能访问,正常的ArrayList中add方法是ArrayList父类提供,Arrays的内部类ArrayList没有覆写add方法。
下面源码为 ArrayList静态内部类 实现的个方法。 /** * @serial include */ private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override public int size() { return a.length; } @Override public Object[] toArray() { return a.clone(); } @Override @SuppressWarnings("unchecked") public T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.getClass()); System.arraycopy(this.a, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } @Override public E get(int index) { return a[index]; } @Override public E set(int index, E element) { E oldValue = a[index]; a[index] = element; return oldValue; } @Override public int indexOf(Object o) { E[] a = this.a; if (o == null) { for (int i = 0; i < a.length; i++) if (a[i] == null) return i; } else { for (int i = 0; i < a.length; i++) if (o.equals(a[i])) return i; } return -1; } @Override public boolean contains(Object o) { return indexOf(o) != -1; } @Override public Spliterator spliterator() { return Spliterators.spliterator(a, Spliterator.ORDERED); } @Override public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); for (E e : a) { action.accept(e); } } @Override public void replaceAll(UnaryOperator operator) { Objects.requireNonNull(operator); E[] a = this.a; for (int i = 0; i < a.length; i++) { a[i] = operator.apply(a[i]); } } @Override public void sort(Comparator<? super E> c) { Arrays.sort(a, c); } }
即没有实现 add 和remove 方法,所以asList 返回的为一个长度不可变的列表 ,数组为多长转换为列表为多长,即不在保持列表动态变长的特性 。subList
嗯,不多讲,直接上代码 ArrayList arrayList = new ArrayList(); LinkedList linkedList = new LinkedList(); Vector vector = new Vector(); linkedList.subList(2,3); arrayList.subList(2,3); vector.subList(2,3);
List 提供一个subList 方法,与String 的subString 有点类似,这里的List 通过subList 生成子list 方式也是通过内部类继承方式的多继承 实现的。
当然这里,具体需要分析, ArrayList 和其他List 的实现的方式略有不同
ArrayList 是自己定义的内部类SubList 继承AbstractList 实现的public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable { ....... public List subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); } ..... private class SubList extends AbstractList implements RandomAccess { private final AbstractList parent; private final int parentOffset; private final int offset; int size; .........
LinkedList 的subList 方法是由AbstractList 实现的,它会根据是不是随机存储 提供不同的实现方法 ,subList 返回的类也是AbstractList的子类SubList 。public abstract class AbstractList extends AbstractCollection implements List { ........ public List subList(int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList<>(this, fromIndex, toIndex) : new SubList<>(this, fromIndex, toIndex)); } class SubList extends AbstractList { ... } class RandomAccessSubList extends SubList implements RandomAccess{ ....... } ........ }
这里需要注意的是,不管是ArrayList还是LinkedList等其他List,通过SubList内部类生成的List,其所有的方法(get,add,set,remove等)都是在 原始列表上操作 的,它自身并没有生成一个数组或是链表 ,也就是子列表只是原列表的一个视图(View) ,所有的修改都反映在原列表 上。
微信读书是否能颠覆kindle?作为一个目前有三台kindle和每天都在使用微信读书的用户,我的结论是微信读书必定会颠覆kindle!原因有以下几点第一,墨水屏并不是kindle的壁垒。微信读书如果愿意,也可以出
数字化工厂总体设计与建设方案超详细剖析数字化工厂伴随数字仿真技术和虚拟现实技术发展而来,是智能制造发展的重要实践模式,它通过对真实工业生产的虚拟规划仿真优化,实现对工厂产品研发制造生产和销售服务的优化和提升,是现代工业
工厂周边百名儿童鼻出血比亚迪陷污染指控后承诺彻底整改独家凤凰网新视界出品作者季倩编辑于浩5月7日,据中国慈善家杂志报道,长沙比亚迪雨花区工厂(下称长沙比亚迪)陷入环境污染漩涡。凤凰网新视界了解到,近两个月,比亚迪长沙工厂附近有浓烈的油漆
CTFSSTI(服务器模板注入)绕过过滤绕过绕过姿势getitem绕过。class。mro。getitem(2)。subclasses()。getitem(40)(etcpasswd)。read()。class。mr
小小SDK,如何玩转人脸识别2022年两会期间,有人大代表提出身联网,将人体与互联网相连的技术。2020年开始,历经几轮疫情之后,社区和企业厂区越来越关注无接触快速精准识别,AI人脸识别业务迎来短暂的黄金时代
积极推动民用和军用的小型无人飞艇的尝试随着现在无人机在各行各业显示出来的优势使用,以及无人机在战场上的优异表现,未来在无人机领域竞争肯定会越来越激烈。因为各国都会投入更多去支持本国的无人机产业。我们中国除了应该继续积极
组装机台式电脑组装机和原装机有什么区别?台式电脑组装机和原装机的区别有稳定性方面灵活性方面以及外观方面。一稳定性方面1原装机有自己独立的技术部门,会针对原装机的各部件进行严格的测试和检验,所以兼容性非常好,不容易出现故障
你怎么看待去美国化的电脑文件根据网上泄露的某文件,说相关部门需要推进,替换掉美国产的电脑硬件。全部换成国产硬件,国产cpu,国产内存,国产磁盘。从爱国者的意义上来说我举双手双脚支持这种举措。但是我想了解的是这
iPhone14全系惨遭曝光果粉看完沉默了中关村在线消息苹果将于6月召开WWDC开发者大会,iOS16手机操作系统将在本次发布会中登场,不出意外的话,iPhone14系列将会首发搭载。近日,大家关心的iPhone14配置被
经典再升级,还能延续经典吗?兴戈洛神EM2R絮叨如果说青春有记忆的话,我能联想到的东西可太多了。但如果就听音乐这件事来说,除了一首首旋律烂熟于心的曲子以外,最能承载记忆的也就是各种设备了,这里头播放器和耳塞是必不可少。早在去
iPhone14系列曝光,抢先看大家放心,还有4个多月的时间,我们才会和iPhone14系列见面。根据网上爆料的信息,外媒汇总了iPhone14系列的相关配置规格,并绘制了渲染图。如下图这次iPhone14系列取