【问题标题】:Why am I able to have a public member in a non-public class?为什么我可以在非公共课程中拥有公共成员?
【发布时间】:2014-03-03 00:27:42
【问题描述】:
class MyClass 
{
    public static final int num=90;
}
  • 为什么允许我在非公共类中创建公共成员?
  • 是否有其他我不知道的访问该成员的方法(除了通过类名)?

【问题讨论】:

  • 同样,您可以将接口上的方法声明为publicabstract,即使这些属性无论如何都必须为真,并且您可以声明其参数final,即使它没有意义在这种情况下。 Java 是一头奇怪的野兽。
  • @fge 我不确定这是不是真的。 MyClass 可能在包外不可见,但您可以添加一个扩展它的 public 类。我认为现在成员上的访问修饰符变得非常重要。
  • @JasonC,我用于静态字段的相同技术也可用于成员变量(“普通”字段)。我们应该对 Java 语法更有信心:)。

标签: java class public-members


【解决方案1】:

由于您的问题是关于 members,我将同时讨论字段和方法(非静态;Anthony Accioly's answer 涉及另一个很好的用例,其中也包括静态字段)。

虽然在许多情况下,这只是语言语法的模棱两可的结果(特别是:非公共类中的公共 字段,如您的示例 sn-p),但有很好的理由因为需要能够在非公共类中使用公共方法

扩展Mik378's 答案,考虑例如以下(人为的示例):

import ...;

class BleebleAscendingComparator implements Comparator<Bleeble> {
    @Override public int compare (Bleeble o1, Bleeble o2) { ... }
}

class BleebleDescendingComparator implements Comparator<Bleeble> {
    @Override public int compare (Bleeble o1, Bleeble o2) { ... }
}

public class BleebleView {  
    public enum SortMode { ASC, DESC };
    public Comparator<Bleeble> getDisplayOrderComparator (SortMode mode) {
        if (mode == SortMode.ASC)
            return new BleebleAscendingComparator();
        else
            return new BleebleDescendingComparator();
    }
}

您不能直接在该上下文之外实例化这些Comparator 实现之一,但它们必须覆盖Comparator 的公共方法,并且它们的功能可以通过Comparator 接口访问。

同样的推理也适用于 privateprotected 内部类。如果您无法声明方法public,您将无法覆盖它们继承的接口或它们扩展的类的public 方法。

实际例子:

  • 每次在匿名内部类中重写公共方法时(例如,每次在匿名 ActionListener 中重写 public void actionPerformed 时)都会使用此方法。

  • 考虑您希望存储在HashMap 中的任何非公共类。您将覆盖该非公共类中的公共equals()hashCode(),并且HashMap 的实现可以访问它们,而不管该类是非公共的。

  • 经常被覆盖的 public toString() 是潜在非公共类的公共成员的另一个常见示例。

  • 一个更复杂的例子是在java.sql.DriverManager 中使用java.sql.Driver(一般来说,工厂类型的设计会大量使用这个概念)——SQL 驱动程序实现可能不会公开实现类(例如Oracle 驱动程序产生非公开的Connection 对象)。

  • 还有更多...如果您留意这方面的例子,您会惊讶于它的普遍性!

【讨论】:

  • 完全同意 ;) 很好地说明了我试图写的想法。
【解决方案2】:

不要忘记具有default 访问权限的类可以由同一包中的public 类进行子类化。

package package1;

class MyDefaultClass {

    public static final int MY_CONSTANT = 0xCAFEBABE;
}

public class PublicExporter extends MyDefaultClass {

}

现在public 类充当桥梁,您可以使用其他包中的MyDefaultClass public 成员。

package package2;

import package1.PublicExporter;

public class Consumer {
    public static void main(String[] args) {
        System.out.printf("%x\n", PublicExporter.MY_CONSTANT);
    }
}

消费者甚至可以导入静态成员:

import static package1.PublicExporter.MY_CONSTANT;

public class Consumer {
    public static void main(String[] args) {
        System.out.printf("%x\n", MY_CONSTANT);
    }
}

【讨论】:

    【解决方案3】:

    当属于封闭类Apublic 方法返回对其具有默认范围的内部类B 的引用(public 超类型引用,如接口)时,外部客户端(在A 的包之外)只能调用B 的方法,但不能创建自己的B 的新实例。

    如果B 的方法不是public,则外部客户端无法访问它们,更糟糕的是:由于没有很好地实现其接口,会导致编译错误。

    这种建模在特定情况下可能很有用,可以改进代码设计。

    【讨论】:

    • 外部客户端在看不到类的情况下如何调用这些方法?他们怎么知道这个方法?
    • 更新了我的答案。想象一下返回类型是内部类的public 接口。假设 inner class 具有默认范围,因此扩展此 interface
    • 公共方法如何返回非公共类?调用者应该怎么做?他只能将其视为Object
    • 好吧,如果你实现了一个接口,那就完全不同了。但问题是关于字段的。
    • @Thilo 实现接口的内部类不会改变概念。
    【解决方案4】:

    当你声明一个变量public 时,它基本上就是这样;它可以在整个程序中看到,无需任何特殊的 getter/setter。该类不一定必须是 public 才能使其成员也公开。

    请记住,在 Java 中,每个编译单元(.java 文件)只能有 1 个公共类,并且该公共类需要与编译单元具有相同的名称。除此之外,它不“拥有”关键字 public 的所有权。

    您将num 声明为publicstatic 的事实允许您说System.out.println(MyClass.num)。 public 属性允许您直接获取num 变量。因此,您不必创建一个方法来为您返回num。因为是公开的,所以也可以说

          MyClass mc = new MyClass();
          System.out.println(mc.num);
    

    但是,由于您还添加了 static 声明,您应该只能通过类名访问它,即 MyClass.num

    要点:公共变量可以存在于任何类型的类中,它们允许您访问它们而无需 getter 和 setter。但是,公共类并不是唯一可以拥有公共变量的类。

    【讨论】:

    • 类的公开与主方法的存在无关。
    • “类不一定要公开才能使其成员也公开。”你确定吗? @fge 对这个问题的评论表明相反。
    • @DirkHaase 好点,我应该编辑说 JVM 将查看公共类是否存在 main
    • @Thilo,我很确定。问题的代码是合法的 Java,不是吗?成员可以声明为公共的,并且在同一个 Java 文件中,范围将是公共的
    • 啊,我知道我在哪里犯了错误。感谢您指出这一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 2016-02-05
    • 2010-10-22
    • 2017-08-22
    • 1970-01-01
    • 2021-10-06
    • 2011-11-20
    相关资源
    最近更新 更多