后期绑定? Field vs Property。自我与静态

时间:2013-01-09 19:33:39

标签: java

这让我困扰了很长时间,所以我想我会继续问问。

如果我写

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

            public void printName()
            {
                    System.out.println( name() );
            }

            public String name()
            {
                    return name;
            }
    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";

            public String name()
            {
                    return name;
            }
    }
}

然后输出

shape
triangle

但如果我写

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

            public void printName()
            {
                    System.out.println( name );
            }

    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";
    }
}

然后输出

shape
shape

在第一个版本中,我必须将相同的函数getName()一遍又一遍地复制/粘贴到每个子类中。必须有一个更好的方法。在第二个例子中我需要改变什么?

4 个答案:

答案 0 :(得分:5)

无法从父类访问静态字段。类Shape不会“看到”类name的静态字段Triangle并使用自己的静态字段name

UPD:您问:第二个例子中您需要更改什么?更具体地说,您的第一个示例是正确“修复”您的第二个示例。唯一正确的方法是使用一些getter方法,例如name()方法。

UPD2:(来自我的评论):嗯,另一种方式:原谅任何类型的字段name。使用名为name()的方法(非静态!),它将在每个类中返回所需的名称。其中只有return "shape";return "triangle";

答案 1 :(得分:1)

好吧,我已经用否定键回答了这个问题。但作为一种笑话和有趣的解决方案(可以工作!!! ),您可以将printName()方法更改为此方法:

public void printName() throws NoSuchFieldException, IllegalAccessException {
    System.out.println((String)(this.getClass().getDeclaredField("name").get(this)));
}

这只是一个更改,您需要在第二个示例中执行此操作才能获得输出

shape
triangle

答案 2 :(得分:0)

这是Java如何将名称解析为值的一个很好的例子。您有两个名为name的变量,一个位于Shape,另一个位于Triangle。即使TriangleShape 的子类,这些也是完全不相关的变量。这是因为它们是静态的;静态事物永远不会覆盖,因为它们属于类,而不是对象。在Shape中,当您引用name时,这是Shape.name的真正简写。同样,在Triangle中,name表示Triangle.name相同符号指的是不同范围中的不同变量

在此代码中:

public class Shape {
    static String name = "shape";

    public static void main(String[] args) {
        System.out.println(name);
    }
}

class Colour {
    static String name = "colour";
}

你不会想到输出会是“颜色”,你呢?这正是您显示的代码中的情况。这两个类之间的继承关系只是一个红色的鲱鱼。

如果您希望名称是多态的,那么您唯一的选择是使用实例方法,因为实例方法是唯一可以是多态的。最简洁的方法是将常量内联到方法中:

class Main {

    public static void main(String[] args) {
        new Shape();
        new Triangle();
    }

    public static class Shape {
        Shape() {
            printName();
        }

        public void printName() {
            System.out.println(name());
        }

        public String name() {
            return "shape";
        }
    }

    public static class Triangle extends Shape {
        @Override
        public String name() {
            return "triangle";
        }
    }
}

答案 3 :(得分:0)

您可以使用最终字段并在构造函数中设置它,但恕我直言,最好覆盖getter。

public static class Shape
{
        protected final String name;

        public Shape()
        {
                this("shape");
        }

        protected Shape(String name)
        {
                this.name = name;
        }

        public void printName()
        {
                System.out.println( name() );
        }

        public String name()
        {
                return name;
        }
}

public static class Triangle extends Shape
{
        public Triangle()
        {
               super("triangle");
        }
}