When a class doesn't know it's grandpa...

  • Thread starter Andreas Leitgeb
  • Start date
A

Andreas Leitgeb

I'm somewhat surprised by a behaviour I didn't expect.

The situation is as follows:
class Z.A is static private and defines static meth().
class Z.B is static public and inherits class Z.A.
class Y inherits class Z.B, and shouldn't be able to
know it's own grandpa Z.A.
But still, Y can call its grandpa's static meth().


SSCCE: Z.java: (but run class Y)
public class Z {
private static class A {
public static void meth() {System.out.println("Hello, World! A"); }
}
public static class B extends A { }
}
class Y extends Z.B {
public static void main(String[]a){ Y.meth(); }
}
 
P

Piotr Kobzda

Andreas said:
I'm somewhat surprised by a behaviour I didn't expect.

The situation is as follows:
class Z.A is static private and defines static meth().

But that method is public, thus it's still publicly accessible.
class Z.B is static public and inherits class Z.A.
class Y inherits class Z.B, and shouldn't be able to
know it's own grandpa Z.A.
But still, Y can call its grandpa's static meth().

Declare meth() private to make it inaccessible outside the Z class.
Alternatively, if access to this method from other classes of your
package is desired (e.g. form Z.B) make it protected, or package
protected (which BTW, is usually a better choice than making it private
-- no synthetic accessors generation is needed).


piotr
 
R

rossum

I'm somewhat surprised by a behaviour I didn't expect.

The situation is as follows:
class Z.A is static private and defines static meth().
class Z.B is static public and inherits class Z.A.
class Y inherits class Z.B, and shouldn't be able to
know it's own grandpa Z.A.
But still, Y can call its grandpa's static meth().


SSCCE: Z.java: (but run class Y)
public class Z {
private static class A {
public static void meth() {System.out.println("Hello, World! A"); }
}
public static class B extends A { }
}
class Y extends Z.B {
public static void main(String[]a){ Y.meth(); }
}
Can you run class Y when Y is not public?

Do you need to use B.meth() anywhere? If not then you could override
meth() inside B to throw an UnsupportedOperationException so the
version inherited by Y does not do anything useful?

public static class B extends A {
public static void meth() {
throw new UnsupportedOperationException();
}
}

If you need to use meth inside B itself then you could use
super.meth() to pick the working version in A.

rossum
 
R

Roedy Green

class Y inherits class Z.B, and shouldn't be able to
know it's own grandpa Z.A.
But still, Y can call its grandpa's static meth().

Just as you mother might intervene to pass gifts on from your
grandmother, you can do the same in Java.

Mother can preserve the original grandmother method by wrapping it in
a name like "grannysOrginialRecipe" then the child can access it.
 
B

Ben Phillips

Do you need to use B.meth() anywhere? If not then you could override
meth() inside B to throw an UnsupportedOperationException so the
version inherited by Y does not do anything useful?

Override a static method? That would be a neat trick. :)

You can *hide* it, of course...
 
A

Andreas Leitgeb

Roedy Green said:
Mother can preserve the original grandmother method by wrapping it in
a name like "grannysOrginialRecipe" then the child can access it.

If she did that, I'd be less surprised. But mother's class-file doesn't
contain any mention of meth(), nor does granny's alter ego's classfile
(Z$1.class) have one.

The reason behind this thread lies in the dependencies-thread.
I wanted to know, whether private nested classes could have
any impact on other classes. While they can be seen only by
roommate(nested in the same place)classes, any of these might
expose them to public.
The result was: yes, they can, if any of their derivatives
goes public. So even methods of private classes need to be
taken care of (when they're added or removed).
 
B

Ben Phillips

Andreas said:
The result was: yes, they can, if any of their derivatives
goes public. So even methods of private classes need to be
taken care of (when they're added or removed).

When the methods aren't themselves private, anyway.

Private methods can be changed without worrying about direct effects
outside the one source file.

Private classes with package-private methods "leak" the least after
that. Private classes with no non-private descendants in the same source
file should be as safely changeable as private methods. That an instance
might be returned (e.g. from a factory method) and used by an outsider
doesn't change this since there are intermediaries. Like a public method
calling a private method and needing to change if the private method
changes, if this private class changed the method that returned an
instance might need to change, or the interface type that was the return
type might need to change.

That said, it's probably a wart in the JLS that it's permitted for a
non-private class to extend a private class that has public methods.
It's certainly poor encapsulation to have such an arrangement in your
code. Often it's a sign of having used inheritance where composition
would have been the better choice, as is the case in pretty much all
situations where an inherited method is exposed that you feel should not
be exposed. Always consider that an alert that composition is to be
considered as an alternative to the inheritance that is bringing in the
unwanted public method.
 
A

Andreas Leitgeb

rossum said:
Can you run class Y when Y is not public?
It did work, when I tried it :)

For the rest of the posting:
sorry, that was irrelevant due to me not having
explicitly explained my "problem" well enough.
 
A

Andreas Leitgeb

Ben Phillips said:
When the methods aren't themselves private, anyway.
Private methods can be changed without worrying about direct effects
outside the one source file.

Thanks, and sorry for my lateness in answering...
Your posting put my mind back on the right track on
that topic. Java's behaviour now looks more natural
to me than before.

To close up this thread, yet another screwed example:
(no need to followup, unlike you really want to)

---- snip --- Z.java ---
public class Z {
private void meth() {
System.out.println("Hello, World! Z");
}

public static class A extends Z {
public void meth(int i) { // this is *not* an override!
// puzzle: which of the following three lines of code are
// compileable, and which cause an compiler-error?
// guess first, try then (unless you know it anyway).
meth();
Z.meth();
super.meth();
// 'nother one: if these methods were both static,
// which of the previous lines would then be compileable?
}
}
}
class Y {
public static void main(String[]a){ new Z.A().meth(1); }
}
---- snip --- EOF ---
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top