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,忽略它是静态属性这一事实。如果您将“静态字符串名”更改为“字符串名”,则会得到相同的结果。请参阅我的第二个答案。这是另一种(但有趣的)方式。