6

I am reading the book of OCA & OCP for java 7 certification and I am trying the exercises of the book with java 8 and I noticed something wired.

I have Class1 class as follows:

package cert;
public class Class1{
    protected static void importantMethod(){
    System.out.println("importantMethod() method of Class1 class TEST \n");
}

The modifiers of importantMethod() method are protected static and the package is cert as you may see, and as explained in the book I would expect that another class from another package, in my case Class2 shown bellow, can access the importantMethod() method only through inheritance, but it turned out that from Class2 I could access the importantMethod() method through an instance of Class1 as well.

Class2 class:

package exam;
import cert.Class1;
class Class2 extends Class1 {
    public static void main(String[] args) {
        Class1 c1 = new Class1();
        c1.importantMethod();
    }
}

If I remove the static modifier from Class1 it gives the expected error when trying to access the importantMethod() method from the Class2:

exam\Class2.java:7: error: importantMethod() has protected access in Class1
            c1.importantMethod();
              ^

My question is, does a non access modifier change the level of access for a member of a class?

Arber Hoxha
  • 73
  • 10
  • *"The modifiers of Class1 are protected static"*... Your question clearly shows it as `public` – OneCricketeer Apr 11 '17 at 13:08
  • 1
    @cricket_007 he should've meant the modifiers of the method 'importantMethod'. – djames Apr 11 '17 at 13:13
  • Related: http://stackoverflow.com/questions/24289070/why-we-should-not-use-protected-static-in-java – OneCricketeer Apr 11 '17 at 13:14
  • Static members are properties of the *class* and non-static members are properties of the object or instance. The quick answer is no, `static` doesn't change the level of access, but the *type* of access. – Drew Kennedy Apr 11 '17 at 13:24
  • Hi @DrewKennedy, so it is wired that I could access the importantMethod through an instance of Class1 and not as an inherited member right? – Arber Hoxha Apr 11 '17 at 13:31
  • @Arber You never used it as an inherited member. You made a `new Class1`, not a `Class2` – OneCricketeer Apr 11 '17 at 13:35
  • Compiler should have stopped me to use it other than an inherited member, that is my point, why did I not get an error when I did not call the importantMethod as an inherited member? – Arber Hoxha Apr 11 '17 at 13:38

2 Answers2

3

Everything is fine - that's how protected access is meant to work. It's specified in JLS 6.6.2.1:

Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.

In addition, if Id denotes an instance field or instance method, then:

  • [Irrelevant stuff as Id does not denote an instance field or instance method]

Your code is within the body of a subclass S of C (where S is Class2 and C is Class1) so it's fine.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Hi @JonSkeet, this part of the book made me confuse: This makes the variable accessible to all other classes inside the certification package, as well as ** *inheritable* by any subclasses outside the package** . Finally, we've seen that subclasses outside the package can't use a superclass reference to access a protected member. *For a subclass outside the package, the protected member can beaccessed **only** through inheritance.* Thank you for your answer. – Arber Hoxha Apr 11 '17 at 14:23
  • @ArberHoxha: Well that's just a not-terribly-clear way of saying the same thing. The "only through inheritance" is being used as a shorthand for the "only within the body of a subclass S of C" and the parts that follow. – Jon Skeet Apr 11 '17 at 14:29
  • Please take a look at the example between page 38 and 39 at this picture: https://www.dropbox.com/s/4gdl6ry939285gi/Protected.PNG?dl=0 – Arber Hoxha Apr 11 '17 at 14:34
  • @ArberHoxha: Yes, and that's explained by the rules that are in the "irrelevant stuff" because that's showing an *instance field*. Your question shows a static field. Really, just read the section of the spec that I referred you to. – Jon Skeet Apr 11 '17 at 14:43
  • @ArberHoxha I think maybe additionally where you are confused is that the `main` method is not inherited – OneCricketeer Apr 11 '17 at 15:38
  • Sorry @cricket_007 I did not understand you, what do you mean by "main method is not inherited"? – Arber Hoxha Apr 11 '17 at 15:41
  • @ArberHoxha I mean exactly that... `Class2 extends Class1` has a `public static void main` method. It is not "inherited from `Class1`" (assuming you had a `main` method there). You called a *`protected` method* on a `Class1` instance in a *separate package* and *not using a `Class2` instance*. – OneCricketeer Apr 11 '17 at 15:44
  • @cricket_007 what you are saying does not answer my question that I did in the beginning I think: "My question is, does a non access modifier change the level of access for a member of a class?" Maybe I am becoming too stubborn here but I am not being able to understand if here is being broken the access control that protected forces or not. If you are sure that you have given the answer to me I withdraw and will try to analyse better the answers that you have given to me. Thanks a lot :) – Arber Hoxha Apr 11 '17 at 15:50
  • 2
    @ArberHoxha: No, the compiler is behaving correctly, according to the language specification. The book you're using just used unfortunately oversimplistic terminology. – Jon Skeet Apr 11 '17 at 16:02
2

it turned out that from Class2 I could access the importantMethod() method through an instance of Class1

You don't need an instance to call a static method. Class1.importantMethod() works fine. If you remove static, it doesn't, and that's what you're seeing.

If I remove the static modifier from Class1 it gives the expected error

Because you're in a different package and not calling the method through inheritance like so

package exam;
import cert.Class1;
public class Class2 extends Class1 {

    public static void main(String[] args) {
        new Class2().importantMethod();
    }
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • Hi @cricket_007, you said **You don't need an instance to call a static method. That's why that worked.**, but it should not work, because I am still in a different package and the **importantMethod()** method has protected access modifier, that is why I am asking why it worked. It is protected anyway, it shouldn't matter if it static or not I think, because static is a non access modifier right? Anyway I can not call the – Arber Hoxha Apr 11 '17 at 13:23
  • `c1.importantMethod()` is not correct when it's a static method. `Class1.importantMethod()` is how you refer to a static method and `protected` doesn't affect that, I don't think – OneCricketeer Apr 11 '17 at 13:32
  • But c1.importantMethod() worked. If that was not correct shouldn't I have taken an error in that case? – Arber Hoxha Apr 11 '17 at 13:34
  • It's a compiler warning. It's syntactically incorrect. You never need an instance to call a static method. That's my only point – OneCricketeer Apr 11 '17 at 13:36
  • Ok, maybe is a problem of the compiler that did not "protect" the importantMethod from being called from another class in another package not as an inherited member even though importantMethod had the protected access modifier... – Arber Hoxha Apr 11 '17 at 13:41
  • Static members are tied to classes, not instances so there can only be one copy of any static member and importantMethod is a static member of Class1.. Btw, protected access is not the same as private access which may be where you are getting confused Arber. – Old Nick Apr 11 '17 at 13:43
  • Hi @NickSimpson, I was more focused on the access level reather than on the way that importantMethod is accessed. – Arber Hoxha Apr 11 '17 at 13:46
  • I edited my comment, maybe have another quick read up on the differences between private and protected access.. Protected is almost the same as default access. – Old Nick Apr 11 '17 at 13:48
  • I know the difference between private and protected because I am reading the book of OCA & OCP and according to the book, protected allows the access of a member of class by other classes in the same package as the default access level and it allows that the classes from another package can access the member of a class ONLY through the inheritance right? This is the problem, in my case I do not access the importantMethod as an inherited member but through an instance, according to the rules of protected explained above that should NOT happen. Am I missing something else? – Arber Hoxha Apr 11 '17 at 13:57
  • 1
    No, you are not accessing it through an instance, there is only one copy of it as it is a static member, you need to go back and read your study material again as you haven't understood it properly. – Old Nick Apr 11 '17 at 14:00