3

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

如果我写

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

4 回答 4

5

父类无法访问静态字段。该类Shape没有“看到”name该类的静态字段Triangle并使用他自己的静态字段name

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

UPD2:(来自我的评论):嗯,另一种方式:原谅任何类型的领域name。改用一个名为name()(不是静态的!)的方法,它将在每个类中返回所需的名称。只是return "shape";return "triangle"在他们之中;

于 2013-01-09T19:35:33.933 回答
1

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

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

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

shape
triangle
于 2013-01-09T20:10:34.567 回答
0

这很好地说明了 Java 如何将名称解析为值。您有两个变量称为name,一个 inShape和一个 in Triangle。即使TriangleShape 这些完全不相关的变量的子类。这是因为它们是静态的。静态事物永远不会覆盖,因为它们属于类,而不是对象。在Shape中,当您提到 时name,这实际上是 的简写Shape.name。同样,在 中Trianglename表示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";
        }
    }
}
于 2013-01-09T20:03:19.297 回答
0

您可以使用 final 字段并将其设置在构造函数中,但恕我直言,最好覆盖 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");
        }
}
于 2013-01-09T20:14:53.323 回答