【问题标题】:How can I assign final variables of the base class within a derived class' constructor in Java?如何在 Java 的派生类的构造函数中分配基类的最终变量?
【发布时间】:2009-11-14 14:31:05
【问题描述】:

我有一个基本的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 修饰符?


编辑:

最后,我选择了一个基本抽象 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,实现了一个初始化 RGBValuesHSLValues 成员的简单构造函数。 (是的,我知道基类 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);
    }
}

【问题讨论】:

  • 顺便说一句,从超类的构造函数调用子类是危险的,以防这些方法依赖于子类尚未初始化的状态,因为它的构造函数在超类的构造函数正在运行。

标签: java inheritance immutability final


【解决方案1】:

必须在声明类型的构造函数完成之前分配最终变量。因此,不能在子类中分配 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);
    }
}

【讨论】:

    【解决方案2】:

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

    super(calculateRGB(...))
    

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

      • 有比规范化更多的好处:getter 函数(和 equals)也将被继承。此外,一组常量被继承
      • 如果您向我们展示更多 Color 适合的模型,我们可能会想出更好的想法...
      【解决方案4】:

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

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

      【讨论】:

      • 这有点误导-最好使用return new Color(r, g, b)(当然是在计算RGB值之后)。
      • 不确定您的意思?最初的问题涉及颜色的一个子类。如果这只是一门课,那就没有问题了。
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-24
        • 2010-10-16
        • 2016-12-20
        • 1970-01-01
        • 2018-07-16
        • 1970-01-01
        • 2012-12-24
        • 2011-04-23
        相关资源
        最近更新 更多