简体   繁体   中英

How can I enforce a type constructor in a concrete class through the interface it implements?

Let me describe the situation, and I'm sure I'm just thinking about this problem incorrectly. I have a concrete class that will implement an interface. I want to enforce in the contract that the class must have a constructor with a specific type. So for instance:

interface MyInterface {}
public class MyClass implements MyInterface {
    public MyClass(HashMap<String, String> params) {

    }
}

I want to ensure that MyClass is instantiated with a single HashMap argument, which seems like it would be done something like this:

interface MyInterface<T>

Other than using generics on method signatures, I've never used them with classes or interfaces, and I'm really a beginner with that, so please explain any generics involved with the solution... or the alternative solution if I'm thinking about this incorrectly (architecturally speaking). Thanks!

You can't enforce a contract on constructor using interface in Java. The best approximation you could get is by defining an interface for a factory, with a create() method that takes a single HashMap ...

Also you can replace the interface with an abstract class for which the constructor requires an HashMap , that will force sub classes to give one, but not more (the sub classes will not necessarily have an HashMap parameter).

Adding to the above answers, a constructor is an implementation detail. An interface defines a contract which describes how it behaves, not how it is assembled.

For this reason, you can't force an implementor to have a specific constructor. I think that whatever you're trying to do, an interface is not the way.


Update : This Annotation Processing Tool article describes how you can create an annotation and annotation processor which take effect at compile time and validate that a class has a no-arg constructor.

It can be adapted to work for a 1-argument constructor which takes a map instance.

To quote the article, its usage would be similar to:

@NoArgsConstructor
public abstract class NoArgsSuperClass {
  public NoArgsSuperClass() {
  }
}

// Passes
public class PublicNoArgsConstructor extends NoArgsSuperClass {
  public PublicNoArgsConstructor() {
  }
}

// Fails
public class NonPublicConstructor extends NoArgsSuperClass {
  NonPublicConstructor() {
  }
}

Instead of an Interface you would have to create an abstract class, declare the constructor in there and then any class which inherits from it would have to call the base constructor. May be make the default constructor inside the base class private also.

Andrew

It is not possible in Java to force a class to implement a constructor with specific argument types. Why would you want to do this? Normally, it isn't useful to do this.

You can force a non-abstract class to implement a certain method by making the class implement an interface or extend an abstract class in which that method is declared (but not defined). That's useful because of polymorphism; you can make a variable of the superclass type refer to an instance of the subclass, and call the method:

interface Animal {
    void makeSound(); }
}

class Dog implements Animal {
    void makeSound() {
        System.out.println("Woof!");
    }
}

// Later:

Animal a = new Dog();
a.makeSound();

Now you can call makeSound() without knowing that a refers to a Dog ; you know that the object that a refers to has a makeSound() method, because it's declared in the interface Animal (and a is an Animal ).

In the case of constructors, you never call a constructor polymorphically; you always call it by mentioning the name of the concrete class that you want to instantiate. Because of that, it's not very useful to force a class to have a constructor with certain parameters.

The only case where this might be useful is when instantiating classes dynamically via reflection. Through reflection you can find out which constructors a class has, and call one of them dynamically. You could then thrown an exception if the class doesn't have the specific constructor that you need - but there's no way to check this at compile-time.

Are you trying to create an object of MyInterface type through reflection?

Factory interface is a much simpler, and better, alternative.

Define a factory interface ( You can even define it as an inner interface in MyInterface ).

interface MyInterface {
  public static interface Factory {
    create( HashMap< String, String > params );
  }
}

Wherever new objects of MyInterface are created make sure it is done only through MyInterface.Factory .

On a question of generics. From the code as you provided MyInterface does not look generic at all

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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