1

Assume I have a base class with a package accessible member:

package testcase;

public class B
{
    int b;
}

And it has a subclass:

package testcase.sub;

import testcase.B;


public class C
    extends B
{   
    int c;
}

Now I need to access the member field from within the same package that defined the field:

package testcase;

import testcase.sub.C;


public class A
{

    void testcase( C c )
    {
        c.c = 0;             // HINT
        ( (B) c ).b = 1;     // FIRST
        c.b = 2;             // SECOND
    }

}

EDIT: I absolutely understand that A cannot access c.c and why the line marked HINT does not compile: C.c is only visible to code in the same package and while C.c is in package testcase.sub A is in testcase.

However A and B.b are both in package testcase so why does the first assignment compile, while the second does not?

Steffen Heil
  • 4,286
  • 3
  • 32
  • 35
  • Are A, B and C in the same package? – Raedwald Apr 01 '16 at 15:47
  • What makes you think `testcase` is the same package as `testcase.sub`? –  Apr 01 '16 at 16:48
  • @Raedwald Every class has its package declaration. – Steffen Heil Apr 03 '16 at 19:23
  • `A` and `B` are both in `testcase` – Steffen Heil Apr 03 '16 at 19:25
  • 1
    I don't agree that this question is a duplicate. I know what the access modifiers mean in general, but this is a very specific question that contradicts what most definitions of the modifiers allow. How can the question be marked as non-duplicate? – Steffen Heil Apr 03 '16 at 19:50
  • You have to *show in the text of your question* why it is not a duplicate. You have to convince. – Raedwald Apr 04 '16 at 05:41
  • @Raedwald The question explicitly asks, why the first assignment is allowed while the second is not. I this this clearifies that the concept of public, private, protected and package-protected are known to me. The "duplicated question" is more a "how should these work" instead of a "is there an exception and why" question. – Steffen Heil Apr 04 '16 at 06:25

1 Answers1

2

C doesn't have access to B.b, B.b is package level permission and B is in the testcase package but C is in the testcase.sub package. Those are not the same package, so C has no b field.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • 1
    The obligatory link to JLS: https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.1 (see example 6.6-4) – Thomas Apr 01 '16 at 15:49
  • `B.b` is package level and `A` is in the same package... – Steffen Heil Apr 03 '16 at 19:27
  • Yes, but `C` does not have access to `B.b` so there is no `b` in `C`. Even though `A` has visibility to `B` that has nothing to do with `C`'s visibility (or in this case lack there of) to `B.b`. – Elliott Frisch Apr 03 '16 at 19:48
  • @Thomas I look at that example multiple times and I still don't think that this matches the problem. – Steffen Heil Apr 03 '16 at 19:48
  • @ElliottFrisch `C` does not even try to access `B.b`. `A` does. And `A` should have access to `B.b`, which is does, otherwise it would not work after casting... – Steffen Heil Apr 04 '16 at 06:29
  • @SteffenHeil `A` sees `C` as such and not `B`. Thus if `C` can't access the field in `B` then `A` can't do so either since `c` _is a_ `C` not a `B`. – Thomas Apr 04 '16 at 07:32
  • @Thomas `A` knows that `C` is a `B`. For example, `A` could call `c.toString()`, so why shouldn't it know that `C` is a `B` ? – Steffen Heil Apr 05 '16 at 11:32
  • @SteffenHeil even if `A` knows that `C` is a `B` it still treats it as a `C` and knows that it can't see `B.b`. – Thomas Apr 05 '16 at 11:35
  • @Thomas: I understand that it is the way it is - that I already knew, when the compiler complained. However I still don't understand why and I think this is a **bad** JLS decision (if it is not even a bug in the compiler). `A` knows that `C` is a `B` and it knows that `B` is a `Object` so it can call `c.toString()`. Why shouldn't it be able to access `B.b`. That does not make sense. – Steffen Heil Apr 07 '16 at 05:07
  • @SteffenHeil well, if you design your code so that `C` is not allowed to access a member of `B` the compiler should comply with that. It should not allow you to access a member of `B` through an instance of `C` because you decided it can't - unless you state you want to treat `c` as a `B` which you are doing by using the cast. – Thomas Apr 07 '16 at 08:00
  • @Thomas: `C` is not accessing `B.b` in any way and I explicitly denied that. But `C` is no trying to access `B.b`, `A` is. – Steffen Heil Apr 09 '16 at 10:23
  • @SteffenHeil yes, but `A` knows that `c` is an instance of `C` which doesn't have access to `b` and thus `A` knows that it also should not be allowed to access `b`. With the cast to `B` you tell `A` that _you_ want `c` to be treated as a `B` so this works then. – Thomas Apr 11 '16 at 07:07