如何在派生类中分配基类的最终变量? Java 中的构造函数?

发布于 2024-08-11 18:16:18 字数 4117 浏览 8 评论 0原文

我有一个基本 Color 类,看起来像这样。该类被设计为不可变的,因此具有 final 修饰符并且没有 setter:

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 类,它除了提供 颜色类吸气剂由色调、饱和度和亮度构成。这就是事情停止工作的地方。

ColorHSL的构造函数需要进行一些计算,然后设置_r_b_g的值。但必须在进行任何计算之前调用超级构造函数。因此引入了无参数 Color() 构造函数,允许设置最终的_r、_b_g稍后。但是,Java 编译器不接受无参数构造函数或设置(首次在 ColorHSL 的构造函数内)。

有没有办法解决这个问题,或者我是否必须从 _r_b_gfinal 修饰符代码>?


编辑:

最后,我选择了一个基本的抽象 Color 类,其中包含 RGB 和 HSL 数据。基类:

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;
    }
}

RGBColorHSLColor 类从 Color 派生,实现一个初始化 RGBValues 的简单构造函数> 和 HSLValues 成员。 (是的,我知道基类 if-ily 包含派生类的静态实例)

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);
    }
}

I have a base Color class that looks something like this. The class is designed to be immutable, so as a result has final modifiers and no setters:

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
}

Derived from this class is a ColorHSL class that in addition to providing the Color class' getters, is contructed with hue, saturation, and luminosity. This is where things stop working.

The constructor of ColorHSL needs to do some calculations, then set the values of _r, _b, and _g. But the super constructor has to be called before any calculations are made. So the parameterless Color() constructor was introduced, allowing the final _r, _b, and _g to be set later on. However, neither the parameterless constructor or the setting (for the first time, within the constructor of ColorHSL) are accepted by the Java compiler.

Is there a way around this issue, or do I have to remove the final modifier from _r, _b, and _g?


Edit:

In the end, I went for a base abstract Color class, containing both RGB and HSL data. The base class:

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;
    }
}

The classes of RGBColor and HSLColor then derive from Color, implementing a simple constructor that initializes the RGBValues and HSLValues members. (Yes, I know that the base class if-ily contains a static instance of a derived class)

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);
    }
}

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

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

发布评论

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

评论(5

善良天后 2024-08-18 18:16:18

必须在声明类型的构造函数完成时分配最终变量。因此,你不能在子类中分配super的final字段。

但是,您可以在子类中的静态工厂方法中进行转换:

class HSLColor {
    private HSLColor(int r, int g, int b) { super(r,g,b);}

    static HSLColor create(int h, int s, int l) {
        // conversion code here
        return new HSLColor(r,g,b);
    }
}

A final variable must be assigned by the time the declaring type's constructor has been completed. Therefore, you can not assign super's final fields in the subclass.

You could, however, do the conversion in a static factory method in the subclass:

class HSLColor {
    private HSLColor(int r, int g, int b) { super(r,g,b);}

    static HSLColor create(int h, int s, int l) {
        // conversion code here
        return new HSLColor(r,g,b);
    }
}
等风来 2024-08-18 18:16:18

据我所知,完成此操作的唯一方法是将超级构造函数的调用与计算 r、g 和 b 的函数嵌套在一起:

super(calculateRGB(...))

因此,您可能会考虑向 Color 添加一个构造函数,它将 RGB 值作为数组。

As far as I know the only way to get this done would be to nest the call of the super constructor with the function to calculate r, g, and b:

super(calculateRGB(...))

So you might consider adding a constructor to Color that takes RGB values as an array.

林空鹿饮溪 2024-08-18 18:16:18

是的,我可以看到 super(calculateRGB(...)) - 但看起来你几乎没有从这里的继承中获得任何东西。我只是使用通用接口。 RGB 和 HSV 不是两种不同的、可互换的颜色模型吗?

我认为Java问题背后有一个面向对象的分析问题。为什么要使用继承?

如果您需要做的只是可互换地操作 Color,您可能会发现您根本没有从继承中受益(而且它只会产生将 HSV 映射回超类的 RGB 的开销) ...如果您只想要可互换的颜色模型,请考虑使用 Color 接口而不是从 RGB 继承。

如果不了解 Color 对象的实际用途,就很难提出更好的设计。现在看起来继承的成本(调用超级构造函数中的颜色模型转换)将超过重用 normalize 的唯一好处。

Yes, I can see how super(calculateRGB(...)) - but it looks as though you gain practically nothing from inheritance here. I'd just use a common interface. Aren't RGB and HSV just two different, interchangeable colour models?

I think there's an object-oriented analysis problem here behind the Java problem. Why are you using inheritance?

If all you need to do is to manipulate a Color interchangeably, you might find that you don't benefit at all from inheritance (and it just creates an overhead of mapping HSV back into RGB for the superclass)... If you just want interchangeable colour models, consider using a Color interface rather than inheriting from RGB.

Without seeing what you're going to actually use the Colour objects for, it's hard to suggest a better design. Right now it looks as though the cost of inheritance (colour model conversion in a call to a super constructor) will outweigh the sole benefit of reusing normalize.

绅刃 2024-08-18 18:16:18

Java 中不能有抽象构造函数,因此除非您可以将所有计算放入对 super 的调用中,否则您无法对当前设计执行您想要执行的操作,因为最终变量必须按时分配声明构造函数已完成。

另一种方法是分解一些用于创建 Color 对象(工厂模式)的方法,该方法接受参数,在构造函数外部进行计算,然后您可以调用 super() 作为第一个参数。

例如 - 如果您的 Color 类中有以下内容,

public Color static createHSLColor(int h, int s, int v) {
   // All the calculation here

   return new ColorHSL(h,s,v);
}

那么您可以将构造函数设置为不公开(可能是受保护的),然后创建对象的唯一方法是通过工厂方法。

You can't have an abstract constructor in Java, so unless you can put all the calculation into the call to super you can't do what you'd like to do with the current design as a final variable must be assigned by the time the declaring constructor has completed.

An alternative would be to factor out some methods for the creation of Color objects (a factory pattern) which takes the arguments, does the calculations external to the constructor and then you can can call super() as the first argument.

For example - if you have the following on your Color class

public Color static createHSLColor(int h, int s, int v) {
   // All the calculation here

   return new ColorHSL(h,s,v);
}

You could then make the constructors not public (maybe protected) and then the only way the objects can be created is via your factory methods.

栀子花开つ 2024-08-18 18:16:18

您可以做的一件事是拥有一个代表计算器的构造函数参数。例如:

public Color(int r, int g, int b, Calc calc) {
   _r = calc.normalize(r);
   _g = calc.normalize(g);
   _b = calc.normalize(b);
}

这可能会完全消除对子类的需要。您可以声明构造函数:

public Color(int r, int g, int b) { 
  this(r,g,b, defaultCalc);
}

或者甚至提供静态样式构造函数:

public static Color hslColor(int r, int g, int b) {
    return new Color(r,g,b, hslCalc);
}

One thing you could do is to have a constructor parameter which represents the calculator. So for example:

public Color(int r, int g, int b, Calc calc) {
   _r = calc.normalize(r);
   _g = calc.normalize(g);
   _b = calc.normalize(b);
}

This may possibly remove the need for a subclass completely. You could declare constructors:

public Color(int r, int g, int b) { 
  this(r,g,b, defaultCalc);
}

Or even provide static style constructors:

public static Color hslColor(int r, int g, int b) {
    return new Color(r,g,b, hslCalc);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文