Java 迟订?字段vs属性。自我与静态

Java 迟订?字段vs属性。自我与静态,java,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

这件事困扰了我很长时间,所以我想我应该继续问下去

如果我写

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
shape
shape
但是如果我写

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
triangle
shape
shape

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

静态字段无法从父类访问。类
Shape
没有“看到”类
Triangle
的静态字段
name
,而是使用自己的静态字段
name

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


UPD2:(来自我的评论):好吧,另一种方式:原谅任何类型的字段
name
。改为使用名为
name()
(非静态!)的方法,该方法将在每个类中返回所需的名称。只需
返回“shape”
返回其中的“三角形”

这是Java如何将名称解析为值的一个很好的例子。您有两个名为
name
的变量,一个在
Shape
中,另一个在
Triangle
中。尽管
Triangle
Shape
的一个子类,但它们是完全不相关的变量。这是因为它们是静态的;静态的东西永远不会覆盖,因为它们属于类,而不是对象。在
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";
        }
    }
}

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

public void printName() throws NoSuchFieldException, IllegalAccessException {
    System.out.println((String)(this.getClass().getDeclaredField("name").get(this)));
}
这只是一个更改,您必须在第二个示例中进行更改,以获得输出

shape
triangle

您可以使用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");
        }
}

所以我必须将“publicstringname(){returnname;}”复制到每个子类中?当然还有更好的方法。每当你引用一个静态字段时,你就静态地绑定到那个具体的字段。静态字段不会被继承覆盖,因此最终会得到两个不同的名称字段(一个在形状中,一个在三角形中)。Shape的name()方法静态绑定到Shape.name字段,而triangle中的name()方法静态绑定到triangle.name字段。无多态性there@beardedlinuxgeek,如果您想保存字段
name
的静态性质,例如可以重写
printName()
方法。但我不认为这是一个更好的方法。对我来说,在这种情况下,我总是为这种静态字段创建一些getter,忽略它是静态属性这一事实。如果您将“静态字符串名”更改为“字符串名”,则会得到相同的结果。请参阅我的第二个答案。这是另一种(但有趣的)方式。