This is a very odd question, so please bear with me.
I'd like to know if the Java specification guarantees that an overriding method in two subclasses is resolved via identical mechanisms in each. In other words, if I have
public class Foo {
public int frob() {
return 7;
}
}
public class Bar extends Foo {
#Override
public int frob() {
return 8;
}
}
public class Baz extends Foo {
#Override
public int frob() {
return 9;
}
}
and a method somewhere:
public static int quux(Bar b) {
return b.frob();
}
which I know only calls .frob() on b, how safe is it to call quux((Bar)new Baz())?
quux((Bar)new Baz()) will not even compile. (Cannot cast from Baz to Bar since Baz IS-NOT a Bar).
- Bar IS-A Foo, and Baz IS-A Foo.
- But neither Bar is a Baz nor Baz is a Bar, so this casting won't work.
Related
I've inherited some code, and I'm trying to refactor it in an attempt to clean it up.
This is a simplified case of how I received the code:
public class Foo
{
private void doSomething()
{
someOtherAction(Foo.this);
}
protected class FooChildClass
{
protected void anotherAction()
{
createDialogBox(Foo.this);
}
}
}
//totally not related to class Foo even though most code is duplicated
public class Bar
{
private void doSomething()
{
someOtherAction(Bar.this);
}
protected class BarChildClass
{
protected void anotherAction()
{
createDialogBox(Bar.this);
}
}
}
Now, here's the catch - after further examination of the code, Bar is almost a carbon-copy of Foo with some slight changes here and there.
I'd like to condense my code into something like this:
//superclass
public class Foo
{
protected void doSomething()
{
someOtherAction(Foo.this);
}
protected class ChildClass
{
protected void anotherAction()
{
createDialogBox(Foo.this);
}
}
}
//inherits from Foo and only overrides when necessary
public class Bar extends Foo
{
//rely on base implementation of doSomething
//override other functions only when necessary
}
Will my condensed code run successfully? I have a C# background, so I understand a good bit of Java syntax, but C# doesn't have anything similar to ClassName.this.
I'm figuring that ClassName.this is meant to resolve scoping issues by defining what 'this' is intended - and that with my modified code, Bar is indeed a Foo object too - but I figure I would ask to be sure!
Edited original question for clarification
Foo.this is equivalent to this. Therefore your condensed code is Okay with no requirement of being changed.
The following test code is to test your updated program:
Foo f = new Foo();
Foo.ChildClass fc = f.new ChildClass();
f.doSomething();
fc.anotherAction();
Bar b = new Bar();
Bar.ChildClass bc = b.new ChildClass();
b.doSomething();
bc.anotherAction();
The output is:
Foo#52e922
Foo#52e922
Bar#25154f
Bar#25154f
Referring to your most recent edit I composed the following example:
public class Foo {
public void printMe() {
System.out.println("I'm foo");
}
public class Child {
public void printMe() {
Foo.this.printMe();
}
}
}
public class Bar extends Foo {
#Override
public void printMe() {
System.out.println("I'm bar");
}
}
public class Main {
public static void main(String[] args) {
new Bar().new Child().printMe();
}
}
The result was:
I'm bar
Which concludes, that Foo.this.printMe() does not statically refer to the outer class Foo, but to the outer instance of the Child instance, which in this case is an instance of Bar.
For further reading:
The Classname.this syntax is used for inner classes.
You can use the following example to try a bit around and see its effects:
public class Foo {
private int value = 1;
public class Bar {
private int value = 2;
public void printValue() {
System.out.println(Foo.this.value);
}
}
}
Regarding derivation, there's no way to explicitly refer to a certain super type in java, like in C. However, you can refer to your super class using the super keyword.
With java 1.8 and default interface methods, the Classname.super syntax was introduced:
public interface Foo {
default int getValue() {
return 1;
}
}
public interface Bar {
default int getValue() {
return 2;
}
}
public class Impl implements Foo, Bar {
#Override
public int getValue() {
return Bar.super.getValue();
}
}
However, you can still only refer to direct super types. Everything other will be denied by the compiler.
At work I came across the following design in a java project:
Consider interfaces Foo, Bar, and Baz as follows:
interface Bar { public int a(); }
interface Baz { public int b(); }
interface Foo extends Bar, Baz { public int c(); }
Now, consider class FooImpl:
public class FooImpl implements Foo {
private Bar bar;
private Baz baz;
public int a() {
return bar.a();
}
public int b() {
return baz.b();
}
public int c() {
return 0;
}
}
What are the use cases for this kind of class hierarchy? It seems to me that this introduces a lot of boilerplate and does not add much in terms of abstraction, other than breaking up what could be a large file into smaller files.
It allows things like this:
Foo foo = new FooImpl();
useBar(foo);
public void useBar(Bar bar) {
bar.a();
}
Whether this is useful depends on the real context. Your example code with classes and methods with meaningless names does not support a rational judgement.
The other thing to note is your FooImpl is actually implemented as some kind of wrapper for Bar and Baz instances. That's not (strictly speaking) an interface design issue.
I think it's a workaround for multiple inheritance (which is not allowed in Java). You're not showing implementations for Bar and Baz, but let's suppose they exist:
public class BarImpl implements Bar {
#Override
public int a() {
return 1;
}
}
public class BazImpl implements Baz {
#Override
public int b() {
return 2;
}
}
You neither have told us how Bar and Baz attributes are instantiated and set to FooImpl, because, if executed as stated in your question, you'll get a NullPointerException both in FooImpl.a() and FooImpl.b(). Again, let's imagine how this could be achieved:
public class FooImpl implements Foo {
private Bar bar; // better if final
private Baz baz; // better if final
// Constructor to properly initialize bar and baz
public FooImpl(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
#Override
public int a() {
return bar.a();
}
#Override
public int b() {
return baz.b();
}
#Override
public int c() {
return 0;
}
}
Wiring everything up:
Bar bar = new BarImpl();
Baz baz = new BazImpl();
Foo foo = new FooImpl(bar, baz);
int one = foo.bar(); // 1
int two = foo.baz(); // 2
In a way, FooImpl is "inheriting" from both BarImpl and BazImpl, though this is achieved by means of delegation.
To do this is really just redirecting fooimpl using its propertie's(bar and baz) "a" method and "b" method
I had a problem I could actually solve myself, but I still don't understand why my original code doesn't work, or if there is a more elegant solution than the one I found. I'm presenting a simplified version of my code here.
Consider the following abstract superclass X:
public abstract class X{
private int i;
public void m1(X x){
x.i = 1;
m2(x);
}
public abstract void m2(X x);
}
When m1 is called, we manipulate a private field of X of the instance passed, and then we call m2 with that instance.
I have several subclasses of X, they are all alike in the sense that they also declare private members which they manipulate. In order to achieve that, they always need to make a cast at the beginning of m2. Here is one of them:
public class Y extends X{
private int j;
public void m2(X x){
Y y = (Y) x;
y.j = 0;
}
}
But - I can guarantee that every call of m1 of an instance of a subclass of X will always have a parameter that is of the same type, e.g. when I have an instance of Y, the parameter of the method m1 will always be another instance of Y.
Because of that guarantee, I wanted to make the cast unnecessary, by introducing generics. This is how I want my subclasses to look like:
public class Y extends X<Y>{
private int j;
public void m2(Y y){
y.j = 0;
}
}
How does the superclass X have to look like now? My first try was that:
public abstract class X<T extends X<T>>{
private int i;
public void m1(T x){
x.i = 1;
m2(x);
}
public abstract void m2(T x);
}
But - that doesn't work, when I compile this, I get the following error:
X.java:6: error: i has private access in X
That's usually what you get you try to access the private members of another class. Obviously, Java doesn't recognise that T is always an instance of X as well, although I used "T extends X" in the declaration.
I fixed X like this:
public abstract class X<T extends X<T>>{
private int i;
public void m1(T x){
X<?> y = x;
y.i = 1;
m2(x);
}
public abstract void m2(T x);
}
At least I'm not using casts any more - but why is this extra assignment necessary? And why didn't the original code work? Also, I found it strange I had to use X<?> and could not use X<T>.
I believe we can reduce your question down to: Why does the following example fail to compile?
public class Foo {
private final String bar = "bar";
public <T extends Foo> void printFoo(T baz) {
System.out.println(baz.bar); //bar is not visible
}
}
It's a great question, and it sure took me by surprise. But we can actually remove Generics from the equation by noting that this doesn't work either:
public class Foo {
private final String bar = "bar";
public void printFoo(SubFoo baz) {
System.out.println(baz.bar); //bar is not visible
}
}
class SubFoo extends Foo {
}
In other words, the issue is that you're dealing with a subclass of Foo, not Foo itself. In the case of T, we don't know which subclass, but we know it is a subclass, or Foo.
As you've already figured out, the solution (surprisingly, at least to me) is to upcast:
System.out.println(((Foo)baz).bar);
Or for the Generic case:
public <T extends Foo> void printFoo(T baz) {
System.out.println(((Foo)baz).bar);
}
Is the cast so bad? Not really. It's certainly as good or better than avoiding the cast with an intermediate variable. As with any upcast, I would assume it would be removed by the compiler. It exists only as a hint to the compiler. We certainly don't have to worry about the safety of the cast, because the erasure of T is already Foo.
I can only assume this restriction is required so as to be clear about the access...since SubFoo could redeclare bar itself, it could become ambiguous which bar is being referred to, and so the cast is necessary. This is demonstrated in this complicated example:
public class Foo {
private final String bar = "hello";
static class SubFoo extends Foo {
private final String bar = "world";
}
public <T extends SubFoo> void printFoo(T baz) {
// System.out.println(baz.bar); // doesn't compile
System.out.println(((Foo)baz).bar); //hello
System.out.println(((SubFoo)baz).bar); //world
}
public static void main(String[] args) {
new Foo().printFoo(new SubFoo()); //prints "hello\nworld"
}
}
In this regard, it serves more as a qualifier than as a cast.
This is what I'm trying to do (in Java 1.6):
public class Foo {
public Foo() {
Bar b = new Bar();
b.setSomeData();
b.doSomethingElse();
this(b);
}
public Foo(Bar b) {
// ...
}
}
Compiler says:
call to this must be first statement in constructor
Is there any workaround?
You could implement it like this:
public class Foo {
public Foo() {
this(makeBar());
}
public Foo(Bar b) {
// ...
}
private static Bar makeBar() {
Bar b = new Bar();
b.setSomeData();
b.doSomethingElse();
return b;
}
}
The makeBar method should be static, since the object corresponding to this is not available at the point you are calling the method.
By the way, this approach has the advantage that it does pass a fully initialized Bar object to the Foo(Bar). (#RonU notes that his approach does not. That of course means that his Foo(Bar) constructor cannot assume that its Foo argument is in its final state. This can be problematical.)
Finally, I agree that a static factory method is a good alternative to this approach.
You can implement the "default constructor" as a static factory method:
public class Foo {
public static Foo createFooWithDefaultBar() {
Bar b = new Bar();
b.setSomeData();
b.doSomethingElse();
return new Foo(b);
}
public Foo(Bar b) {
// ...
}
}
Like it says, a call to this() must be the first thing to happen in a constructor. Is there any reason this wouldn't work?
public class Foo {
public Foo() {
this(new Bar());
Bar b = getBar();
b.setSomeData();
b.doSomethingElse();
}
public Foo(Bar b) {
// ...
}
}
Given a class "Bar" that extends class "Foo" which implements interface "DeeDum"
public interface DeeDum {
public String getDee();
public String getDum();
}
public class Foo implements DeeDum {
public String dee = "D";
public String dum;
public String getDee() { return dee; }
public String getDum() { return dum; }
}
public class Bar extends Foo {
public String dee = "DEE";
public String dum = "DUM";
}
Why doesn't this work?
public static Bar mybar = new Bar();
Assert.assertEquals("DEE", mybar.getDee());
Assert.assertEquals("DUM", mybar.getDum());
I get "D" and null instead. In other words, Bar doesn't inherit accessors from Foo, and can't override properties. Somehow calling mybar.getDum() calls a static instance of class Foo and returns the static properties from the parent class. Even if the properties are overridden in the child class! Does that mean that you can't inherit any methods or properties?
I can't wrap my head around it. Why can't Java inherit accessors (and why did they choose such an odd alternative?)
Or am I just doing something wrong?
Actually, I'm seeing something weird and undeterministic still. If you have another class 'Bar' that extends Foo and sets the inherited accessors in an initialization block
While you can set the parent property in the above block, it doesn’t actually create a copy for the child class.
It seems to be a non-deterministic initialization for multiple classes.
So if you have Bar and Baz which both extend foo and have an initialization block, it seems like both inherit the value set by Bar.
public class Bar extends Foo {
{
dee = "dee";
dum = "dum";
}
}
public class Baz extends Foo {
{
dee = "DEE";
dum = "DUM";
}
}
public static Bar bar = new Bar();
public static Baz baz = new Baz();
System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum()); // DEEDUM
System.out.println("mybar: " + mybar.getDee() + mybar.getDum()); // DEEDUM
but if they're instantiated in a different order, I get:
public static Baz baz = new Baz();
public static Bar bar = new Bar();
System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum()); // deedum
System.out.println("mybar: " + mybar.getDee() + mybar.getDum()); // deedum
And it comes out still differently if a default is set in the base class Foo.
I think I understand now that the initialization block in Bar and Baz is actually setting Foo::dee and Foo::dum, but why the difference in declaration? Seems "undefined" to me.
The problem is that your duplicate declaration of the members dee and dum of Foo in Bar hides those of Foo. Bar has its own members; those of Foo will never be used by Bar. What you mean is something like
public class Bar extends Foo {
{
dee = "DEE";
dum = "DUM";
}
}
You are hiding the inherited variables with ones defined in the subclass.
public class Bar extends Foo {
public Bar() {
dee = "DEE";
dum = "DUM";
}
}
should work better.
When you call mybar.getDee(), you're calling the method defined in the Foo base class. (That method was inherited by Bar. Otherwise, you wouldn't have been allowed to call it on a Bar instance variable in the first place.) That method returns the value of the dee field, but it's the dee field defined in the Foo class — the class where the method itself was defined. The compiler resolved the reference to the field at the time the method was compiled, in the Foo class.
Some other answers have used the word override to define what you did by declaring a field named dee in Bar, but that's not what happened. You can't override a field because fields aren't virtual. Perhaps you thought they were, though. If there were such a thing as a "virtual field," I too might expect getDee() to return the run-time class's version of the field (the one in Bar) instead of the one that was in scope at the time the method was compiled (Foo's). But that's simply not the way Java (or C#, or C++, or Delphi, or any other language I know of) works. What language are you accustomed to where this would have worked?
Accessor methods themselves (e.g. getDee()) are inherited, but instance variables are not.
If instance variables could be overridden in subclasses (like you're trying to do here), it would cause many more problems than it would fix.
Accessors aren't the problem, it's the fields. The accessors are referring to Foo.this.dee, not to Bar.this.dee which are separate.
As for your second "question"...
Actually, I'm seeing something weird and undeterministic still...
...
"...System.out.println(baz.getDee()); // 'DEE' but would expect 'dee'"
It would be useful if you run the program before posting the question to see actual results.
This is what I get. It is "dee" as you expected.
You could see it for your self by creating the files, compiling them and the run them as shown below:
C:\oreyes\samples\java\dee>type DeeDum.java Foo.java Bar.java Baz.java Test.java
DeeDum.java
public interface DeeDum {
public String getDee();
public String getDum();
}
Foo.java
public class Foo implements DeeDum {
public String dee = "D";
public String dum;
public String getDee() { return dee; }
public String getDum() { return dum; }
}
Bar.java
public class Bar extends Foo {
{
dee = "DEE";
dum = "DUM";
}
}
Baz.java
public class Baz extends Foo {
{
dee = "dee";
dum = "dum";
}
}
Test.java
class Test {
public static Bar bar = new Bar();
public static Baz baz = new Baz();
public static void main( String [] args ) {
System.out.println(bar.getDee()); // 'DEE'
System.out.println(baz.getDee()); // 'DEE' but would expect 'dee'
}
}
C:\oreyes\samples\java\dee>javac *.java
C:\oreyes\samples\java\dee>java Test
DEE
dee
C:\oreyes\samples\java\dee>
PEBKAC?