Java 如何强制在抽象类的所有子类中定义构造函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3164334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I force a Constructor to be defined in all subclass of my abstract class
提问by dodecaplex
I have an abstract class A that define abstract methods. This means that, for a class to be instanciable, all the abstract method have to be implemented.
我有一个定义抽象方法的抽象类 A。这意味着,要使类不可实例化,必须实现所有抽象方法。
I'd like all my subclasses to implement a constructor with 2 ints as parameters.
我希望我的所有子类都实现一个带有 2 个整数作为参数的构造函数。
Declaring a constructor defeats my purpose, as I want the constructor defined in subclasses and I don't know anything about the implementation. Moreover I cannot declare a constructor as being abstract;
声明构造函数违背了我的目的,因为我想要在子类中定义构造函数,而我对实现一无所知。此外,我不能将构造函数声明为抽象的;
Is there a way to do this ?
有没有办法做到这一点 ?
Example of what I want:
我想要的例子:
Lets say that I am defining the API of a Matrix class. In my problem, Matrix cannot change their dimensions.
假设我正在定义 Matrix 类的 API。在我的问题中,Matrix 不能改变它们的尺寸。
For a Matrix to be created, I need to provide its size.
要创建一个矩阵,我需要提供它的大小。
Hence, I want all my implementors to provide the constructor with the size as a parameter. This constructor is motivated by the problem, not by an implementation concern. The implementation can do whatever it wants with these, provided that all the semantic of the methods are kept.
因此,我希望我所有的实现者都为构造函数提供大小作为参数。这个构造函数的动机是问题,而不是实现问题。只要保留了方法的所有语义,实现就可以对它们做任何想做的事情。
Let's say I want to provide a basic implementation of the invert()
method in my abstract class. This method will create a new matrix with this
inverted dimensions. More specifically, as it is defined in the abstract class, it will create a new instance of the same class as this
, using a constructor that takes two ints. As it does not know the instance it will use reflection (getDefinedConstructor) and I want a way to waranty that I'll get it and that it will be meaningfull for the implementation.
假设我想invert()
在我的抽象类中提供该方法的基本实现。此方法将创建一个具有this
反转维度的新矩阵。更具体地说,因为它是在抽象类中定义的,它将this
使用一个带有两个整数的构造函数创建与 相同类的新实例。由于它不知道实例,它将使用反射(getDefinedConstructor),我想要一种方法来保证我会得到它并且它对实现有意义。
采纳答案by Jon Skeet
You can't force a particular signature of constructor in your subclass - but you canforce it to go through a constructor in your abstract class taking two integers. Subclasses couldcall that constructor from a parameterless constructor, passing in constants, for example. That's the closest you can come though.
您不能在子类中强制使用构造函数的特定签名 - 但您可以强制它通过抽象类中的构造函数接受两个整数。例如,子类可以从无参数构造函数调用该构造函数,例如传入常量。不过,这是你能来的最接近的地方。
Moreover, as you say, you don't know anything about the implementation - so how do you know that it's appropriate for them to have a constructor which requires two integers? What if one of them needs a String as well? Or possibly it makes sense for it to use a constant for one of those integers.
此外,正如您所说,您对实现一无所知 - 那么您怎么知道他们拥有一个需要两个整数的构造函数是合适的?如果其中一个也需要字符串怎么办?或者它可能对这些整数之一使用常量是有意义的。
What's the bigger picture here - whydo you want to force a particular constructor signature on your subclasses? (As I say, you can't actually dothis, but if you explain why you want it, a solution might present itself.)
这里更大的图景是什么 -为什么要在子类上强制使用特定的构造函数签名?(正如我所说,您实际上无法做到这一点,但是如果您解释了为什么想要它,那么可能会出现一个解决方案。)
One option is to have a separate interface for a factory:
一种选择是为工厂提供单独的界面:
interface MyClassFactory
{
MyClass newInstance(int x, int y);
}
Then each of your concrete subclasses of MyClass
would also need a factory which knew how to build an instance given two integers. It's not terribly convenient though - and you'd still need to build instances of the factories themselves. Again, what's the real situation here?
然后,您的每个具体子类MyClass
还需要一个工厂,该工厂知道如何在给定两个整数的情况下构建实例。不过这并不是很方便——而且你仍然需要自己构建工厂的实例。再次,这里的真实情况是什么?
回答by Tim Bender
If you need to define in your interface the internal representation that implementing classes will use, then you are just doing it wrong. Please go read about encapsulationand data abstraction.
如果您需要在接口中定义实现类将使用的内部表示,那么您就做错了。请阅读有关封装和数据抽象的信息。
If your abstract implementation relies on certain implementation details, then they belong to that abstract class. Meaning, the abstract class should define a constructor which allows it to initialize the internal state needed to allow the abstracted methods to work.
如果您的抽象实现依赖于某些实现细节,则它们属于该抽象类。意思是,抽象类应该定义一个构造函数,允许它初始化允许抽象方法工作所需的内部状态。
Generally, constructors are intended to create an instance of a class by providing some details of the initial state of that object instance. This does not mean that the instance being constructed should copy a reference to each individual argument as is often the case in most software I see. Therefore, even if Java did offer a construct for forcing the implementation of certain Constructor signatures on subclasses, those subclasses could easily discard the arguments.
通常,构造函数旨在通过提供该对象实例的初始状态的一些细节来创建类的实例。这并不意味着正在构造的实例应该复制对每个单独参数的引用,这在我看到的大多数软件中都是如此。因此,即使 Java 确实提供了强制在子类上实现某些构造函数签名的构造,这些子类也很容易丢弃参数。
回答by emory
You could try something like below. The constructor will thrown an exception if the implementing class does not have a constructor with the appropriate arguments.
您可以尝试以下操作。如果实现类没有带有适当参数的构造函数,构造函数将抛出异常。
This is silly. Compare OK and Bad. Both classes are the same, except that OK meets your requirement and thus passes the runtime checks. Thus enforcing the requirement promotes counter-productive busy work.
这是愚蠢的。比较 OK 和 Bad。这两个类是相同的,除了 OK 满足您的要求并因此通过运行时检查。因此,强制要求会促进适得其反的繁忙工作。
A better solution would be some sort of Factory.
更好的解决方案是某种工厂。
abstract class RequiresConstructor
{
RequiresConstructor( int x, int y ) throws NoSuchMethodException
{
super();
System.out.println( this.getClass().getName() ) ;
this.getClass(). getConstructor ( int.class , int.class ) ;
}
public static void main( String[] args ) throws NoSuchMethodException
{
Good good = new Good ( 0, 0 );
OK ok = new OK ();
Bad bad = new Bad ();
}
}
class Good extends RequiresConstructor
{
public Good( int x, int y ) throws NoSuchMethodException
{
super( x, y ) ;
}
}
class OK extends RequiresConstructor
{
public OK( int x, int y ) throws NoSuchMethodException
{
super( x, y ) ;
throw new NoSuchMethodException() ;
}
public OK() throws NoSuchMethodException
{
super( 0, 0 ) ;
}
}
class Bad extends RequiresConstructor
{
public Bad() throws NoSuchMethodException
{
super( 0, 0 ) ;
}
}
回答by yesennes
Have the abstract class have an abstract method which takes what you would have for parameters. For instance:
让抽象类有一个抽象方法,它采用您将拥有的参数。例如:
public abstract void setSize(int rows,int columns);
回答by Abdullah
A little bit late, but...
有点晚了,但是...
Just create a default constructor in your class which is always called as super constructor. In this default constructor you can check all defined constructors with reflection on it's own class object (which is then not the abstract super class but the concrete subclass). If the constructor you want to be implemented is missing, throw a runtime exception.
只需在您的类中创建一个默认构造函数,它总是被称为超级构造函数。在这个默认构造函数中,您可以检查所有已定义的构造函数,并对其自身的类对象(这不是抽象超类而是具体子类)进行反射。如果要实现的构造函数缺失,则抛出运行时异常。
I'm not a great friend of reflection because it has the taste of hacking through the back door, but sometimes it helps...
我不是反思的好朋友,因为它有通过后门入侵的味道,但有时它会有所帮助......
Have a look at this example:
看看这个例子:
import java.lang.reflect.Constructor;
public abstract class Gaga {
public Gaga() {
boolean found = false;
try {
Constructor<?>[] constructors = getClass().getConstructors();
for (Constructor<?> c : constructors) {
if (c.getParameterTypes().length==2) {
Class<?> class0 = c.getParameterTypes()[0];
Class<?> class1 = c.getParameterTypes()[1];
if ( (class0.getName().equals("int") || class0.isAssignableFrom(Integer.class))
&& (class1.getName().equals("int") || class1.isAssignableFrom(Integer.class)) )
found = true;
}
}
} catch (SecurityException e)
{
found = false;
}
if (!found)
throw new RuntimeException("Each subclass of Gaga has to implement a constructor with two integers as parameter.");
//...
}
}
And a test class:
和一个测试类:
public class Test {
private class Gaga1 extends Gaga {
public Gaga1() { this(0, 0); }
public Gaga1(int x, Integer y) { }
}
private class Gaga2 extends Gaga {
}
public static void main(String[] args)
{
new Gaga1();
new Gaga1(1, 5);
new Gaga2();
System.exit(0);
}
}
In the main function the objects of Gaga1 will be created, but the creation of Gaga2 will throw a runtime exception.
在 main 函数中会创建 Gaga1 的对象,但是创建 Gaga2 会抛出运行时异常。
But you can't be sure that this constructor is called - you can't even ensure that it is doing the things you want.
但是你不能确定这个构造函数被调用了——你甚至不能确保它正在做你想做的事情。
This test is only useful if you're working with reflection.
此测试仅在您使用反射时才有用。