【问题标题】:Why are protected members allowed in final java classes?为什么最终 Java 类中允许受保护的成员?
【发布时间】:2011-04-09 08:14:45
【问题描述】:

为什么最终类中允许受保护的成员?

这不应该是编译时错误吗?

编辑:正如人们所指出的,您可以通过使用 default 修饰符来获得相同的包访问权限。它应该以完全相同的方式表现,因为 protected 只是 default + 子类,而 final 修饰符明确拒绝子类化,所以我认为答案不仅仅是提供相同的包访问。

【问题讨论】:

  • 问题的一个变体仍然有效:为什么我们可以拥有私有静态最终方法? “私有”意味着“最终”以及“静态”,对吗?是不是多余的?
  • @gawi:我不知道如何解释你的评论,但private 肯定不暗示static/final
  • @gawi:私有意味着非虚拟,不是静态的,说“私有意味着最终”是没有意义的,因为“最终”只对继承的方法有意义。我同意,因为我找不到在私有方法声明中使用“final”的正当理由。
  • 抽象类中也可以有公共构造函数,这是一种常用的模式。仅仅因为它不是很有用,并不会使其成为错误。
  • 在方法上,“静态”与最终/非最终方面不兼容,因为无法覆盖静态方法。在基类 B 中拥有最终静态方法 x() 不会阻止派生类 D 拥有自己的 x() 方法。静态方法的 final 关键字没有任何意义。

标签: java oop


【解决方案1】:

protected 修饰符对于从基类重写 protected 方法的方法是必需的,而不会将这些成员暴露给 public

一般来说,您可以引入许多不必要的规则来取缔不合理的组合(例如protected static),但这无济于事。你不能取缔愚蠢。

【讨论】:

  • 啊,好的。因为您不能降低可见性以使它们成为默认或私有(这可能是最终类中的意图),所以您可以将它们保护或公开它们。尽管在这种情况下将它们设为默认值不会降低可见性(因为不可能进行子类化),所以恕我直言,编译器应该停止抱怨。
  • 是的。我应该说你可以让他们public,但你不想这样做。实际上,protected 如果您在不同的包中覆盖,则表现得特别。我不是protected的粉丝。
  • 行为异常如何?你的意思是受保护的有包访问权不直观吗?
  • @orbfish 如果您的类具有受保护的方法,则同一包中的类可以访问它。到目前为止一切都很好(很糟糕,但你知道)。现在考虑一个覆盖该方法的派生类,使其受到保护。现在原始包中的类无法访问它,除非它们将对象分配给具有基类类型的变量。那“破坏了LSP”并且很丑陋。但是避免受保护,你不会看到它。
  • @Tom - 没想到这一点,谢谢!现在,如果我能弄清楚为什么有人会在最终的非子类中有一个受保护的成员....
【解决方案2】:

因为受保护的成员可以被同一个包中的其他类以及子类访问。

【讨论】:

  • 当然正确,但如果是这种情况,您使用默认(包)访问会得到相同的结果,所以它仍然可能是编译错误。我认为这只是更多证据表明他们应该将子类可见性和包/内部类可见性作为完全独立的概念。他们是谁告诉我,如果一个子类具有可见性,那么包也必须如此?
  • @Mark:是的,这显然没有经过深思熟虑。
  • “受保护的成员可以被同一个包中的其他类访问”:真的吗?!我以为这就是 package-private 的用途?
  • @Coronatus,请参阅 JLS 6.6.1,java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.1。 \ @Mark Peters,同意,并且包访问不应该是默认的。
  • @Coronatus:是的。但protected也是如此。
【解决方案3】:

protected 修饰符还允许在同一个包内访问,而不仅仅是子类。所以在最后一堂课上也不是完全没有意义。

【讨论】:

    【解决方案4】:

    这里所说的protected成员可以被同一个包的类访问的论点是有效的,但在这种情况下protected等于默认可见性(包私有),问题仍然存在——为什么两者都允许。

    我猜两件事:

    • 无需禁止
    • 可以暂时创建一个类final,直到做出设计决定。每次添加或删除 final 时,不应更改所有可见性修饰符

    【讨论】:

    • +1:然而,我很惊讶“不正确”的答案被投票的速度如此之快。它是否说明了平均知识?
    【解决方案5】:

    你可以这样说,但无论如何也没有真正的伤害。非最终类也可能有一个受保护的成员,但没有子类,它也不会打扰任何人。

    【讨论】:

    • 可以被证明无用的东西是编译错误的好候选(警告会更好)不是因为它们直接“打扰”或“伤害”任何人/任何东西,而是因为很有可能发生这是程序员的错误/错字。
    • 你怎么证明它没用?将最终类更改为非最终类甚至不会破坏二进制兼容性。
    【解决方案6】:
    package p;
    
    import java.sql.Connection;
    
    public final class ProtectedTest {
        String currentUser;
        Connection con = null;
    
        protected Object ProtectedMethod(){
            return new Object();
        }
        public ProtectedTest(){
        }
        public ProtectedTest(String currentUser){
            this.currentUser = currentUser;
        }
    }
    

    package p;
    
    public class CallProtectedTest {
        public void CallProtectedTestMethod() {
            System.out.println("CallProtectedTestMethod called :::::::::::::::::");
            ProtectedTest p = new ProtectedTest();
            Object obj = p.ProtectedMethod();
            System.out.println("obj >>>>>>>>>>>>>>>>>>>>>>>"+obj);
        }
    }
    

    package p1;
    
    import p.CallProtectedTest;
    
    public class CallProtectedTestFromp2 {
        public void CallProtectedTestFromp2Method(){
            CallProtectedTest cpt = new CallProtectedTest();
            cpt.CallProtectedTestMethod();
        }
    
        public static void main(String[] args) {
            CallProtectedTestFromp2 cptf2 = new CallProtectedTestFromp2();
            cptf2.CallProtectedTestFromp2Method();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-01
      • 2016-09-13
      • 2017-01-01
      • 2012-05-03
      • 2017-09-14
      • 2012-01-17
      • 2018-02-11
      • 1970-01-01
      相关资源
      最近更新 更多