`
yunhaifeiwu
  • 浏览: 163222 次
  • 性别: 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 子类对象赋值给父类对象的使用

    4. **类型转换**:虽然父类引用可以指向子类对象,但反过来不行,即子类引用不能直接指向父类对象。若要从父类引用转回子类引用,需要进行类型转换(downcasting),如`Dog dog = (Dog) animal;`,但需要注意,只有...

    重写equals方法

    在 Object 基类中,equals 方法的实现是使用“==”操作符来比较对象的引用,但是这并不满足实际需求。因此,需要重写 equals 方法以满足特定的需求。 什么时候需要重写 equals 方法? ------------------------- ...

    方法重写equals和多态

    在Java编程语言中,"方法重写equals"和"多态"是两个核心概念,尤其对于面向对象的设计和实现至关重要。下面将详细解释这两个概念及其相互关系。 **方法重写equals()** 在Java中,`equals()`方法是Object类的一个...

    day004 面向对象3-继承、抽象和方法的重写.doc

    * 私有化成员不能直接通过子类对象直接访问,但是可以通过继承过来的公共方法间接访问 继承、抽象和方法重写是面向对象编程的三大要素,它们可以提高代码的复用性、开发效率和程序的扩展性。但是,需要注意继承的...

    java面试题目之面向对象基础问答题

    - **重写**:发生在子类和父类之间。子类可以重新定义从父类继承的方法,但方法签名(名称、参数列表和返回类型)必须完全相同。这允许子类修改或扩展父类的行为。例如,如果父类有一个名为`display`的方法,子类...

    Java语言深入_equals

    以`FieldPosition`类为例,它的`equals`方法检查了对象类型、`attribute`字段以及`beginIndex`和`endIndex`的值。这段代码看起来是正确的,符合API规范。然而,当我们用自定义的`MyTest`类扩展`FieldPosition`并重写...

    Java面向对象测试题一.doc

    `是错误的,因为不能将父类对象赋值给子类引用。 7. **继承**: - 子类可以继承一个基类,并且可以作为其他类的基类。 - 子类不能通过`this`关键字访问父类的私有属性,`private`访问修饰符限制了这种访问。 - ...

    think in java 第11章 持有对象

    多态性允许我们使用父类引用指向子类对象,这样在运行时可以根据实际对象类型执行相应的操作,增强了代码的灵活性。 7. **构造器链**:在创建对象时,可能会涉及到多个构造器的调用,这就是构造器链。一个构造器...

    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 ...

    面向对象程序设计实验报告.docx

    子类可以继承父类的成员变量和成员方法,并可以添加新的成员变量和成员方法或重写父类的成员方法。在本实验中,我们使用继承机制来实现 Product 类和它的子类 Coffee、CoffeeBrewer、Orderitem。 类图 在本实验中...

    java快速学习笔记(已有基础)

    `super()`用于调用父类的构造器,`this()`用于调用当前类的其他构造器,两者都必须放在构造器的第一行,且不能同时存在。 4. **继承与super关键字**: - Java支持单继承,一个子类只能有一个父类。当子类和父类有...

    java基础篇学习笔记

    向上转型是通过子类对象实例化父类对象,此时会失去子类特有的属性和方法。向下转型则是将父类对象转换为子类对象,需要显式进行。`instanceof`关键字用于检查对象是否是某一类的实例。 Java中的`Object`类是所有类...

    Java面向对象(进阶)- Object类的详细概述

    - `==`和`equals()`的区别在于:`==`比较的是对象的引用,而`equals()`比较的是对象的内容。如果对象是基本类型,`==`和`equals()`的行为相同;如果是引用类型,`==`检查两个引用是否指向同一个对象,而`equals()`...

    Java学习笔记,面向对象深化

    - 构造方法不能被重写,但可以通过`super`关键字在子类构造器中调用父类的构造器。 4. **`Object`类**: - 所有Java类都隐式继承自`Object`类,即使没有明确指定。因此,所有Java对象都有`Object`类提供的方法,...

    Java基础入门教程 含习题 第04章 面向对象(下)(共66页).pptx

    - **对象的类型转换**:可以将子类对象向上转型为父类对象,也可以将父类引用指向子类对象,实现方法的多态调用。 - **Object类**:所有的类都默认继承自`Object`类,它提供了如`equals()`、`toString()`等通用...

    java第05章.面向对象编程-2.pdf

    向上转型是将子类对象赋值给父类引用,而向下转型则是将父类引用赋值给子类对象,这种操作需要使用类型转换操作符。此外,多态还允许使用instanceof关键字来判断一个对象是否为特定类的实例。Java通过简单工厂模式来...

    补上一篇面向对象知识总结的思维导图

    继承是面向对象的另一个关键特性,它允许子类继承父类的数据和方法。在JAVA中,存在单继承(一个子类只有一个父类)和多重继承(一个类可以有多个父类,但JAVA中通过接口实现了类似的功能,因为类只能单继承)。继承...

    (姓名) 面向对象.docx

    多态允许子类对象能够替代父类对象,提高程序的灵活性。 7. **定义类的关键字**:在Java中,使用`class`关键字来定义类。 8. **访问控制权限**:Java提供了四种访问控制权限:private、protected、public和default...

    java对象类余接口的学习

    所有Java类都隐式地继承自`java.lang.Object`类,它提供了所有对象共有的基本方法,如`toString()`、`equals()`和`hashCode()`。 12. **finalize(), clone(), getClass()方法** `finalize()`方法在对象被垃圾...

Global site tag (gtag.js) - Google Analytics