继承在Java中,如何在派生类的构造函数中分配基类的最终变量?
我有一个基类Color
,看起来像这样。该类被设计为不可变的,因此具有final
修饰符而没有设置符:
public class Color
{
public static Color BLACK = new Color(0, 0, 0);
public static Color RED = new Color(255, 0, 0);
//...
public static Color WHITE = new Color(255, 255, 255);
protected final int _r;
protected final int _g;
protected final int _b;
public Color(int r, int b, int g)
{
_r = normalize(r);
_g = normalize(g);
_b = normalize(b);
}
protected Color()
{
}
protected int normalize(int val)
{
return val & 0xFF;
}
// getters not shown for simplicity
}
从这个类派生的是一个ColorHSL
类,它除了提供Color
类的getter之外,还由色调、饱和度和亮度构成。这就是事情停止运转的地方
ColorHSL
的构造函数需要进行一些计算,然后设置_r
、_b
和_g
的值。但是在进行任何计算之前,必须调用超级构造函数。因此引入了无参数的Color()
构造函数,允许稍后设置最终的_r
、_b
和_g
。但是,Java编译器不接受无参数构造函数或设置(第一次,在ColorHSL
的构造函数中)
有没有办法解决这个问题,或者我必须从_r
、_b
和_g
中删除final
修饰符
编辑:
最后,我选择了一个包含RGB和HSL数据的基本抽象Color
类。基类:
public abstract class Color
{
public static Color WHITE = new ColorRGB(255, 255, 255);
public static Color BLACK = new ColorRGB(0, 0, 0);
public static Color RED = new ColorRGB(255, 0, 0);
public static Color GREEN = new ColorRGB(0, 255, 0);
public static Color BLUE = new ColorRGB(0, 0, 255);
public static Color YELLOW = new ColorRGB(255, 255, 0);
public static Color MAGENTA = new ColorRGB(255, 0, 255);
public static Color CYAN = new ColorRGB(0, 255, 255);
public static final class RGBHelper
{
private final int _r;
private final int _g;
private final int _b;
public RGBHelper(int r, int g, int b)
{
_r = r & 0xFF;
_g = g & 0xFF;
_b = b & 0xFF;
}
public int getR()
{
return _r;
}
public int getG()
{
return _g;
}
public int getB()
{
return _b;
}
}
public final static class HSLHelper
{
private final double _hue;
private final double _sat;
private final double _lum;
public HSLHelper(double hue, double sat, double lum)
{
//Calculations unimportant to the question - initialises the class
}
public double getHue()
{
return _hue;
}
public double getSat()
{
return _sat;
}
public double getLum()
{
return _lum;
}
}
protected HSLHelper HSLValues = null;
protected RGBHelper RGBValues = null;
protected static HSLHelper RGBToHSL(RGBHelper rgb)
{
//Calculations unimportant to the question
return new HSLHelper(hue, sat, lum);
}
protected static RGBHelper HSLToRGB(HSLHelper hsl)
{
//Calculations unimportant to the question
return new RGBHelper(r,g,b)
}
public HSLHelper getHSL()
{
if(HSLValues == null)
{
HSLValues = RGBToHSL(RGBValues);
}
return HSLValues;
}
public RGBHelper getRGB()
{
if(RGBValues == null)
{
RGBValues = HSLToRGB(HSLValues);
}
return RGBValues;
}
}
然后RGBColor
和HSLColor
类派生自Color
,实现了一个简单的构造函数来初始化RGBValues
和HSLValues
成员。(是的,我知道基类包含派生类的静态实例)
public class ColorRGB extends Color
{
public ColorRGB(int r, int g, int b)
{
RGBValues = new RGBHelper(r,g,b);
}
}
public class ColorHSL extends Color
{
public ColorHSL(double hue, double sat, double lum)
{
HSLValues = new HSLHelper(hue,sat,lum);
}
}
# 1 楼答案
最后一个变量必须在声明类型的构造函数完成时赋值。因此,不能在子类中指定super的最终字段
但是,您可以在子类中的静态工厂方法中进行转换:
# 2 楼答案
是的,我可以看到
super(calculateRGB(...))
——但是看起来你从继承中几乎什么也得不到。我只需要使用一个公共接口。RGB和HSV不只是两种不同的、可互换的颜色模型吗我认为Java问题背后有一个面向对象的分析问题。你为什么要使用继承
如果你所需要做的只是互换地操作一种颜色,你可能会发现你根本没有从继承中受益(这只会为超类创建一个将HSV映射回RGB的开销)。。。如果你只想互换颜色模型,考虑使用颜色界面,而不是继承从RGB。
如果看不到这些彩色物体的实际用途,就很难提出更好的设计。现在看来,继承的成本(调用超级构造函数时的颜色模型转换)将超过重用
normalize
的唯一好处# 3 楼答案
可以做的一件事是使用一个表示计算器的构造函数参数。例如:
这可能会完全消除对子类的需求。您可以声明构造函数:
甚至提供静态样式的构造函数:
# 4 楼答案
Java中不能有一个抽象构造函数,所以除非你能把所有的计算都放在对super的调用中,否则你不能对当前的设计做你想做的事情,因为最终变量必须在声明构造函数完成时赋值
另一种方法是找出一些创建颜色对象(工厂模式)的方法,这些方法接受参数,在构造函数外部进行计算,然后可以调用super()作为第一个参数
例如,如果你的颜色课上有以下内容
然后可以使构造函数不公开(可能受保护),然后创建对象的唯一方法是通过工厂方法
# 5 楼答案
据我所知,实现这一点的唯一方法是将超级构造函数的调用与计算r、g和b的函数嵌套:
<>你可能会考虑添加一个构造函数来将RGB值作为数组。p>