覆盖属性

时间:2011-07-14 11:20:05

标签: java inheritance attributes override

覆盖方法时,必须保留方法的签名,但不能降低其可见性。现在我尝试使用属性执行此操作时发生的事情。我很惊讶 - 它的工作原理!看看你自己:

public class A {

    public Integer myAttribute;

}

public class B extends A {

    public String myAttribute;

}

public class Main {

        public static void main(String[] args) {
        B b = new B();
        b.myAttribute = "myString";
        ((A) b).myAttribute = 1337;
        System.out.println(b.myAttribute);
        System.out.println(((A)b).myAttribute);
    }

}

因此可以在子类中编写具有与超类中相同的属性名称的属性,但您可以使用不同的可见性(修饰符)和类型。所以我要说超类和子类中的属性几乎完全相互独立。

现在,如果您真的在超类和子类中使用相同的属性名称,则可以有效地隐藏超类的属性。使用子类访问属性时,您将获得子类的属性。但超类的属性也在那里!您必须执行强制转换才能从外部访问超类的属性。从“super”关键字里面应该是有用的。

问题1: 现在基本上你有两个具有相同名称的不同属性。这不会中断LSP吗?

为什么我来这个细节是这样的: 我正在尝试自编写的持久性框架。我想读取对象的完整内部状态并保持该状态。我通过reflexion读取所有属性的值,从子类型开始并遍历超类。 现在,如果在超类和子类中有两个具有相同名称的属性,我必须记住声明属性的类,以便能够将属性值映射到正确的属性并恢复对象的状态。

问题2: 任何其他想法如何处理这个细节? 问题3: 其他持久性框架如何处理这个细节?

我从未在使用中看到过这个细节。也许编写两个具有相同名称的属性有点难看,但它是可能的,任何持久性框架都可能面临它。也许有些情况下这种技术可能会有用。

提前吃完。

5 个答案:

答案 0 :(得分:5)

ORM通常使用定义“属性”的javabeans标准。属性由读取器和/或写入器方法定义,而不是它们读/写的字段。在99%的情况下,属性是字段+ getter& setter,但不一定是这种情况。 ORM读取这些属性,并仅检测具有getter和ampter的字段。由于方法被覆盖而不是被遮蔽,因此问题就消失了。

这是一个封装问题,而不是违反LSP。字段访问不受多态性的影响,因此如果您有Foo foo = new FooSubclas(); foo.field the value of the Foo`字段将被采用,这意味着行为不会改变。

答案 1 :(得分:2)

问题1:它不会破坏LSP,因为成员变量不是多态的。

答案 2 :(得分:2)

您无法覆盖属性,只能隐藏它。这在tutorial中被称为隐藏字段。有关此blog的详细信息。

Q1:不,它不会破坏LSP,对A a = new B(); a.myAttribute的任何引用仍将引用A.myAttribute而不引用B.myAttribute

Q2:我会尽量避免,但如果必须,您仍然可以使用A.myAttribute关键字从B访问super.myAttribute

问题3:我认为C#允许相同,他们使用base而不是super,但我手头没有C#编译器,而且隐藏在C#中的字段文档很稀疏。

答案 3 :(得分:1)

问题1:LSP约为behavioral subtyping,我想说有两个同名的成员本身不会改变行为。

问题2:检测它(你需要扫描类层次结构)并且不允许它。

答案 4 :(得分:1)

问题2:仅通过getter / setter序列化/反序列化。

问题3:见答案2.