限制构造函数只能使用同级构造函数 - Java

发布于 2024-10-22 05:22:25 字数 908 浏览 2 评论 0原文

这可能是不可能的,但我正在尝试创建一个只有共享超类的类才能访问的构造函数,这几乎是 protected 修饰符的逆逻辑。我假设没有修改器可以直接完成此任务,但是知道我想要完成什么,有什么建议吗?

public Account extends SomeEntity {

    //default public
    public Account() {

    }

    // I am wanting this constructor to be only available to sibling classes.
    // (those that share the same super class )
    <modifier> Account(Element accountElement) {

    }
}


public Accounts extends SomeEntity {

    private List<Account> accountList;

    //default public
    public Accounts() {

        Account newAcct = new Account(element);

        //looped loading up Generic list of Account
        this.accountList.add(newAcct);
    }

我正在使用 RESTful Web 服务并从 XML 响应构建对象,问题是如果我 GET 帐户列表,要将其构建到帐户对象列表中,我将不得不查询网络尽管我已经掌握了信息,但仍为每个个人帐户提供服务,这似乎效率很低。

但是

我不想让我正在构建的 API 的普通用户能够以这种方式实例化帐户对象。 (使用元素

This might not be possible but I am trying to create a constructor that only classes that share a super class can access, almost a reverse logic of the protected modifier. I assume there is no modifier to accomplish this directly, but knowing what I am trying to accomplish, any suggestions?

public Account extends SomeEntity {

    //default public
    public Account() {

    }

    // I am wanting this constructor to be only available to sibling classes.
    // (those that share the same super class )
    <modifier> Account(Element accountElement) {

    }
}


public Accounts extends SomeEntity {

    private List<Account> accountList;

    //default public
    public Accounts() {

        Account newAcct = new Account(element);

        //looped loading up Generic list of Account
        this.accountList.add(newAcct);
    }

I am working with RESTful web services and building the Objects out of XML responses, the problem is if I GET a listing of accounts, to build that into a list of Account Objects I would have to query the web service for each individual account even though I already have the information, and that seems entirely inefficient.

BUT

I don't want to give a general user, of the API I'm building, to be able to instantiate an Account Object this way. (With an Element)

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

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

发布评论

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

评论(7

审判长 2024-10-29 05:22:25

不存在这样的语言结构。从 1.6 开始,包(=默认)访问是唯一的 Java 机制。

我确信你可以用堆栈做一些令人讨厌的事情,但我不会推荐它们。

There is no language construct like this. Package (=default) access is the only Java mechanism in town, as of 1.6.

I'm sure you could do nasty things with the stack, but I wouldn't recommend them.

被翻牌 2024-10-29 05:22:25

我会看一下工厂模式。您可能可以使用工厂方法的访问修饰符来玩游戏,以获得接近您想要的东西。您还可以在工厂方法内使用反射来获得比包访问更接近您想要的东西。

I'd take a look at the factory pattern. You can probably play games with the access modifiers of the factory method(s) to get something close to what you want. You might also be able to play with reflection inside the factory method to get something closer to what you want than what package access gets you.

绝影如岚 2024-10-29 05:22:25

抱歉,我还是不明白这个设计的意义。如果将方法添加到类中,则其实现可能仅使用该类的私有数据,因此不能向“兄弟”类保证该数据也可供它们使用。换句话说,如果您的愿望得到满足,您如何保证构造函数 Account(Object arg0) 实现不会使用 Account 类的私有数据? (因此对 Accounts 类不可见)

在我看来,您希望您的代码为单个帐户和帐户列表提供相同的接口 - 扩展 SomeEntity 类。通过复合模式可以更优雅地实现这一点。

http://en.wikipedia.org/wiki/Composite_pattern

如果您的目的是提供只有子类才会使用的自定义构造函数,为什么不在 SomeEntity 中声明自定义构造函数并使此类抽象?

另外,请记住您可以这样做:

public Account() {
  this(new arg0());
}

Account(Object arg0) {

}

不过不确定这是否有帮助。

Sorry but I still don't get the point of this design. If a method is added to a class, its implementation will probably use private data to this class only, and therefore no guarantee can be made to 'sibling' classes that this data is also available for them. In other words, if your wish was granted, how would you guarantee that constructor Account(Object arg0) implementation won't use private data to Account class? (and therefore invisible to Accounts class)

It seems to me like you desire your code to provide the same interface for a single account and a list of accounts - extending SomeEntity class. That can be accomplished more elegantly with a composite pattern.

http://en.wikipedia.org/wiki/Composite_pattern

if your intent however is to provide a custom constructor that only subclasses will use, why not declare the custom constructor in SomeEntity and making this class abstract?

also, remember you can do this:

public Account() {
  this(new arg0());
}

Account(Object arg0) {

}

Not sure if this helps, though.

我喜欢麦丽素 2024-10-29 05:22:25

有一种方法可以模拟 C++ 的 friend 功能,从而达到您想要的结果。

警告:这是一种人为的技术,只有在没有其他解决方案时才应使用!

由于在这种情况下没有修饰符可以实现您想要的功能,因此技巧是将访问限制移至另一个位置,其中修饰符适用。为此,请向构造函数添加一个key 参数。该键属于只能由允许的“兄弟”类(即给定类的子类)实例化的类。

因此,限制被转移到公共超类,其中可以使用通常的修饰符来限制键的创建。

这是一个例子:

public class CommonSuperClass {
    public static final class Key {
        private Key() {}
    }

    // This is the only way to create a key, and it's protected
    protected final Key createKey() {
        return new Key();
    }
}

public class Account {
    // The restricted constructor can even be public
    public Account(Key key) {
        // Everybody can try with null, but we're not that stupid
        // Of course any RuntimeException can be thrown instead
        if (key == null) throw new UnsupportedOperationException();
    }
}

public class AllowedSibling extends CommonSuperClass {
    public void foo() {
        // I'm allowed
        new Account(this.createKey());
    }
}

public class DeniedClass {
    public void foo() {
        // This doesn't compile
        new Account(new Key());

        // This will throw an exception
        new Account(null);
    }
}

There is a way to emulate the C++'s friend feature, and thus achieve the result you want.

Warning: This is a contrived technique that should be used only if you have no other solution!

Since no modifier does what you want in this case, the trick is to move the access restriction to another place, where modifiers apply. To do that, add a key parameter to the constructor. That key is of a class that can only be instantiated by the allowed "sibling" classes, i.e. by the subclasses of a given class.

The restriction is thus moved to the common superclass, where restraining the creation of the key is possible with the usual modifiers.

Here is an example:

public class CommonSuperClass {
    public static final class Key {
        private Key() {}
    }

    // This is the only way to create a key, and it's protected
    protected final Key createKey() {
        return new Key();
    }
}

public class Account {
    // The restricted constructor can even be public
    public Account(Key key) {
        // Everybody can try with null, but we're not that stupid
        // Of course any RuntimeException can be thrown instead
        if (key == null) throw new UnsupportedOperationException();
    }
}

public class AllowedSibling extends CommonSuperClass {
    public void foo() {
        // I'm allowed
        new Account(this.createKey());
    }
}

public class DeniedClass {
    public void foo() {
        // This doesn't compile
        new Account(new Key());

        // This will throw an exception
        new Account(null);
    }
}
瀟灑尐姊 2024-10-29 05:22:25

这是一个非常奇怪的要求,我认为没有访问修饰符可以做你想做的事。无论如何,我建议您将构造函数公开并将其记录为“仅供内部使用”。

如果您确实需要限制访问,您可以使用这个冗长的解决方案:

public class Base {
    protected interface Factory {
        Base getInstance(Element e);
    }

    private static Map<Class<?>, Factory> registry = new HashMap<Class<?>, Factory>();
    protected static void register(Class<?> c, Factory f) { registry.put(c, f); }
    protected static <T extends Base> T create(Class<T> c, Element e) {
        return (T) registry.get(c).getInstance(e);
    }
}

public class Derived1 extends Base {
    protected Derived1(Element e) { }
    private static class Derived1Factory implements Factory {
        public Derived1 getInstance(Element e) {
            return new Derived1(e);
        }
    }

    static {
        register(Derived1.class, new Derived1Factory());
    }
}

public class Derived2 extends Base {
    protected Derived2(Element e) { }
    private static class Derived2Factory implements Factory {
        public Derived2 getInstance(Element e) {
            return new Derived2(e);
        }
    }

    static {
        register(Derived2.class, new Derived2Factory());
    }

    public void method() {
        Element e = null;
        ...
        // Put some element in e
        ...
        // This is what you were trying to do
        Derived1 d1 = create(Derived1.class, e);
    }
}

This is a very strange requisite, and I think no access modifier can do what you want. Anyway, I recommend that you just make the constructors public and document them as "for internal use only".

If you really need to limit access you can use this wordy solution:

public class Base {
    protected interface Factory {
        Base getInstance(Element e);
    }

    private static Map<Class<?>, Factory> registry = new HashMap<Class<?>, Factory>();
    protected static void register(Class<?> c, Factory f) { registry.put(c, f); }
    protected static <T extends Base> T create(Class<T> c, Element e) {
        return (T) registry.get(c).getInstance(e);
    }
}

public class Derived1 extends Base {
    protected Derived1(Element e) { }
    private static class Derived1Factory implements Factory {
        public Derived1 getInstance(Element e) {
            return new Derived1(e);
        }
    }

    static {
        register(Derived1.class, new Derived1Factory());
    }
}

public class Derived2 extends Base {
    protected Derived2(Element e) { }
    private static class Derived2Factory implements Factory {
        public Derived2 getInstance(Element e) {
            return new Derived2(e);
        }
    }

    static {
        register(Derived2.class, new Derived2Factory());
    }

    public void method() {
        Element e = null;
        ...
        // Put some element in e
        ...
        // This is what you were trying to do
        Derived1 d1 = create(Derived1.class, e);
    }
}
抚笙 2024-10-29 05:22:25
public class SomeEntity
    protected void init(Element accountElement) {}

public class Account extends SomeEntity 

    public Account() 
        ....

    protected void init(Element accountElement)
        ....


public class Accounts extends SomeEntity

    Account newAcct = new Account();
    newAcct.init(element);
public class SomeEntity
    protected void init(Element accountElement) {}

public class Account extends SomeEntity 

    public Account() 
        ....

    protected void init(Element accountElement)
        ....


public class Accounts extends SomeEntity

    Account newAcct = new Account();
    newAcct.init(element);
夜吻♂芭芘 2024-10-29 05:22:25

这是我会尝试的(我没有测试过这个方法):

<modifier> Account(Object arg) {
    if (!super.getClass().isAssignableFrom(this.getClass())) {
        throw new AssertionError("This constructor is only available to super classes.");
    } else {
        // Continue...
    }
}

Here's what I would try (I have not tested this method):

<modifier> Account(Object arg) {
    if (!super.getClass().isAssignableFrom(this.getClass())) {
        throw new AssertionError("This constructor is only available to super classes.");
    } else {
        // Continue...
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文