在我的代码中,我对ArrayList有两种截然不同的用途:我想将它作为坐标使用,或者作为一维索引的数组使用。为此,我尝试这样做:
public abstract class Sugar
{
public static class Indexes extends ArrayList<Integer> {}
public static class Coord extends ArrayList<Integer> {}
}
这似乎一直有效,直到我尝试使用非默认构造函数,现在编译器在我尝试做这样的事情时对我大喊大叫:
public Integer getIndex(Integer ... inDims)
{
return getIndex(new Sugar.Coord(Arrays.asList(inDims)));
}
我是否需要重新定义扩展类中的所有构造函数,或者我对这种方法运气不好?希望我错过了一些非常明显的东西;我一直试图搜索其他尝试过此操作的人,但我无法弄清楚Google / Stack Overflow会将哪种查询引导到正确的问题。
答案 0 :(得分:3)
关于构造函数:是的,你必须全部编写它们。幸运的是,大多数IDE(Eclipse,netbeans,...)都能够从超类中自动生成构造函数,因此您不需要将它们写成mannualy。
然而,我根本不会使用这种糖方法。如果你需要区分坐标和索引,我会用变量名或方法名来做,而不是类类型。
然而 ,您的方法(至少)有1个优势:安全。就像现在一样,您无法将Coords
分配给Indexes
或反之亦然,因此错误代码的可能性较小。
答案 1 :(得分:3)
是的,您必须实现希望新类型公开的所有构造函数。
是的,实现自己的类型是合理有用的。
但是,值得考虑您是否希望您的类型是ArrayLists,或者您是否只希望将ArrayList用作实现的一部分。一般原则是 更喜欢构图而不是继承 。
例如,对于Coord类,扩展ArrayList允许任意多个维度。如果这不是你想要的,那么封装表示会给你更多的控制而不是扩展。
public static class Coord {
private List<Integer> coord = new ArrayList<Integer>();
public Coord( int x, int y, int z ) {
coord.add( x );
coord.add( y );
coord.add( z );
}
// Other constructors and methods you want to expose.
}
封装表示法还可以让您以后更改它。例如,您可以将其更改为int[]
以减少内存占用,而无需更改该类的任何客户端。
答案 2 :(得分:0)
如果您没有覆盖或添加新功能,那么扩展是没有意义的。你所做的只是创建几乎不被任何人使用的内部类。由于您创建了子类,因此您没有尝试使用的构造函数。如果你想继续这个设计(我不推荐),你需要覆盖基本上只调用super的构造函数。
答案 3 :(得分:0)
是的,你应该。如果你的类A
带有接受参数的构造函数,你想要定义子类B
,你应该以某种方式调用超类的构造函数:
class A {
A(int i) {
}
A(String s) {
}
}
class B extends A {
B(int i) {
super(i);
}
B(String s) {
super(i);
}
}
BTW不必调用获取相同类型的构造函数。例如,我可以说:
B(String s) {
super(s.length()); // call int constructor of supper class
}
(我以s.length()
为例)。
BUT
你肯定是错误的。如果为每种类型的集合定义子类,它不是语法糖。这是......我甚至不知道是什么。相反,您应该始终尝试在可能的情况下使用接口。例如索引只是一个列表:
private List<Integer> indexes = ArrayList<>();
甚至只是Collection
private Collection<Integer> indexes = ArrayList<>();
甚至只是Iterable
private Iterable<Integer> indexes = ArrayList<>();
这使您的代码设计得更好,因为您可以随时更改实现(例如,将ArrayList
更改为LinkedList
,甚至更改为Set
(最后两个示例),甚至更改为Cassandra {{ 1}}(对于最后一个示例),不更改使用索引操作的代码。