繁体   English   中英

Java继承-仅在子类型中使用setter

[英]Java Inheritance - setters only in subtypes

我们有两个班级(一个父母和一个孩子)。 两者都使用私有变量来存储值,但父级不应该提供设置器(x和y是由构造函数提供的,它们是某种不可变的)。 B应该用x和y的二传手扩展A。 有一种通用的方法吗?

class A{
    private int x;
    private int y;

    A(int x, int y){
        this.x = x;
        this.y = y;
    }

}

class B extends A{

    public void setx(int x){
        this.x = x;
    }

    //same for y
}

一些想法

  • 变量应该是私有的
  • 父代的x和y必须是不可变的
  • 乙必须提供一个公共设置者

在基类中声明protected的变量,并在子类中编写getter和setter。

如果您希望变量不可变,则应为

class B extends A{

    public B(int x, int y){
          super(x, y);
    }
}

目前,您在A中的x和y变量是不可变的。 为了使它们不可变,然后在它们之前添加final

这是分配x和y私有的唯一方法。 如果要使用setter,则必须使变量受保护。

我个人是不变性的忠实拥护者,因此可以做到这一点,而不是二传手-创建对象通常非常便宜。

您不能有一个私有成员变量,也没有方法(这里的方法也指构造函数)来设置它(从技术上讲可以,但是没有意义)。 如果要从派生类设置变量,则必须对其进行保护。

编辑:但是,您可以在基类中定义一个受保护的“帮助程序”设置程序,并从派生类中的公共设置程序调用此受保护的帮助程序设置程序。

第二次编辑:另一种可能性是在基类中定义一个抽象的getter,并在派生类(模板模式)中实现getter,setter和private字段。

这是一个很奇怪的问题,它是一成不变但可变的,是私人的却是公共的……正确的方法应该是使它们受到保护,正如每个人都说的那样。

无论如何,在Java中,如果安全管理器没有抱怨,您可以使用肮脏的技巧,请检查以下内容:

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Priv
{
    public static class A
    {
        private final int x;
        public A(int x)
        {
            this.x = x;
        }
    }

    public static class B extends A
    {
        public B(int x)
        {
            super(x);
        }

        public void setX(int x)
        {
            Class c = A.class;
            try
            {
                 Field f = c.getDeclaredField("x");
                f.setAccessible(true);
                f.set(this, x);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchFieldException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        public int getX()
        {
            int v = 0;

            try {
                Class c = A.class;
                Field f = c.getDeclaredField("x");
                f.setAccessible(true);
                v = f.getInt(this);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchFieldException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex);
            }

            return v;
        }
    }

    public static void main(String[] args)
    {
         B b = new B(5);

         System.out.println("b.x is " + b.getX());

         b.setX(42);

        System.out.println("b.x now is " + b.getX());
    }

}

没有不变的概念,您有任何调用super的setter方法或子类的构造函数来重新初始化私有的super类的变量。

不可变本质上是线程安全的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM