【问题标题】:Java class whose fields are only accessible to its subclasses (without getters/setters)?Java 类的字段只能由其子类访问(没有 getter/setter)?
【发布时间】:2009-10-01 16:28:22
【问题描述】:

我真正想要的是一个具有泛型构造函数的类,并且当调用子类的相同构造函数时,子类将可以访问相同的字段。这是我想做的一个例子:

public abstract class Command{
    private Mediator m

    public Command(Mediator med){
       m = med;
    }

    abstract void exec();
}

public class FoobarCommand extends Command{
    public FoobarCommand(Mediator med){
        super(med);
    }

    public void exec(){
        med.doAFoobar()
    }
 }

public static void main(String[] args){
    Mediator m = new Mediator();
    Command c = new FoobarCommand(m);
    c.exec();
}

显然这不起作用,因为 FoobarCommand 没有直接访问 Mediator med 的权限。那么,您将如何访问 med 字段?我不希望除了子类之外的任何其他人都可以访问它,并且“受保护”不是一个选项,因为我希望人们能够创建自己的命令(这显然会在包之外)。

【问题讨论】:

  • 我不明白你为什么不选择预保护
  • 看来这个问题是由于“exec”是指挥官的一种方法而不是调解人的方法。为什么不让 exec 的功能成为 Mediator 的方法(声明为 Mediator 接口的一部分)?然后你可以有一个通用的 Command 对象,它带有一个用于 Mediator 的 setter 和一个多态的 exec 方法。
  • 感谢大家的cmets。我有点睡眠不足,意识到我一直想要“保护”,甚至不应该问这个问题:-!

标签: java


【解决方案1】:

严格来说,实际上并没有这样的访问修饰符。声明一个字段(或方法/类,就此而言)可供子类访问是不可能的;您可以使用的最严格的修饰符是protected,它仍然允许访问父类的包中的其他类。

但除此之外,protected 才是正确的选择。

编辑:阐明受保护的一个选项。要访问受保护的方法,您必须是或者子类在同一个包中;你不必两者兼而有之。所以在不同包中创建的Command 的子类仍然可以访问(super).m

【讨论】:

  • 您可以检查 getter 和 setter 中的类型。它不是访问修饰符,但仍应达到预期的效果。
【解决方案2】:

将 Mediator Med 声明为“受保护”而非私有。

【讨论】:

    【解决方案3】:

    你需要在你的母类中声明 Mediator m protected。

    此外,在子类的 exec() 方法中,您需要执行 m.doAFoobar() 而不是 med.doAFoobar() 因为 med 不是成员,而是构造函数的形式参数。

    【讨论】:

      【解决方案4】:
      abstract class Command {
          protected Mediator m
      
          public Command(Mediator med){
              m = med;
          }
      
          abstract void exec();
      }
      

      这个类不是公共的,所以它只能被同一个包中的其他类扩展,并且'm'是受保护的,所以它可以被派生类访问。

      【讨论】:

      • 是的,但也可以被同一包及以上包中的类访问,这不是想要的行为。
      【解决方案5】:

      如果您授予 med 受保护的访问权限,它将可用于包外的子类。

      http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

      【讨论】:

        【解决方案6】:

        如果您希望某个字段只能被类本身以及该包中的任何派生类和其他类访问,请使用 protected 关键字。这就是它的用途,即使在包装之外它仍然应该工作。他们不需要调用 med.doFoobar();,而是需要调用 m.doFoobar();

        或者,您可以创建一个受保护的(甚至是公共的)get 函数。这样,您就可以公开获取中介的能力,但您不必在声明后让它们覆盖它。

        但是,您想要的(无法在包内读取)在 java 关键字中是不可能的。但是,既然你是编写这个特定包的人,你就不能从包内部访问它吗?或者只用这个文件创建你自己的包?没有办法允许子类访问,也不允许包中的类。

        【讨论】:

        • 你不能让它只被子类访问。它对同一个包中的类也是可见的。
        【解决方案7】:

        你可以做的是给子类一个命名完全相同的变量,然后使用构造函数和方法将它设置为等于超类

        public abstract class Command{
            private Mediator m
        
            public Command(Mediator med){
               m = med;
            }
        
            abstract void exec();
        }
        
        public class FoobarCommand extends Command{
        
            private Mediator m;
        
            public FoobarCommand(Mediator med){
                super(med);
                m = med;
            }
        
            public void exec(){
                m.doAFoobar()
            }
         }
        
        public static void main(String[] args){
            Mediator m = new Mediator();
            Command c = new FoobarCommand(m);
            c.exec();
        }
        

        但是,它的功能有限。由于m是一个对象引用,所以子类中m的变化会反映在超类中;但是,如果类成员是原语,则不会发生这种情况。 (鉴于所有原语都有一个等效的对象,如果有点笨拙,这可以解决)

        子类还必须直接接收引用,因为这是存储引用副本的地方。对于抽象超类,这很好,因为您可以保证是子类,但在此之下您必须小心处理数据的方式。

        【讨论】:

          猜你喜欢
          • 2020-04-19
          • 1970-01-01
          • 1970-01-01
          • 2020-05-14
          • 2021-12-07
          • 1970-01-01
          • 1970-01-01
          • 2023-03-31
          • 1970-01-01
          相关资源
          最近更新 更多