简体   繁体   English

Java,除了其中一个之外,如何停止继承类调用特定的抽象类构造函数?

[英]Java, how to stop inheriting classes from calling a particular abstract class constructor, apart from one of them?

I have an abstract class and several concrete classes which extend it. 我有一个抽象类和几个扩展它的具体类。

The abstract class has two constructors. 抽象类有两个构造函数。 I want one of the constructors to only be callable in one particular concrete class. 我希望其中一个构造函数只能在一个特定的具体类中调用。

(I do know about the enum pattern for Java state machines, but two levels of subclassing (and immutable POJOs) work better for the problem I'm solving.) (我确实知道Java状态机的enum模式,但是两级子类化(和不可变的POJO)对于我正在解决的问题更有效。)

public abstract class SuperState {
    public final long mValue;
    protected SuperState(long value) { mValue = value; }
    protected SuperState(SuperState last) { mValue = last.mValue + 1; } 
    ...
}

public class FirstState extends SuperState {
    public FirstState() { super(0); }
    ...
}

public class SecondState extends SuperState {
    public SecondState(SuperState last) { super(last); }
    ...
}

public class ThirdState extends SuperState {
    public ThirdState(SuperState last) { super(last); }
    ...
}

I want to make it a compile-time (or at least runtime) error for any subclass (apart from FirstState ) to call the SuperState(long value) constructor. 我想让它成为任何子类(除了FirstState之外)的编译时(或至少运行时)错误,以调用SuperState(long value)构造函数。

Could I find out the type of the concrete class being constructed in the SuperState constructor, and throw a runtime exception if it's not as expected? 我可以找出在SuperState构造函数中构造的具体类的类型,如果它不符合预期,则抛出运行时异常吗?

Is there a was of having a "preferred" concrete class for an abstract class, such that it has some form of extra access? 是否有一个抽象类的“首选”具体类,以便它具有某种形式的额外访问?

I think you don't know clearly what you're doing. 我想你不清楚你在做什么。 You're saying that SuperState has a constructor which is only callable from one specific implementation. 你说SuperState有一个只能从一个特定实现调用的构造函数。 Why? 为什么? Is that subclass special? 那个子类特别吗? Why shouldn't other implementation call that? 为什么其他实现不应该这样称呼?

If FirstState is so special, maybe you want to have it as an internal class: 如果FirstState如此特别,也许您希望将其作为内部类:

public abstract class SuperState {
  public final long mValue;
  private SuperState(long value) { mValue = value; }
  protected SuperState(SuperState last) { mValue = last.mValue + 1; } 
  ...
  public static class FirstState {
    //Can call SuperState(long) from here
  }
}

If this doesn't seem appropriate to you, then probably you should leave both constructors open. 如果这对您来说不合适,那么您可能应该打开两个构造函数。 If, as it seems to me, you're making a chain-like structure, then you probably don't even want to have FirstState as an accessible class: 如果在我看来,你正在制作一个类似链的结构,那么你可能甚至不希望将FirstState作为可访问的类:

public abstract class SuperState {
  public final long mValue;
  private SuperState(long value) { mValue = value; }
  protected SuperState(SuperState last) { mValue = last.mValue + 1; } 
  ...
  private static class FirstState extends SuperState {
    private FirstState() { super(0); }
  }
  public static SuperState getFirstState() { return new FirstState(); }
}

One way I can think of, though I find it ugly : 我能想到的一种方式,虽然我发现它很难看:

protected SuperState(long value) 
{
    if (!this.getClass().getName().equals("SomeConcreteClassName"))
        throw new SomeException ();
    mValue = value; 
}

Though Tom's comment about putting the FirstState class in the same package as SuperState and using package private access sounds better. 虽然Tom关于将FirstState类放在与SuperState相同的包中并使用包私有访问的评论听起来更好。

I think the only way to achieve it is to use analog of "friend". 我认为实现它的唯一方法是使用“朋友”的模拟。 The trick is to have private Value class in the FirstState which is possible to construct only by FirstState . 诀窍是在FirstState拥有私有Value类,只能由FirstState Other classes can see the FirstState.Value class, but cannot instantiate it. 其他类可以看到FirstState.Value类,但无法实例化它。

abstract class SuperState {
    public final long mValue;
    protected SuperState(FirstState.Value value) { mValue = value.value; }
    protected SuperState(SuperState last) { mValue = last.mValue + 1; } 
}

class FirstState extends SuperState {
    public static class Value { private Value() {} }
    private static Value value = new Value();

    public FirstState() { super(value); }
}

class SecondState extends SuperState {
    public SecondState(SuperState last) { super(last); }
}

You can do it with default access modifier like this: 您可以使用默认访问修饰符来执行此操作:

package a;

public abstract class SuperState {
    public final long mValue;
    SuperState(long value) { mValue = value; } // constructor has default access modifier
    protected SuperState(SuperState last) { mValue = last.mValue + 1; } 
    ...
}



package a;

public class FirstState extends SuperState {
    public FirstState() { super(0); }
    ...
}



package b;
// is not able to access constructor SuperState(long) ie. calling contructor
// SuperState(long) will result in compile time error
public class SecondState extends SuperState {
    public SecondState(SuperState last) { super(last); }
    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM