返回顶部
首页 > 资讯 > 精选 >Java中继承多数为什么是有害的
  • 317
分享到

Java中继承多数为什么是有害的

2023-06-03 05:06:22 317人浏览 薄情痞子
摘要

这篇文章主要介绍“Java中继承多数为什么是有害的”,在日常操作中,相信很多人在Java中继承多数为什么是有害的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中继承多数为什么是有害的”的疑惑有所帮助!

这篇文章主要介绍“Java中继承多数为什么是有害的”,在日常操作中,相信很多人在Java中继承多数为什么是有害的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中继承多数为什么是有害的”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

  大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends 关系)。实际上80%的代码应该完全用interfaces写,而不是通过extends。“Java设计模式”一书详细阐述了怎样用接口继承代替实现继承。这篇文章描述设计者为什么会这么作。

  Extends是有害的;也许对于Charles Manson这个级别的不是,但是足够糟糕的它应该在任何可能的时候被避开。“JAVA设计模式”一书花了很大的部分讨论用interface继承代替实现继承。

  好的设计者在他的代码中,大部分用interface,而不是具体的基类。本文讨论为什么设计者会这样选择,并且也介绍一些基于interface的编程基础。

  接口(Interface)和类(Class)?

  一次,我参加一个Java用户组的会议。在会议中,Jams Gosling(Java之父)做发起人讲话。在那令人难忘的Q&A部分中,有人问他:“如果你重新构造Java,你想改变什么?”。“我想抛弃classes”他回答。在笑声平息后,它解释说,真正的问题不是由于class本身,而是实现继承(extends) 关系。接口继承(implements关系)是更好的。你应该尽可能的避免实现继承。

  失去了灵活性

  为什么你应该避免实现继承呢?第一个问题是明确的使用具体类名将你固定到特定的实现,给底层的改变增加了不必要的困难。

  在当前的敏捷编程方法中,核心是并行的设计和开发的概念。在你详细设计程序前,你开始编程。这个技术不同于传统方法的形式----传统的方式是设计应该在编码开始前完成----但是许多成功的项目已经证明你能够更快速的开发高质量代码,相对于传统的按部就班的方法。但是在并行开发的核心是主张灵活性。你不得不以某一种方式写你的代码以至于最新发现的需求能够尽可能没有痛苦的合并到已有的代码中。

  胜于实现你也许需要的特征,你只需实现你明确需要的特征,而且适度的对变化的包容。如果你没有这种灵活,并行的开发,那简直不可能。

  对于Inteface的编程是灵活结构的核心。为了说明为什么,让我们看一下当使用它们的时候,会发生什么。考虑下面的代码:

  f()
  {
  LinkedList list = new LinkedList();
  //...
  g( list );
  }

  g( LinkedList list )
  {
  list.add( ... );
  g2( list )
  }

  假设一个对于快速查询的需求被提出,以至于这个LinkedList不能够解决。你需要用HashSet来代替它。在已有代码中,变化不能够局部化,因为你不仅仅需要修改f()也需要修改g()(它带有LinkedList参数),并且还有g()把列表传递给的任何代码。象下面这样重写代码:

  f()
  {
  Collection list = new LinkedList();
  //...
  g( list );
  }

  g( Collection list )
  {
  list.add( ... );
  g2( list )
  }

  这样修改Linked list成hash,可能只是简单的用new HashSet()代替new LinkedList()。就这样。没有其他的需要修改的地方。

  作为另一个例子,比较下面两段代码:

  f()
  {
  Collection c = new HashSet();
  //...
  g( c );
  }

  g( Collection c )
  {
  for( Iterator i = c.iterator(); i.hasNext() )
  do_something_with( i.next() );
  }

  和

  f2()
  {
  Collection c = new HashSet();
  //...
  g2( c.iterator() );
  }

  g2( Iterator i )
  {
  while( i.hasNext() )
  do_something_with( i.next() );
  }


  g2()方法现在能够遍历Collection的派生,就像你能够从Map中得到的键值对。事实上,你能够写iterator,它产生数据,代替遍历一个Collection。你能够写iterator,它从测试框架或者文件中得到信息。这会有巨大的灵活性。

  耦合

  对于实现继承,一个更加关键的问题是耦合---令人烦躁的依赖,就是那种程序的一部分对于另一部分的依赖。全局变量提供经典的例子,证明为什么强耦合会引起麻烦。例如,如果你改变全局变量的类型,那么所有用到这个变量的函数也许都被影响,所以所有这些代码都要被检查,变更和重新测试。而且,所有用到这个变量的函数通过这个变量相互耦合。也就是,如果一个变量值在难以使用的时候被改变,一个函数也许就不正确的影响了另一个函数的行为。这个问题显著的隐藏于多线程的程序。

  作为一个设计者,你应该努力最小化耦合关系。你不能一并消除耦合,因为从一个类的对象到另一个类的对象的方法调用是一个松耦合的形式。你不可能有一个程序,它没有任何的耦合。然而,你能够通过遵守OO规则,最小化一定的耦合(最重要的是,一个对象的实现应该完全隐藏于使用他的对象)。例如,一个对象的实例变量(不是常量的成员域),应该总是private。我意思是某段时期的,无例外的,不断的。(你能够偶尔有效地使用protected方法,但是protected实例变量是可憎的事)同样的原因你应该不用get/set函数---他们对于是一个域公用只是使人感到过于复杂的方式(尽管返回修饰的对象而不是基本类型值的访问函数是在某些情况下是由原因的,那种情况下,返回的对象类是一个在设计时的关键抽象)。

  这里,我不是书生气。在我自己的工作中,我发现一个直接的相互关系在我OO方法的严格之间,快速代码开发和容易的代码实现。无论什么时候我违反中心的OO原则,如实现隐藏,我结果重写那个代码(一般因为代码是不可调试的)。我没有时间重写代码,所以我遵循那些规则。我关心的完全实用?我对干净的原因没有兴趣。

   脆弱的基类问题

  现在,让我们应用耦合的概念到继承。在一个用extends的继承实现系统中,派生类是非常紧密的和基类耦合,当且这种紧密的连接是不期望的。设计者已经应用了绰号“脆弱的基类问题”去描述这个行为。基础类被认为是脆弱的是,因为你在看起来安全的情况下修改基类,但是当从派生类继承时,新的行为也许引起派生类出现功能紊乱。你不能通过简单的在隔离下检查基类的方法来分辨基类的变化是安全的;而是你也必须看(和测试)所有派生类。而且,你必须检查所有的代码,它们也用在基类和派生类对象中,因为这个代码也许被新的行为所打破。一个对于基础类的简单变化可能导致整个程序不可操作。

  让我们一起检查脆弱的基类和基类耦合的问题。下面的类extends了Java的ArrayList类去使它像一个stack来运转:

  class Stack extends ArrayList
  {
  private int stack_pointer = 0;

  public void push( Object article )
  {
  add( stack_pointer++, article );
  }

  public Object pop()
  {
  return remove( --stack_pointer );
  }

  public void push_many( Object[] articles )
  {
  for( int i = 0; i < articles.length; ++i )
   push( articles[i] );
  }
  }

  甚至一个象这样简单的类也有问题。思考当一个用户平衡继承和用ArrayList的clear()方法去弹出堆栈时:

  Stack a_stack = new Stack();
  a_stack.push("1");
  a_stack.push("2");
  a_stack.clear();

  这个代码成功编译,但是因为基类不知道关于stack指针堆栈的情况,这个stack对象当前在一个未定义的状态。下一个对于push()调用把新的项放入索引2的位置。(stack_pointer的当前值),所以stack有效地有三个元素-下边两个是垃圾。(Java的stack类正是有这个问题,不要用它).

  对这个令人讨厌的继承的方法问题的解决办法是为Stack覆盖所有的ArrayList方法,那能够修改数组的状态,所以覆盖正确的操作Stack指针或者抛出一个例外。(removeRange()方法对于抛出一个例外一个好的候选方法)。

  这个方法有两个缺点。第一,如果你覆盖了所有的东西,这个基类应该真正的是一个interface,而不是一个class。如果你不用任何继承方法,在实现继承中就没有这一点。第二,更重要的是,你不能够让一个stack支持所有的ArrayList方法。例如,令人烦恼的removeRange()没有什么作用。唯一实现无用方法的合理的途径是使它抛出一个例外,因为它应该永远不被调用。这个方法有效的把编译错误成为运行错误。不好的方法是,如果方法只是不被定义,编译器会输出一个方法未找到的错误。如果方法存在,但是抛出一个例外,你只有在程序真正的运行时,你才能够发现调用错误。

  对于这个基类问题的一个更好的解决办法是封装数据结构代替用继承。这是新的和改进的Stack的版本:

  class Stack
  {
  private int stack_pointer = 0;
  private ArrayList the_data = new ArrayList();

  public void push( Object article )
  {
  the_data.add( stack_poniter++, article );
  }

  public Object pop()
  {
  return the_data.remove( --stack_pointer );
  }

  public void push_many( Object[] articles )
  {
  for( int i = 0; i < o.length; ++i )
   push( articles[i] );
  }
  }

  到现在为止,一直都不错,但是考虑脆弱的基类问题,我们说你想要在stack创建一个变量, 用它在一段周期内跟踪最大的堆栈尺寸。一个可能的实现也许象下面这样:

  class Monitorable_stack extends Stack
  {
  private int high_water_mark = 0;
  private int current_size;

  public void push( Object article )
  {
  if( ++current_size > high_water_mark )
   high_water_mark = current_size;
   super.push( article );
  }

  publish Object pop()
  {
  --current_size;
  return super.pop();
  }

  public int maximum_size_so_far()
  {
  return high_water_mark;
  }
  }

  这个新类运行的很好,至少是一段时间。不幸的是,这个代码发掘了一个事实,push_many()通过调用push()来运行。首先,这个细节看起来不是一个坏的选择。它简化了代码,并且你能够得到push()的派生类版本,甚至当Monitorable_stack通过Stack的参考来访问的时候,以至于high_water_mark能够正确的更新。

到此,关于“Java中继承多数为什么是有害的”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java中继承多数为什么是有害的

本文链接: https://lsjlt.com/news/232739.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java中继承多数为什么是有害的
    这篇文章主要介绍“Java中继承多数为什么是有害的”,在日常操作中,相信很多人在Java中继承多数为什么是有害的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中继承多数为什么是有害的”的疑惑有所帮助!...
    99+
    2023-06-03
  • Java中继承有什么危害
    这篇文章主要讲解了“Java中继承有什么危害”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中继承有什么危害”吧!  大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends ...
    99+
    2023-06-03
  • 为什么Java不支持多继承
    这篇文章主要介绍“为什么Java不支持多继承”,在日常操作中,相信很多人在为什么Java不支持多继承问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”为什么Java不支持多继承”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-15
  • Java中的接口多继承机制是什么
    这篇文章主要介绍Java中的接口多继承机制是什么,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题原因今天在看集合源码的时候,突然看到接口继承接口,觉得有点差异,以前写代码也就是类继承一个类,实现接口。这样写的多了,...
    99+
    2023-06-29
  • 什么是Java继承
    本篇内容主要讲解“什么是Java继承”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是Java继承”吧!一、继承的概念什么是继承在现实生活中,继承指的是子女继承父辈的财产。在程序中,当一个类A...
    99+
    2023-06-15
  • Java中封装、继承、多态特性是什么
    这篇文章主要为大家展示了“Java中封装、继承、多态特性是什么”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java中封装、继承、多态特性是什么”这篇文章吧。1.封装什么是封装,谈谈自己对封装的...
    99+
    2023-06-22
  • java中继承的含义是什么
    在Java中,继承是一种面向对象编程的机制,允许一个类(子类)基于另一个类(父类)来定义。通过继承,子类可以继承父类的属性和方法,从...
    99+
    2023-10-26
    java
  • java什么是类的继承
    Java 中类的继承是通过扩展其他类而形成新类来实现的,原来的类称为父类(super class)或基类,新类称为原来类的子类或派生类。在子类中,不仅包含父类的属性和方法,还可以增加新的属性和方法,使得父类的基本特征可被所有子类的对象共享。...
    99+
    2014-09-27
    java 继承
  • Python中的继承和多态是什么
    这篇文章主要讲解了“Python中的继承和多态是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python中的继承和多态是什么”吧!一、继承的介绍继承是一种创建新的类的方式,新创建的叫子...
    99+
    2023-06-15
  • Java不支持多继承的原因是什么
    这篇文章主要介绍“Java不支持多继承的原因是什么”,在日常操作中,相信很多人在Java不支持多继承的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java不支持多继承的原因是什么”的疑惑有所帮助!...
    99+
    2023-07-05
  • java继承的概念是什么
    在Java中,继承是一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以使用父类中定义的属性和方法,也可以根据需要...
    99+
    2024-04-02
  • Python中类的多继承原理是什么
    本篇文章给大家分享的是有关Python中类的多继承原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、Python不同版本的类Python2.2之前是没有共同的祖先的,...
    99+
    2023-06-15
  • Java中封装和继承是什么
    这篇文章给大家分享的是有关Java中封装和继承是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一. 封装那封装是什么呢?在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接...
    99+
    2023-06-20
  • CSS中的继承是什么
    这篇文章主要讲解了“CSS中的继承是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS中的继承是什么”吧!CSS的继承是由所使用的样式属性定义的。换句...
    99+
    2024-04-02
  • C++私有继承是什么
    本篇内容介绍了“C++私有继承是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.私有继承通过私有继承,我们可以实现一种has-a的关系...
    99+
    2023-06-29
  • python中多继承的查找顺序是什么
    python中多继承的查找顺序是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python可以做什么Python是一种编程语言,内置了许多有效的工具,Pyt...
    99+
    2023-06-14
  • java类的继承原则是什么
    Java类的继承原则是通过一个类(子类)继承另一个类(父类)的特性和行为。以下是Java类继承的原则:1. 单一继承:Java中的类...
    99+
    2023-10-18
    java
  • java继承的优缺点是什么
    这篇“java继承的优缺点是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java继承的优缺点是什么”文章吧。1、优点提...
    99+
    2023-06-30
  • Java多继承的优点有哪些
    Java不支持多继承,但是可以通过接口实现多继承的一些优点包括:1. 代码重用:通过多个接口可以在一个类中实现不同的功能,避免了代码...
    99+
    2023-09-14
    Java
  • C++ 函数重载在多继承中的影响是什么?
    在多继承中,派生类中的函数重载会导致隐藏或覆盖基类函数,具体取决于签名是否相同。钻石继承结构可能会导致歧义,因为派生类不知道要调用哪个基类函数。可以使用显式作用域解析符、类型转换或虚继承...
    99+
    2024-04-26
    函数重载 多继承 c++ 作用域 编译错误
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作