3

This is a protected inheritance question. I do understand that protected means that in a package, it is as if it is public. Outside a package, generally speaking it is only accessible when you are INSIDE the subclass. That is not my confusion. My confusion is on a little nit pick that is occurring and I do not know why. I will explain the guts of the question after the code. You are given packages com.wobble.foo which holds the TestA class and com.wobble.bar which holds the TestB class which extends classA.

//A Package
package com.wobble.foo;

public class TestA{
    static protected int x = 5;
    protected int y = 6;
}

//A different Package
package com.wobble.bar;

public class TestB extends TestA{
    static{
        TestA t = new TestA();
        t.x = 1; //compiles
        t.y = 2; //field not visible, fails to compile
    }
}

The super class has a two variables both protected, one static. The subclass in a different package created a new superclass object attempting to access those two variables. Why are you able to, via the object, access the static variable through it, but not access the instance variable through it? They are both protected. Both from the same class. Both access by the same object. Note, to those who think this might be a duplicate: the other questions simply ask how protected works, but they fail to ask the specific question, of why only one of these two variables, both protected, can be accessed.

This is not a how-to-fix-the-code question. I know how to make the end game work. The question is why it is accessible via t.x; but not t.y;?

lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
JustAFellowCoder
  • 300
  • 2
  • 11
  • 3
    You never instantiate a TestB object in your code, the last three lines of your code are in a static initializer block, which does not need an instance to run. – MikaelF Mar 16 '19 at 23:47
  • 1
    Also: `t.x` should be `T.x` (since it's a static method call); and you would be able to access `y` if your code simply ran inside a non-static method of a `TestB` object; you wouldn't even need to say the object name `y` instead of `t.y`. – MikaelF Mar 16 '19 at 23:49
  • @MikaelF whether I put the code in a static or instance initializer, does not change the outcome. The point is accessing it through a TestA object. – JustAFellowCoder Mar 16 '19 at 23:50
  • @MikaelF thank you but I am quite aware how to fix it. This isn't a "how to fix this code" question. Thank you for your insight but I'm referring to why this approach does not work. Lastly, T.x would fail to compile while t.x will compile. – JustAFellowCoder Mar 16 '19 at 23:52
  • 2
    `T.y`is not accessible because, as a protected field, it's only accessible to its descendants (in this case `t`). However, you're not accessing it from `t`, but from a static block inside of class `TestA`. Protected is like private, but classes can access fields and methods they inherited from parent classes. – MikaelF Mar 17 '19 at 00:08
  • @MikaelF That should be an answer – Ferrybig Mar 17 '19 at 00:09
  • @Ferrybig Sorry, I just had enough time for a quick comment or two :( – MikaelF Mar 17 '19 at 00:11
  • @MikaelF if classes can access fields and methods from their inherited class, well... T.y is from the parent class... – JustAFellowCoder Mar 17 '19 at 00:40
  • 1
    @user11214549 Two ways you can see this: 1) You're trying to access a protected member of `t`, but it won't let you, because you're not `t` (see my remark about protected being similar to private); 2) You're accessing a non-static field from a static context, which you can't do. Your last 3 lines are not running inside of `t`; rather, they are running statically, and do not belong to any specific instance. Code not running inside of `t` can't see fields that `t` won't show outside of itself and of its dependants. Also, `t.x`is misleading, as it's really just `x` (`x` is static). – MikaelF Mar 17 '19 at 00:51
  • So I'm not allowed to access a protected member t cause I am not t? Ok that makes sense but then how can I access t.x? It is a protected member too and I am still not t. As for the static context. The context isn't static. TestA is the class. The instance of the object is t. I am doing t.y therefore the context is not a problem. (I changed it to public and it was fine). Lastly, so it is simply that t.x is technically not accessing it through t? Then to clarify everything that would mean, for outside package: only accessible IN subclass through subclass context; not even superclass context? – JustAFellowCoder Mar 17 '19 at 01:14
  • For the last part (I ran out of characters): if it is outside the package, you can only access it IN the subclass along with the condition that it is being access through the subclass. So in otherwords, it cannot be accessed by making an instance of the superclass inside the subclass because it is only accessible via the subclass. And for the t.x part, it is static so technically you aren't accessing it via the superclass, but through the subclass? i.e. t.x -> x -> TestB.x which gets it via TestB? – JustAFellowCoder Mar 17 '19 at 01:24

1 Answers1

3
 t.x = 1; //compiles

This is a static field. So you should write it as TestA.x (there will have been a compiler warning about that).

Static protected fields are accessible from within static code of subclasses (or from non-static code for that matter).

 t.y = 2; //field not visible, fails to compile

This is an instance field. Protected instance fields are accessible from within instance methods on subclasses. But only from within those methods. You cannot call them from a static method (even if that static method happens to be on a subclass).

If you need to access the fields from a static method in another class, you need to either make the field public or move the code that needs it into the same package.


But only from within those methods.

And only if you can be sure that the instance in question is in fact from your own class.

In your example

TestA t = new TestA();
t.y = 2;

t.y is not visible, because code in TestB cannot access the protected field on instances from TestA. It needs to be an instance of TestB. The same code would work inside of a method on TestA, though.

The following won't work, either:

// in TestB
void boo(TestA someInstance){
   this.y = someInstance.y; 
   // does not compile, because someInstance.y is not visible
   // because it could be from unknown TestC
}

Ok that makes sense but then how can I access t.x? It is a protected member too and I am still not t.

The instance t is not used at all here (it could even be null and the code would still work). A static method is only dispatched on the compile-time (declared) type of the variable. Ideally, t.x should not even be allowed, but at least you get a compiler warning.


it is static so technically you aren't accessing it via the superclass, but through the subclass? i.e. t.x -> x -> TestB.x which gets it via TestB?

Static methods cannot be overridden by subclasses. TestB.x is just a confusing (or convenient, depending how you look at it) way to write TestA.x. You can think of it as the subclass automatically importing all the (public and protected) static fields and variables from the parent class. Makes for less keystrokes, but does not change the behaviour (certainly works very different from instance methods, which are dynamically dispatched on the actual instance type).

Either way, because TestA.x is protected, it is accessible to static code blocks in subclasses of TestA, including TestB.

Thilo
  • 257,207
  • 101
  • 511
  • 656