在Java中,为什么我不能在父类中声明一个final成员(不初始化它)并在子类中设置它的值? 我该如何解决?

发布于 2024-07-15 03:58:32 字数 448 浏览 3 评论 0原文

在 Java 程序中,我有多个从父类(抽象的)继承的子类。 我想表达的是,每个孩子都应该有一个仅设置一次的成员(我计划在构造函数中这样做)。 我的计划是编写代码。 像这样:

public abstract class Parent {
    protected final String birthmark;
}

public class Child extends Parent {
    public Child(String s) {
        this.birthmark = s;
    }
}

然而,这似乎并不能取悦Java诸神。 在父类中,我收到消息:birthmark“可能尚未初始化”,在子类中,我收到“无法访问最终字段birthmark”。

那么 Java 的方式是什么呢? 我缺少什么?

In a Java program, I have multiple subclasses inheriting from a parent (which is abstract). I wanted to express that every child should have a member that is set once only (which I was planning to do from the constructor). My plan was to code s.th. like this:

public abstract class Parent {
    protected final String birthmark;
}

public class Child extends Parent {
    public Child(String s) {
        this.birthmark = s;
    }
}

However, this seems to not please the Java gods. In the parent class, I get the message that birthmark "might not have been initialized", in the child class I get "The final field birthmark cannot be accessed".

So what's the Java way for this? What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

懒的傷心 2024-07-22 03:58:32

你不能这样做,因为在比较父类时,编译器无法确定子类是否会初始化它。 您必须在父级的构造函数中初始化它,并让子级调用父级的构造函数:

public abstract class Parent {
    protected final String birthmark;
    protected Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
        ...
    }
}

You can't do it because while comparing the parent class, the compiler can't be sure that the subclass will initialize it. You'll have to initialize it in the parent's constructor, and have the child call the parent's constructor:

public abstract class Parent {
    protected final String birthmark;
    protected Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
        ...
    }
}
葬﹪忆之殇 2024-07-22 03:58:32

将其传递给父构造函数:

public abstract class Parent {
    private final String birthmark;
    public Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
    }
}

Pass it to the parent constructor:

public abstract class Parent {
    private final String birthmark;
    public Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
    }
}
最丧也最甜 2024-07-22 03:58:32

另一种 Java 风格的方法可能是让父类定义一个抽象的“getter”,并让子类实现它。 在这种情况下,这不是一个好方法,但在某些情况下,它可能正是您想要的。

Another Java-ish way to do this is probably to have the parent class to define an abstract "getter", and have the children implement it. It's not a great way to do it in this case, but it in some cases it can be exactly what you want.

夜雨飘雪 2024-07-22 03:58:32

我会这样做:

public abstract class Parent 
{
    protected final String birthmark;

    protected Parent(final String mark)
    {
        // only if this makes sense.
        if(mark == null)
        {
            throw new IllegalArgumentException("mark cannot be null");
        }

        birthmark = mark;
    }
}

public class Child 
    extends Parent 
{
    public Child(final String s) 
    {
        super(s);
    }
}

final 意味着每个实例可以初始化该变量一次。 编译器无法确保每个子类都会提供对birthmark的赋值,因此它强制赋值在父类的构造函数中发生。

我添加了对 null 的检查,只是为了表明您还可以获得能够在一个位置而不是每个构造函数检查参数的好处。

I would do it like this:

public abstract class Parent 
{
    protected final String birthmark;

    protected Parent(final String mark)
    {
        // only if this makes sense.
        if(mark == null)
        {
            throw new IllegalArgumentException("mark cannot be null");
        }

        birthmark = mark;
    }
}

public class Child 
    extends Parent 
{
    public Child(final String s) 
    {
        super(s);
    }
}

final means that the variable can be initialized once per instance. The compiler isn't able to make sure that every subclass will provide the assignment to birthmark so it forces the assignment to happen in the constructor of the parent class.

I added the checking for null just to show that you also get the benefit of being able to check the arguments in one place rather than each cosntructor.

記柔刀 2024-07-22 03:58:32

为什么不将初始化委托给方法。 然后重写父类中的方法。

public class Parent {
   public final Object x = getValueOfX();
   public Object getValueOfX() {
      return y;
   }
}
public class Child {
  @Override
  public Object getValueOfX() {
     // whatever ...
  }
}

这应该允许自定义初始化。

Why not delegate initialization to a method. Then override the method in the parent class.

public class Parent {
   public final Object x = getValueOfX();
   public Object getValueOfX() {
      return y;
   }
}
public class Child {
  @Override
  public Object getValueOfX() {
     // whatever ...
  }
}

This should allow custom initialization.

花开柳相依 2024-07-22 03:58:32

是的,最终成员将被分配到声明它们的类中。 您需要向 Parent 添加一个带有 String 参数的构造函数。

Yes, the final members are to be assigned in the class in which they are declared. You need to add a constructor with a String argument to Parent.

倾城月光淡如水﹏ 2024-07-22 03:58:32

在超类中声明由子类调用的构造函数。
您必须在超类中设置该字段以确保其已初始化,否则编译器无法确保该字段已初始化。

Declare a constructor in the superclass that's called by the subclass.
You must set the field in the superclass to make sure it's initialized, or the compiler can't be sure the field is initialized.

小嗲 2024-07-22 03:58:32

您可能希望有一个 Parent(Stringbirthmark) 构造函数,以便确保在 Parent 类中 Final 始终被初始化。 然后你可以从 Child() 构造函数中调用 super(birthmark) 。

You probably want to have a Parent(String birthmark) constructor so that you can ensure in your Parent class that final is always initialized. Then you can call super(birthmark) from your Child() constructor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文