`
yunhaifeiwu
  • 浏览: 161390 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
社区版块
存档分类
最新评论

父类对象和子类对象之间究竟能否equals

    博客分类:
  • java
 
阅读更多
http://www.iteye.com/topic/1119409?page=4

   楼主的问题,让我现在思维都还不能停止。现整理了一番,同时也是对自已一次认知的梳理。

   楼主的问题是:父类对象和子类对象之间究竟能否equals。并举了一个例子:
引用

   一个Employee员工类,一个Manager类,是员工类的子类。

   经理肯定是员工,员工未必一定是经理。 如存在某经理,那么他可能有一个Employee类对象,也可能有一个Manager类对象,如果这两个对象调用equals方法,是否应返回true

   假定上述答案是肯定的,那么我们在重写equals方法的时候就不可以再用instance of判定了。因为会违反自反性。(A equals B 则必有B equals A)。

   从面向对象的设计的角度说,这个问题应该怎么看?

   是不同类的对象之间equals永远返回false,还是不应该在equals方法中先用instance of来做下判定?


   首先从JAVA语言来说,equals是允许程序员自行修改的。

   从软件设计角度来说,又怎么样呢?不同的人对软件设计的理解、方法掌握不同,答案又是不一样的。

   如果从我的软件设件理解来说 ,不同类的对象之间的equals是永远为false.

   如果在我负责的项目中,一经发现两个不同类的对象之间需要修改equals时,我会在我的需求设计阶段之需求建模时进行检查,我的需求模型倒底是哪里出现严重的错误

   因为在我的软件设计世界里,软件是对现实世界部份的模拟。
  
   这种理念的优点是:当在软件设计时,遇到困难,可以从要模仿的现实世界去观察、去分析、去建模,从而解决软件设计中的困难。

    在这个理念下,我的程序下,一个实例,就像现实世界中一个鲜活的生命,独一无二的,他一经死亡(即实例注销)就无法复活。 但是我是允许他冬眠的,即让一个实例保存到文件中或数据库里,他一旦从冬眠中结束,恢复到程序世界里,这个过程像冬眠的动物从睡眠中回到真实世界里。愎复到程序世界的过程,在程序表现就是一次从文件中加载并实例化的过程,由于动物从冬眠恢复后,他的生命还是原来的生命,他还是独一无二的,因此从数据中恢复一个实例,该实例还是必须独一无二的,不允许多次加载形成不同的实例。
 
    所以在我的软件设计里,一旦发现需要修改equals时,我会从需求建模的模型中去查找我的严重、致命错误。

   拿楼主举例来说,当一个人是经理时,他肯定是员工。在楼主眼中,这个人,有两个化身--------经理实例与---------员工实例, 从而需要修改equals。但是在我的眼中,一个人,永远是一个人,是一个独一无二,不可复制的人,这个人不会因为身份的变化,他就变成两个人,不会因为是经理他是一个人,当成董事长时,他又是另一个人。

   那么建模时,我应该如何解决"一个人的多重身份问题"呢?首先从功能上要区分开几个概念,人 、经理、员工。经理与员工是身份,他不是生命,人才是真正的生命。身份是人的一个属性,可以允许有多种,即经理 、员工及其他。如果这几个概念理清了,那么我的模型就是:
  
   public class person{//代表一个生命
      private List<Standing> standings;//身份
   }
   public class Standing{//身份}
   public class Manager extends Standing {//经理} 
   public class Employee extends Standing {//员工}
   

   如果在项目中,身份最低就是员工,最多是经理,没有其他时,可以化减模型
  
   public class Employee{//员工; 
      private  Manager manager;//身份,不为null表示经理,否则是普通员工
   }
   public class Manager{}



   如果有人要问,在程序设计中,一定会出现类继承现象,假定某个模型就是

 
public class Manager extends Employee {//经理继承员工}


   如果由于需要,需要把Manager 与 Employee 保存到数据库中,并恢复过来。由于员工、经理的不同,他们的的都需要加载。

   即 会出现某个出书大师-----redhat 提示要出现的调用问题:
  
引用

   m=managerDao.loadFromDb(1);
   e=employeeDao.loadFromDb(1);


    什么意思呢?就是不同的类(Manager 与EmployeeDao 即经理与员工类),在加载同一个员工编号时,所得到的两个类实例,不是不一样吗?不是需要判断这两个是等同的吗?

    在我的软件世界中,首先,不管是用父类加载,还是用子类加载,在程序中只装加载一次。也就是说,一个生命从冬眠中醒过来,不允许变成两个生命。

    由于方便 其他地方编程的需要,我也同时允许父类与子类加载数据形成实例。但是,对于一个员工,如果他是一个经理,在通过员工类加载数据时,绝对不允许让他不能变成经理,或者说不能让他丢失经理身份。

    那么在模型中,如何设计呢?

    具体怎么设计呢?
   
    public class Employee{//员工; 
        private  Manager manager;//身份,不为null表示经理,否则是普通员工
        public Employee load(xxxx){//从数库中加载,并形成一个实例。
           //算法描述为: 先在经理表中,查询该员工是否是经理,如果是经//理,按经理类的加载方法加载,并返回一个Manager对象;如果
//不是经理,按普通员式方法加载,并返回一个Employee对象。
        }
     }

    public class Manager extends Employee{//经理
         public Manager load(xxxx){//从数库中加载,并形成一个实例
     }


     所以,在我的软件设计世界中,不同类的对象之间equals永远是false.

     我把我的理解整理出能,希望能给某些朋友以启迪

     最后,我已经把上面这一段,存放到我的blog里,望楼主不要介怀。


    //==========================本想结束,有朋友继续问,只好继续一下=========

    
kidneyball 写道
楼上的朋友,你的设计在父类里硬编码了子类,没法扩展呀。如果我又想从Employee里继承出来一个TempEmployee(临时工),那不是又要往Employee里加一个TempEmployee的对象域?

另外,“如果在项目中,身份最低就是员工,最多是经理,没有其他时,可以化减模型”这句话谁也不敢写包单的,还是遵循开闭原则比较稳妥。


  朋友说得很到位。 
 
   关于硬编码 ,就要看怎么编码了,编得好就能扩展,编得不好,就扩展不了。 本来第一感觉是用策略模式,把不同的加载方法进行封装。但时,在使用中是非常不方便的,当需要用父类加载所有子类的实例时,通常不知道子类的类型,所以取消策略模式的念头。

  那么上面的方法就真的不能扩展子类了吗? 答案是否定的。关键在于,保存上的数据格式设计问题。 在数据库中,有一表专门存储各种子类的检索表,当某个子类保存到数据库时,他保存的地方,就必须要在检索表中注册,并严格按照检索表的约定去存放。 这样父类加载时,先查遍检表的信息,以确定子类身份,并按相应方式加载。

  这种方法效率有点低,特别是当子类众多时。  但是,不管怎么说,至少有一种方法能实现子类扩展问题。再有的继承上,去优化,去思考效率更高的方法。

  另外,当这种情况----即子类特别众多,我会怎么办?

  在我的软件设计世界中,我又会马上去检查我的需求模型设计,这里又出了致命的重大问题。
 
  因为,在我的软件设计世界中,这种类继承关系,不是用来表示软件的被操作部份-----即数据部份;而是用来表示操作者--即程序本身。 道理非常的简单,现在的大多数面向对象的编辑语言,一旦类写好,类继承关系确定好,在程序运行里,是非常难改变继承关系的,也很难改把运行实例的类,改成另一个全新运行的类。 如果用类继承关系去描述那些被操纵的数据部份,这些对象的继承关系一旦发生变化,整个项目再难继续进行。

  那么,当程序要操作的 对象的类,本身有众多的继承关系怎么办?

  在我的软件设计世界中,我会把这些关系,用数据结构去描绘,去建模,而不会用类继承关系建模。类继承关系建模,永远给软件的控制系统部份。请对数据结构重视不够,或理解不够深的朋友,请不要轻易让其他同行放弃数据结构的学习与领悟 当然了,这是从我的理解角度 说出的建议了。
 
  故当有众多子类需要保存到数据库中,我会检查我的需求建模。

   对于第二个问题
引用
另外,“如果在项目中,身份最低就是员工,最多是经理,没有其他时,可以化减模型”这句话谁也不敢写包单的,还是遵循开闭原则比较稳妥。


   首先你的这个提法,不错,我赞同。
   但是,如果项目价值不大,花的成本很小,需求变化特小,按适合就是最好的原则,按简化的做,没问题。
分享到:
评论

相关推荐

    JAVA面向对象详细资料

    31.6 静态方法是不能被继承 46 31.7 如何区分静态方法和实例方法的应用 46 31.8 静态导入(1.5新特性) 46 32 单例模式 47 32.1 饿汉模式 47 32.2 懒汉模式 47 33 接口(interface) 48 33.1 如何创建一个接口。 48 ...

    【05-面向对象(下)】

    •局部内部类不能在外部类以外的地方使用,那么局部内部类也不能使用访问控制符和static修饰 匿名内部类 •匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下: •new 父类构造器...

    编程技能训练与等级考试辅导:继承、super关键字.pptx

    父类和子类 使用super关键字 方法重写与重载 Object类和toString()方法 多态、动态绑定 对象转换和instanceof操作符 Object类的equals()方法 ArrayList类 关于列表的一些有用的方法 自定义栈类 Protected数据和方法 ...

    java基础课程重点笔记.rar

    重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊...

    超级有影响力霸气的Java面试题大全文档

    重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,...

    Java的面向对象编程

    1、 成下面父类及子类的声明:(1)声明Student类。属性包括学号、姓名、英语成绩、数学成绩、计算机成绩和总成绩。方法包括构造方法、get方法、set方法、toString方法、equals方法、compare方法(比较两个学生的总...

    JAVA面试题最全集

    修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被...

    java面试八股文总结.pdf

    答案:多态是面向对象编程中的一个重要概念,它允许不同的子类对象对同一消息做出不同的响应。在Java中,多态可以通过继承和重写(覆盖)实现。当子类重写父类的方法时,调用该方法时将根据实际对象的类型来确定调用...

    银行账户管理系统 简称BAM(项目介绍及源码)绝对精典

    LoanException:贷款额不能为负数,如果用户试图将贷款额置为负数,则会抛出这个异常 以上四个异常类有一个共同的父类 BusinessException 并妥善的处理这些异常 项目五 练习8:(集合) 改写Bank类,采用集合的方式来...

    net学习笔记及其他代码应用

    接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它...

    java面试宝典2012版.pdf

    70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 71、说出一些常用的类,包,接口,请各举5个 72、java中有几种...

    java开发大猫聊天室源码-AndroidInterview-Questions:Android面试-问题

    不,您不能创建抽象类的实例,因为它没有完整的实现。 抽象类的目的是作为子类的基础。 它就像一个模板,或者一个空的或部分空的结构,你应该在使用它之前对其进行扩展和构建。 Java 中 == 和 .equals() 方法的区别 ...

    疯狂JAVA讲义

    学生提问:能不能只分配内存空间,不赋初始值呢?89 4.5.4 使用数组 90 学生提问:为什么要我记住这些异常信息? 91 4.5.5 JDK1.5提供了foreach循环 91 4.6 深入数组 93 4.6.1 内存中的数组 93 学生提问:为...

    java 面试题 总结

    重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,...

    基于javatcpsocket通信的拆包和装包源码-someData:存放一些思维导图,图片,ppt等等

    如何在父类中为子类自动完成所有的hashcode和equals?优劣点在哪里,两者只实现其中一个会有什么影响 反射的原理,反射创建类实例的三种方式是什么。 反射中,Class.forName和ClassLoader区别 动态代理的几种实现...

    Java复习题及答案

    答:final是最终的意思,final可用于定义变量、方法和类但含义不同,声明为final的类不能被继承。 2、父类的构造方法是否可以被子类覆盖(重写)? 答:父类的构造方法不可以被子类覆盖,因为父类和子类的类名是不...

    java经典面试2010集锦100题(不看你后悔)

    B) 在Java中布尔类型不能和数字之间不能来回转换,即false和true不对应任何零或非零的值。 C) 双精度类型double比单精度类型float具有更高的精度和更大的表示范围,但float类型具有速度快、占用内存小的优点。 D) 在...

    最新Java面试宝典pdf版

    70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...

    java初学者必看

    8.1 父类和子类 8.2 super构造方法调用 8.3 封装和继承 8.4 使用继承 8.4.1 Object类 8.4.2 定义equals方法 8.5 关于设计好继承的几点建议 8.6 实例:一卡通类的继承 8.6.1 构造方法 8.6.2 setter方法 ...

Global site tag (gtag.js) - Google Analytics