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.
Related
I know I'm asking some serious 101 question here...
I have some class Foo and a class Bar that extends Foo. In Foo I have a constructor that takes a set of parameters that it sets to its fields. Deriving classes such as Bar will typically not need to modify this. Now my IDE is giving me "There is no default constructor available in Foo". From a bit of Googling this appears to be because "constructors are not inherited". So all nice and well, but how do I now get this to work without duplicating this constructor in every deriving class? I'm assuming there is a more sane approach?
Use the super constructor:
public Bar(int a, double b, ...) {
super(a, b, ...);
}
So all nice and well, but how do I now get this to work without duplicating this constructor in every deriving class?
You do need to duplicate the constructor signatures - if you want the subclass to have constructors with the same signatures. But you don't need to duplicate the code - you just chain to the superclass constructor:
public Bar(int x, int y) {
super(x, y);
// Any subclass-specific code
}
Of course if you can work out the superclass parameters from a different set of parameters, that's fine. For example:
public Bar(int x) {
super(x, x * 2);
// Any subclass-specific code
}
You really need to work out what information is required to construct a Bar - that should dictate your constructors.
If this is a problem, it's possible that you're overusing inheritance. It's hard to say for sure without any idea of what your actual classes are, but you should look at using composition instead of inheritance. It's no panacea, but it can avoid this sort of thing.
No, there's no more "sane" approach. If your base class has no default constructor, then you must explicitly call the correct constructor from all the children classes.
Note this doesn't mean children classes need to have the exact same constructor than base class. For example this is perfectly valid:
class Foo {
protected int a;
protected int b;
protected Foo(final int a, final int b) {
this.a = a;
this.b = b;
}
}
class Bar extends Foo {
protected Bar() {
super(0,0);
}
}
The problem is solved with this:
class Foo{
Foo(int a, int b){}
}
class Bar extends Foo{
//Here must be a constructor OR declare a constructor in Foo without parameters
Bar(){super(1,1)} //this is an example
}
Other solution is:
class Foo{
Foo(int a, int b){}
Foo(){}
}
class Bar extends Foo{
}
Remember that if have a constructor with parameters in the SuperClass (in this case Foo), the implicit constructor on the child class (in this case Bar), always will have a implicit call to "Super()" (always have to be one unless explicit).
This error could also happen because you are calling your super constructor last. You might have to move it to be the first statement:
public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
mFragmentList = fragmentList;
super(manager);
}
public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
super(manager); --> this should come first
mFragmentList = fragmentList;
}
JVM will not provide a default constructor if you have provided one due to design reasons. What you can do define constructor in Bar with same signature and call super().
public Bar(int x,int y) {
super(x,y);
}
If parameters are not required and/or have default values then you can define default constructor (without parameters):
class Foo
{
public final int DEFAULT_A = 42;
protected int a;
protected int b;
public Foo(final int a, final int b)
{
this.a = a;
this.b = b;
}
// Is equal to new Foo(Foo.DEFAULT_A, 0);
public Foo()
{
this.a = this.DEFAULT_A;
}
}
class Bar extends Foo {}
class PiBar extends Bar
{
public final int DEFAULT_A = Math.PI;
}
I am running into a problem with javas generics and overriding methods. Imagine I have a deep tree-like class hierarchy. The top-level class defines a method foo which takes 1 argument of type Strategy. Strategy has a generic type parameter.
Each class in my class hierarchy needs to override foo to limit the kind of Strategy it can be passed so that the generic type parameter of the strategy matches the declaring class. Below is an example:
abstract static class TopLevelClass {
static final Strategy<TopLevelClass> s1 = tlc -> System.out.println(tlc.getTopLevelAtt());
String getTopLevelAtt() {
return "TopLevelAtt";
}
void foo(Strategy<TopLevelClass> s) {s.bar(this);}
}
static class MidLevelClass extends TopLevelClass {
static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());
String getMidLevelAtt() {
return "MidLevelAtt";
}
void foo(Strategy<MidLevelClass> s) {s.bar(this);}
}
static class LowLevelClass extends MidLevelClass {
static final Strategy<LowLevelClass> s3 = llc -> System.out.println(llc.getTopLevelAtt());
String getLowLevelAtt() {
return "LowLevelAtt";
}
void foo(Strategy<LowLevelClass> s) {s.bar(this);}
}
static interface Strategy<X> {
void bar(X x);
}
In this example I want to be able to call foo on instances of class LowLevelClass with any of the static references s1, s2 and s3 defined in TopLevelClass, MidLevelClass and LowLevelClass respectively. Ideally I would not have to call different methods foo1, foo2 or foo3 depending on the argument.
The code above does NOT compile in java. The compile-time-error is:
Name clash: The method foo(Strategy) of type MidLevelClass has the same erasure as foo(Strategy) of type TopLevelClass but does not override it
I doubt this can easily be resolved. I could just use raw-types and rely on run-time typechecks but I would rather keep type safety. What can I do to achieve this without sacrificing the type hierarchy or type safety? Please note that passing the Strategy in the constructor IS NOT an option for me! It must be possible to call foo multiple times over the life time of the object.
Edit:
I realize, that this problem is perhaps difficult to follow without knowing the circumstances surrounding it. I have opened a more detailed question explaining the background of my problem here: How to make this Strategy-Object pattern type safe
If you are worried about erasure then just use separate method names for separate methods:
abstract class TopLevelClass {
void fooTop(Strategy<TopLevelClass> s) {/*...*/}
}
class MidLevelClass extends TopLevelClass {
void fooMid(Strategy<MidLevelClass> s) {/*...*/}
}
class LowLevelClass extends MidLevelClass {
void fooLow(Strategy<LowLevelClass> s) {/*...*/}
}
However, I suspect erasure is not your problem. You presumably want to override the same method.
An instance of Strategy<LowLevelClass> cannot possibly be a Strategy<MidLevelClass>, which cannot be a Strategy;
Given
Strategy<LowLevelClass> l;
Strategy<MidLevelClass> m;
Then you cannot assign one to another.
l = m; // Compile-time fail.
m = l; // Compile-time fail.
And therefore it would make no sense to be able to do the same via method overriding. (It's also always been true that bar(TopLevelClass) cannot override bar(MidLevelClass), though since 1.5 there are covariant return types.)
Add a type parameter to the class to use as a type argument in the method.
abstract class TopLevelClass<T extends TopLevelClass<T>> {
void foo(Strategy<T> s) {/*...*/}
}
class MidLevelClass<T extends MidLevelClass<T>> extends TopLevelClass<T> {
void foo(Strategy<T> s) {/*...*/}
}
class LowLevelClass<T extends LowLevelClass<T>> extends MidLevelClass<T> {
void foo(Strategy<T> s) {/*...*/}
}
The updated question add the use of this as a argument to a call of Strategy.foo. This implies MidLevelClass must be abstract - it cannot guarantee foo is overridden. The type of this now needs to fit the type parameter. To do that, add an abstract "getThis" method (concrete in concrete subclasses).
protected abstract X getThis();
...
#Override protected X getThis() { return this; }
The type of the static fields requires wildcards:
static final Strategy<? extends TopLevelClass<?>> s1 =
tlc -> System.out.println(tlc.getTopLevelAtt());
(Better designs prefer composition over inheritance.)
I feel that there a couple of difficulties with this design:
Since each of your class implements its own Strategy using only methods within the same class, there is no need for Strategy.bar() to take an instance of the class. This passing of parameter is one of the causes of the hindrance to implementing this neatly.
Since all the implementations of foo() are doing exactly the same thing, you don't need multiple implementations.
Here is a code that has a partial solution. Partial because, in a good solution, you should be able to pass the reference of TopLevelClass in the changed foo() method. If you can figure out a way for that, I think it will be just great. With this solution, the class hierarchy is not a factor since we are using specific reference types.
I have commented the changed parts starting "CHANGE".
public class Erasure1{
public static void main( String[] args ){
LowLevelClass slc = new LowLevelClass(); //'slc' must be exactly the same type as the instance. This is a limitation with this solution. Ideal thing would have been that this reference be of type TopLevelClass.
slc.foo( LowLevelClass.s3, slc );
}
abstract static class TopLevelClass{
static final Strategy<TopLevelClass> s1 = tlc -> System.out.println( tlc.getTopLevelAtt() );
String getTopLevelAtt(){ return "TopLevelAtt"; }
/* CHANGE 1: It is necessary that the instance of TopLevelClass subtype be passed since
* Strategy.bar() doesn't accept wildcards. Changing it to accept a 'T' to pass to bar().
* Also, since, this is now taking 'T' as a parameter, this method could very well be a
* static method in a utility class. */
<T> void foo( Strategy<T> s, T tlc ){
s.bar( tlc );
}
}
static class MidLevelClass extends TopLevelClass{
static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());;
String getMidLevelAtt(){ return "MidLevelAtt"; }
/* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
//void foo(Strategy<MidLevelClass> s) {s.bar(this);}
}
static class LowLevelClass extends MidLevelClass{
static final Strategy<LowLevelClass> s3 = llc -> System.out.println( llc.getLowLevelAtt() );
String getLowLevelAtt(){ return "LowLevelAtt"; }
/* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
//void foo(Strategy<LowLevelClass> s) {s.bar(this);}
}
static interface Strategy<X> {
void bar( X x );
}
}
I have a super class named TestSuper
public class TestSuper {
int a = 0;
}
and I have 2 sub classes named TestSub and TestSub2 that extend TestSuper
public class TestSub extends TestSuper{
int a=1;
}
public class TestSub2 extends TestSuper{
int a=2;
}
in my main class i created a method that takes in a type TestSuper and returns the a value of it and in the main i display it on the console
public class Main {
public static void main(String[] args){
System.out.println(test(new TestSub())+" "+test(new TestSub2()));
}
public static int test(TestSuper b){
return b.a;
}
}
but the output is "0 0" instead of "1 2", what do I do?
You need to cast the reference so say which one you want.
public static int test(TestSuper b){
return b instanceof TestSub ? ((TestSub) b).a :
b instanceof TestSub2 ? ((TestSub2) b).a :
b.a;
}
If this seems needlessly complicated, it is. You should use polymorphism instead.
public class TestSuper {
int a = 0;
public int getA() { return a; }
}
public class TestSub extends TestSuper {
int a = 1;
public int getA() { return a; }
}
public class TestSub2 extends TestSuper {
int a = 2;
public int getA() { return a; }
}
public static int test(TestSuper b) {
return b.getA();
}
First understand the difference between hiding and overriding: https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Then create a getter method in the base-class which you can override in the subclass.
You can look into the theory behind this, and then do the only reasonable thing -forget about writing such kind of code.
In good OOP you consider your fields to be part of your "secret" internal implementation. You don't use fields of sub classes in the super class context. Period.
You are even very conservative about making a field protected in the superclass and to use that in subclasses.
When you call test method like this:
test(new TestSub())+" "+test(new TestSub2())
You use upcasting. Upcasting seperates interface and implementation for an object. But for seperating interface and implementation and achieving true implementation in polymorphism, you must use polymorphic structures. The instance variables aren't polymorphic. Because of this, actually you call a variable which is in TestSuper class.
Only instance methods are polymorphic.
I know there have been lots of thread about Java inheritance (and i already read it), but they all stand for "how it is", and I need knowledge "how to change it". So, we have 2 classes:
class t1{
public int a=5;
public void get(){
System.out.println(a);
}
}
class t2 extends t1{
public int a = 1;
}
and now :
t2 z = new t2();
z.get();
And we get 5
Of cource it is just example, but what i want to do is make some common methods in superclass which will use field from inherited class, ex. user messages
Is there any way to do this? If not then why i would use superclasses, can i use anything else?
Thanks in advance
You should use a constructor and possibly a getter
class t1{
public final int a;
public t1() {
this(5);
}
protected t1(int a) {
this.a = a;
}
public void get(){
System.out.println(a);
}
}
class t2 extends t1{
public t2() {
super(1);
}
}
now
t2 z = new t2();
z.get();
prints 1
Yes, there is a way do to this. You can apply pattern which called "Template method". Here is an example
class Base {
void someMethod() {
int value = getValue();
// calculate something
}
protected abstract int getValue();
}
class Derived extends Base {
int getValue() {
return 5;
}
}
Where getValue() is your template method and you can insert any logic in your inherited classes implementations.
you are shadowing/hiding the variable of t1!
t1 can see the variable of t2 and prints it's own a-value in the get method.
you don't need to declare a again because the a of t1 can be seen everywhere
if you want another default value for a in object of type t2 override the default constructor.
public t2() {
this.a = 1;
}
Polymorphism works only for methods, not for fields and you cant change this Java mechanism. It means that late binding will find correct body of method depending on class of object
class X{
void sayHello(){
System.out.println("Hello from X");
}
}
class Y extends X{
void sayHello(){
System.out.println("Hello from X");
}
}
//...
X obj = new Y();
obj.sayHello();// even if you are using X reference body of method will
// come from Y class
But fields are not polymorphic so if method uses some field it will use this field all the time (once again, late binding will not search for newest field declared in class of current object). That is why you are seeing 5 as result.
If you want to simulate" polymorphic behaviour of field used in methods body your best choice is to let derived class set new value of that field in base class like in Peter Lawrey's answer (big +1 for him).
Why can't I cast a base class instance to a derived class?
For example, if I have a class B which extends a class C, why can't I do this?
B b=(B)(new C());
or this?
C c=new C();
B b=(B)c;
Alright let me be more specific as to what I'm trying to do. Here's what I have:
public class Base(){
protected BaseNode n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode(){
public void foo(BaseNode x){...}
}
Now I want to create a new set of classes which extend Base and Basenode, like this:
public class Derived extends Base(){
public void bar(DerivedNode x){
n.bar(x);//problem is here - n doesn't have bar
}
}
public class DerivedNode extends BaseNode(){
public void bar(BaseNode){
...
}
}
So essentially I want to add new functionality to Base and BaseNode by extending them both, and adding a function to both of them. Furthermore, Base and BaseNode should be able to be used on their own.
I'd really like to do this without generics if possible.
Alright so I ended up figuring it out, partly thanks to Maruice Perry's answer.
In my constructor for Base, n is instantiated as a BaseNode. All I had to do was re-instantiate n as a DerivedNode in my derived class in the constructor, and it works perfectly.
because if B extends C, it means B is a C and not C is a B.
rethink what you are trying to do.
The existing answers are fine in terms of an abstract argument, but I'd like to make a more concrete one. Suppose you could do that. Then this code would have to compile and run:
// Hypothetical code
Object object = new Object();
InputStream stream = (InputStream) object; // No exception allowed?
int firstByte = stream.read();
Where exactly would the implementation of the read method come from? It's abstract in InputStream. Where would it get the data from? It simply isn't appropriate to treat a bare java.lang.Object as an InputStream. It's much better for the cast to throw an exception.
In my experience it's tricky to get "parallel class hierarchies" like the one you're describing to work. You may find that generics help, but it can get hairy very quickly.
You need to use the instanceof keyword to check the type of object referenced by n and typecast the object and call the bar() method. Checkout Derived.bar() method bellow
public class Test{
public static void main(String[] args){
DerivedNode dn = new DerivedNode();
Derived d = new Derived(dn);
d.bar( dn );
}
}
class Base{
protected BaseNode n;
public Base(BaseNode _n){
this.n = _n;
}
public void foo(BaseNode x){
n.foo(x);
}
}
class BaseNode{
public void foo(BaseNode x){
System.out.println( "BaseNode foo" );
}
}
class Derived extends Base{
public Derived(BaseNode n){
super(n);
}
public void bar(DerivedNode x){
if( n instanceof DerivedNode ){
// Type cast to DerivedNode to access bar
((DerivedNode)n).bar(x);
}
else {
// Throw exception or what ever
throw new RuntimeException("Invalid Object Type");
}
}
}
class DerivedNode extends BaseNode{
public void bar(BaseNode b){
System.out.println( "DerivedNode bar" );
}
}
You can create a constructor for B that takes C as a parameter.
See this post for ideas to do what you're trying to do.
Base classes shouldn't know anything about classes derived from them, otherwise the problems highlighted above will arise. Downcasting is a 'code smell', and downcasting in the base class to a derived class is particularly 'smelly'. Such designs can lead to difficult to resolve circular dependencies too.
If you want a base class to make use of derived class implementations use the Template method pattern i.e add a virtual or abstract method in your base class and override and implement it in the derived class. You can then safely call this from the base class.
You can't do that because C does not necessarily implement the behaviours you created when you extended it in B.
So, say C has a method foo(). Then you know that you can call foo() on a B, as B extends C, so you can cast accordingly a treat a B as if it was a C with (C)(new B()).
However - if B has a method bar(), nothing in the subclass relationship says that you can call bar() on C too. Thus you cannot treat a C as if it were a B, and so you cannot cast.
In your exemple, you can cast n into a DerivedNode if you are certain that n is an instance of DerivedNode, or you can use generics:
public class Base<N extends BaseNode> {
protected N n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode {
public void foo(BaseNode x){...}
}
public class Derived extends Base<DerivedNode> {
public void bar(DerivedNode x){
n.bar(x); // no problem here - n DOES have bar
}
}
public class DerivedNode extends BaseNode {
public void bar(BaseNode){
...
}
}
Because if B extends C, then B might have stuff that isn't in C (like instance variables you initialize in the constructor that are not in new C())