19

Why are protected members allowed in final classes?

Shouldn't this be a compile-time error?

Edit: as people have pointed out, you can get same package access by using the default modifier instead. It should behave in exactly the same manner, because protected is just default + sub-classes, and the final modifier explicitly denies subclassing, so I think the answer is more than just to provide same package access.

Tom Tresansky
  • 19,364
  • 17
  • 93
  • 129
  • A variant of the question is still valid: Why can we have private static final methods? "Private" implies "final" as well as "static", right? Isn't it redundant? – gawi Sep 07 '10 at 18:11
  • @gawi: I am not sure how to interpret your comment, but `private` certainly doesn't imply `static`/`final`. – BalusC Sep 07 '10 at 18:38
  • @gawi: Private implies non-virtual, not static, and it makes no sense to say that "private implies final" since "final" only has meaning in regards to inherited methods. I agree inasmuch as I can't find a valid reason to use "final" in a private method declaration though. – Mark Peters Sep 07 '10 at 18:51
  • 2
    You can also have public constructors in abstract classes, which is a commonly used pattern. Just because its not very useful, doesn't make it an error. – Peter Lawrey Sep 07 '10 at 19:08
  • On methods, "static" is incompatible with final/non-final aspect since static methods cannot be overridden. Having a final static method x() in base class B won't prevent a derived class D to have its own x() method. The final keyword on static methods don't have any signification whatsoever. – gawi Sep 07 '10 at 19:28
  • The same for "private". It doesn't change anything to add "final" on a private method since it can't be overridden. – gawi Sep 07 '10 at 19:31
  • To recap: it shouldn't have been allowed in the syntax to add "final" to a static or private method as it's meaningless. – gawi Sep 07 '10 at 19:34

6 Answers6

17

The protected modifier is necessary on methods that override protected methods from a base class, without exposing those members to the public.

In general, you could introduce a lot of unnecessary rules to outlaw implausible combinations (such as protected static), but it wouldn't help much. You can't outlaw stupidity.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Ah, ok. Because you can't reduce the visibility to make them default or private (which is probably what is intended in a final class), so you can leave them protected or expose them as public. Although in this case making them default does NOT reduce the visibility (since no subclassing is possible), so IMHO the compiler should stop whining. – Tom Tresansky Sep 07 '10 at 18:23
  • Yes. I should have said you could make them `public` but you wouldn't want to. Actually `protected` behaves peculiarly if you override in a different package. I'm not a fan of `protected`. – Tom Hawtin - tackline Sep 07 '10 at 18:29
  • Behaves peculiarly how? Do you just mean it's not intuitive that protected would have package access? – orbfish Nov 05 '11 at 03:12
  • @orbfish If you have a class with a protected method then a class in the same package can access it. So far so good (well bad, but you know). Now consider a derived class that overrides that method, keeping it protected. Now classes in the original package can't access it unless they assign the object to a variable with type of the base class. That "breaks LSP" and is just ugly. But avoid protected and you wont see it. – Tom Hawtin - tackline Nov 05 '11 at 09:52
  • @Tom - hadn't even thought of that, thanks! Now if I could just figure out why someone would have a protected member in a final, non-child class.... – orbfish Nov 05 '11 at 22:02
  • @orbfish: A `public` member makes a promise to the whole world on behalf of the class *and all its descendants*. A `protected` member makes a promise to the immediate descendants of the class only (at least in .NET it's possible to shadow a protected member so sub-derived classes can't see it; this doesn't violate LSP: any class which inherits from a class having a protected member knows that its base instance is of that exact type, and cannot be some other type derived from it. Thus, even if `Foo` has a protected member `Bar`, and `Goo` derives from `Foo` but hides it... – supercat Apr 04 '13 at 23:22
  • ...the fact that `Goo` hides `Bar` won't affect any classes that inherit from `Foo`, other than those that inherit from `Goo`. – supercat Apr 04 '13 at 23:23
15

Because protected members can be accessed by other classes in the same package, as well as subclasses.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 6
    Certainly true, though if that's the case you get the same result using the default (package) access, so it could still be a compile error. I think this is just more evidence that they should have kept subclass visibility and package/inner-class visibility as completely separate concepts. Who are they to tell me that if a subclass has visibility, the package must also? – Mark Peters Sep 07 '10 at 18:06
  • @Mark: Yeah, it clearly wasn't thought through as well as it could be. – skaffman Sep 07 '10 at 18:08
  • "protected members can be accessed by other classes in the same package" :O really?! I thought that's what package-private was for? – Amy B Sep 07 '10 at 18:11
  • @Coronatus, see the JLS 6.6.1, http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.1 . \ @Mark Peters, agreed, and package access should not be the default. – Andy Thomas Sep 07 '10 at 18:14
  • @Coronatus: It is. But so is `protected`. – skaffman Sep 07 '10 at 18:22
9

The protected modifier also allows access within the same package, not just to subclasses. So it's not completely meaningless on a final class.

Affe
  • 47,174
  • 11
  • 83
  • 83
7

The argument stated here that protected members can be accessed by classes of the same package is valid, but in this case protected becomes equal to the default visibility (package-private), and the question remains - why are both allowed.

I'd guess two things:

  • no need to forbid it
  • a class may be made final temporarily, until a design decision is made. One should not go and change all visibility modifiers each time he adds or removes final
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 2
    +1: I was however surprised how quick the "incorrect" answers got upvoted. Does it tell something about the average knowledge? – BalusC Sep 07 '10 at 18:14
0

You can argue that, but there's no real harm anyway. A non-final class may also have a protected member, but no subclass, it won't bother anybody either.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • 2
    Things that can be proven useless are good candidates for compile errors (warnings would be better) not because they directly "bother" or "hurt" anybody/anything, but rather because there's a very high likelihood of it being a programmer mistake/typo. – Mark Peters Sep 07 '10 at 18:42
  • how can you prove it's useless? change a final class to a non final class does not even break binary compatibility. – irreputable Sep 07 '10 at 19:55
-1
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();
    }
}
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
vikas
  • 1