I have come across a weird piece of code. I was wondering if there is any usage for it.
class C extends B {
int xB = 4;
C() {
System.out.println(this.xB);
System.out.println(super.xB);
System.out.println(((B)this).xB); // This is the weird code.
}
}
Program prints 4, 10, 10. public xB field of class B has the value 10.
In Java, you can only directly inherit from a single class. But you can have multiple indirect superclasses. Could this be used in upcasting the "this" reference to one of those? Or is this bad programming practice and i should forget about it?
So "((B)this)" basically acts as if it is "super". We could just use super instead of it.
It does NOT generally do the same thing as super.
It does in this case, because fields do not have dynamic dispatch. They are resolved by their compile-time type. And you changed that with the cast.
But super.method() and ((SuperClass)this).method() are not the same. Methods are dispatched at runtime based on the actual type of the instance. The type-cast does not affect this at all.
I was wondering if people are using this structure to upcast "this" to indirect superclasses.
They don't have to, because they don't duplicate field names like that.
It is bad practice to shadow an inherited (visible) field in a subclass (exactly because it leads to confusion like this). So don't do that, and you want have to have this cast.
And you cannot "upcast to indirect superclasses" at all where methods are concerned: You can call super.method() directly (if you are in the subclass), but not something like super.super.method().
this is an instance of C, it can be upcasted to its direct (e.g. B) or indirect (e.g Object) parent.
C c = this;
B b = (B)c;
Object o = (Object)c;
Is this bad programming practice and I should forget about it?
It's a workaround since polymorphism doesn't work for fields. It's a bad practice. Why would C need to declare xB if it's already defined in B and B can grant access to its subclasses to access and work with the field? It's weird, indeed.
Related
apologies if this is simple or has been answered before, I'm new to Java and in my research I can't find too much on this issue and have not yet found a solution.
I have an ArrayList with multiple classes that all share a common Interface, in this example the interface is called "Packable". I'm trying to create a method that takes a class parameter and sweeps through each element of this ArrayList, returning a new list containing all the items in the original list that are of the same class as the reference parameter.
This is my code so far, trying the instanceof method:
public List<Packable> getOfType(Packable reference){
List<Packable> typeOfItems = new ArrayList<>();
for (Packable item: itemsStored) {
if (item instanceof reference){
typeOfItems.add(item);
}
}
return typeOfItems;
}
This is throwing an error as it doesn't yet recognise reference as a class. This question mentions a method isAssignableFrom with the answer stating: "When using instanceof, you need to know the class of B at compile time. When using isAssignableFrom() it can be dynamic and change during runtime." (Thanks Marc Novakowski)
I understand that given the parameter the class isn't known at compilation and as such I've tried implementing isAssignableFrom and can't really seem to get it to work. The IDE doesn't really recognise or suggest it, and there isn't too much about the method online. I've tried implementing it the way the JavaDocs suggest but this isn't working either:
if (reference.isAssignableFrom(item.getClass())){
typeOfItems.add(item);
}
Any help or advice on methods to look into would be greatly appreciated. Thanks for reading the question, and again apologies if this is simple or has been answered elsewhere and I've just missed it. Thanks everyone
I'm not sure what Packable is, but you appear to be confused about a few concepts here.
In java, Packable reference does not represent the Packable concept. It represents a specific instance of Packable (or null).
In other words, given Dog dog, that means dog is some specific dog. Not 'the general concept of a dog'. We know that the specific animal that dog is referring to is, at least, a Dog. It could be Fifi, the neighbour's schnauzer.
instanceof, on the other hand, is about the general concept of things: if (fifi instanceof Dog) is how you're supposed to use it. You're more or less attempting to do the equivalent of if (fifi instanceof rover) which just doesn't make sense. How can one dog be 'an instance' of another? It's not that the answer is 'true' or 'false', but that the very question doesn't even make sense, which is why javac doesn't compile it. It has no idea what this even means.
Java, being java, makes objects of many things. Notably including the very notion of things. Thus, there is the class java.lang.Class, instances of which represent classes. A bit of alice-going-down-the-rabbit-hole thing is happening here: Classes as a concept are also represented as instances of the java.lang.Class class.
A class OBJECT (so, an instance of java.lang.Class) has the .isAssignableFrom method. This in fact takes another j.l.CLass as argument, it's for checking if one type is a subtype of another. In that sense, the question linked is needlessly confusing - you're really looking for the instanceOf method (there is an instanceof language construct, but the j.l.Class class has an isInstance method, which is unrelated, other than that they roughly accomplish the same goal: Check if some INSTANCE is of a type that is equal to, or a subtype of, some TYPE.
This is an example of how to use it:
Class<?> c = Number.class;
Object o = Integer.valueOf(5);
System.out.println(c.isInstance(o));
this is more or less equivalent to:
Object o = Integer.valueOf(5);
System.out.println(o instanceof Number);
Except now the Number part no longer needs to be written at 'write the code' time, you can supply it, say, read it from a parameter. You'd have to, of course, dynamically construct the Class instance. You can do so either by string-lookup, or by getting the actual type of an actual object. For example:
String input = scanner.next(); // user types in "java.lang.Number"
Class<?> c = Class.forName(input);
Object o = Integer.valueOf(5);
System.out.println(c.isInstance(o));
Or:
Object i = Integer.valueOf(5);
Object d = Double.valueOf(10);
Class<?> c = i.getClass(); // will be java.lang.Integer.class
System.out.println(c.isInstance(d)); // false
But doing this latter bit is really dangerous. Often i.getClass() returns some hidden impl detail subtype (java is hierarchical and object oriented, anywhere, say, an ArrayList is needed, someone is free to make a new class: class MyVariantOfArrayList extends ArrayList, and use that - now you write ArrayList foo = getList(), but foo.getClass() doesn't return ArrayList - no, you invoke that method on the object the foo variable points at, so, it'd be MyVariantOfArrayList.class, not ArrayList.class.
It's possible Packable itself represents a type. But then it either needs to also have isInstance and isAssignableFrom and such (and you need to start questioning why you're badly reinventing the wheel here - java.lang.Class already exists!), or it needs a .getRepresentedClass() method. You can't call it .getClass(), as the JVM has already given all objects that method, and it would return Packable.class itself.
This question already has an answer here:
What happens in the heap when class A inherits class B in Java
(1 answer)
Closed 3 years ago.
Consider a Superclass A and a derived class B whereas A contains a private variable x. B contains an explicit super() call as first argument inside its constructor while there might be some other variables of B like y and z. As far as I know there is no inheritance for private fields. Does that mean private fields will not get instantiated while executing:
B b = new b();
My question is: How does the heap look like after running the above code? Of course there will be y and z, but what about x in this case?
Field inheritance and field visibility are two separate concepts, not to be confused.
Field inheritance
In a way (to simplify a bit), a class is a template from making objects. So if a class A declares two fields f1 and f2, then instantiating A creates objects (and allocates memory for them on the heap) that have these two fields.
A subclass is also a template for making objects, but this template is expressed as an addition to another class. So if class B declares field f3 and extends A, it's basically saying, "take all the fields that A defines, and add f3". So instantiating B results in an object with three fields f1, f2, f3.
Field Visibility
Field visibility, as expressed through access modifiers like private and public, is a way to control which part of the code "sees" (or can refer to) a certain field. The private modifier means that no code outside of the class that declares the field can refer to this field. However, it doesn't mean that the field stops existing. To make a dodgy parallel, if you and another person are in a room and you turn off the light, you can't see the other person, but they are still there.
To emphasize the point that the concepts are separate, consider that in some cases you can see fields that are not inherited (e.g., because they are non-private, but in a class not in the same class hierarchy). And in some cases you can't see fields that are inherited, as in the case of private fields in the superclass.
The private field defined in the super class is instantiated when a statement does that.
The fact that you manipulate a subclass doesn't change anything on this point. The field is always existing and instantiable, just the subclass cannot access it directly.
If the field of the super class was not instantiable, the Java inheritance would make not any sense since the subclasses would be not consistent or even unusable as superclass methods will not work any longer.
For example :
private int x;
A(){
this.x = getIntValue();
}
int getX(){return x;}
And B the subclass :
B(int x){
super(); // in the compiled code even if not in the source code
}
new B().getX() will of course return the value of x instantiated in the superclass.
Since many constructors also call the superclass constructor, it seems like one could think that both the subclass and the superclass are instantiated when a subclass is instantiated; i.e. more than one object is created.
Is still just one object created?
Thank you
Just one object, even if the super's constructor is called you are just performing additional instantiation on the one object.
Yes only one object is created
Just one object is created in memory.
At least one object is created. Who knows how many objects are created in the constructor?
class X extends Y
{
Object [ ] objects ;
X ( int n )
{
super ( ) ;
objects = new Object [ n ] ;
for ( int i = 0 ; i < n ; i ++ )
{
objects [ i ] = new Object ( ) ;
}
}
}
Einstein is attributed a saying: explanations should be as simple as possible, but no simpler. The simple answer 'only one object' may be perhaps true, but misses a lot of important information.
As Nick asked, we can invoke the superclass constructor. So that the superclass constructor is 'somewhere', even though I instantiated only the subclass. Is easy to reason that the instance of the subclass must include all the members of the superclasses (all of them, up to Object). In principle all this pile of variables and methods is the subclass instance. These variables and methods must include also variables not inherited by the subclass. So that the instance is not just what the subclass declares or inherits. I.e. a Cat is-a Mammal, even if Mammal declares some member that Cat doesn't inherit (a poor Java design decision, IMO).
For example, if the superclass has a private variable 'priv', and public accessors getPriv() setPriv(), subclass can invoke the accessors, therefore accessing the variable, modifying state, etc. Yet 'priv' itself is not anywhere to be found in the subclass .class file. So that there is more to the instance than 'just the class'.
I leave to some other discussion the rationale behind 'subclass doesn't inherit private members, etc.'. Never made any sense to me (the instance variables are this instance's; so what access control are you talking about? an object can't access its own parts?! ... anyways ... that was the designers decision)
BTW the JVM spec says nothing (and indeed, shouldn't say anything) about how to implement the inheritance semantics. One possible solution (which may or may not be what any of the JVMs do) would be to create full instances of all the ancestor classes when an instance of the subclass is created. Why not?. It is unlikely anyone will come with an authoritative source declaring that this shall not be done. Certainly the JVM spec doesn't say that.
If someone can contribute a pointer to actual JVM implementation information on this topic, that would be illuminating. I couldn't find it by google'ing. Neither could find an authoritative confirmation of the 'just one object' assertion. May be. I don't know. Conceptually, as a Java language construct? sure! but with 'clarifications'. Implementation-wise, i.e. 'in memory'? may be, may be not.
-Polo
HI,
I have a down casting question, I am a bit rusty in this area.
I have 2 clasess like this:
class A{ int i; String j ; //Getters and setters}
class B extends A{ String k; //getter and setter}
I have a method like this, in a Utility helper class:
public static A converts(C c){}
Where C are objects that are retireved from the database and then converted.
The problem is I want to call the above method by passing in a 'C' and getting back B.
So I tried this:
B bClasss = (B) Utility.converts(c);
So even though the above method returns A I tried to downcast it to B, but I get a runtime ClassCastException.
Is there really no way around this? DO I have to write a separate converts() method which returns a B class type?
If I declare my class B like:
class B { String k; A a;} // So instead of extending A it has-a A, getter and setters also
then I can call my existing method like this:
b.setA(Utility.converts(c) );
This way I can reuse the existing method, even though the extends relationship makes more sense. What should I do? Any help much appreciated. Thanks.
The cast from type A to type B:
B bClasss = (B) Utility.converts(c);
doesn't work because objects of type A don't have all the methods that might be called from references of type B. What would you expect to happen if you called
bClasss.getK();
on the next line? The underlying object has no member variable k, so this cast is not allowed.
You can use references of the higher types in your class hierarchy to refer to objects of lower types, but not the other way around.
Without knowing more, I think the best thing to do is implement multiple methods
A aObj = Utility.convertToA(c);
B bObj = Utility.convertToB(c);
If B extends A, then you should still benefit from some code reuse in the constructors of your classes.
What's important here is what Utility.converts() actually returns - if it doesn't create a new B object and return it, there's no way to get a B from it.
(since you're getting ClassCastException, then it doesn't create B inside)
You should work in the appropriate level of abstraction and write your method signatures to do the same. If the public/default interface of B is modified that heavily from A, then your method signature really should be returning a B. Otherwise, ditch trying to cast it, assign the result of .converts to a variable of type A, and treat it like an A even though it's true type is really a B. You would be defeating the point of abstracting through inheritance if you are trying to downcast here.
Without seeing your source code, I have no clue whether or not it makes sense to use composition in lieu of inheritance here. The above paragraph assumes what you say about "extends relationship makes more sense" is really true.
If your converts() method doesn't actually return a B, then there is no way to cast it to a B. Since you are getting a ClassCastException it clearly doesn't return a B.
You can of course write a converts(C c) that returns a B. But an alternative approach might be to write a constructor:
B(A a)
which creates a B based on the contents of A. Then you use converts to get a C, and create a B from it.
I think, the following can't be done in Java. But I would be happy to learn how to implement something that resembles it.
Suppose we have a class C, that is already used in compiled code. (We can neither change that code nor the original definition of C).
Suppose further there is interesting code that could be re-used, if only C would implement interface I. It is, in fact, more or less trivial to derive D that is just C + the implementation of the interface methods.
Yet, it seems there is no way, once I have a C, to say: I want you to be a D, that is, a C implementing I.
(Side remark: I think the cast (D)c, where c's runtime type is C, should be allowed if D is a C and the only difference to C are added methods. This should be safe, should it not?)
How could one work around this calamity?
(I know of the factory design pattern, but this is not a solution, it seems. For, once we manage to create D's in all places where formerly were C's, somebody else finds another interface J useful and derives E extends C implements J. But E and D are incompatible, since they both add a different set of methods to C. So while we can always pass an E where a C is expected, we can't pass an E where a D is expected. Rather, now, we'd need a new class F extends C implements I,J.)
Couldn't you use a delegate class, i.e. a new class which wraps an instance of "Class C", but also implements "Interface I" ?
public class D implements I {
private C c;
public D (C _c) {
this.c = _c;
}
public void method_from_class_C() {
c.method_from_class_C();
}
// repeat ad-nauseum for all of class C's public methods
...
public void method_from_interface_I() {
// does stuff
}
// and do the same for all of interface I's methods too
}
and then, if you need to invoke a function which normally takes a parameter of type I just do this:
result = some_function(new D(c));
If all that you need to be compatible with is interfaces then no problem take a look at dynamic proxy classes, its basically how you implement interfaces at runtime in java.
if you need similar runtime compatibility with classes I suggest you take a look at cglib or javaassist opensource libraries.
If you (can) manage the ClassLoader that loads your class C then you can try to do some class-loading time shenanigans with bytecode instrumentation to make the class implement the interface.
The same can be done during build-time, of course. It might even be easier this way (as you don't need access to the ClassLoader).
(Side remark: I think the cast (D)c,
where c's runtime type is C, should be
allowed if D is a C and the only
difference to C are added methods.
This should be safe, should it not?)
Not at all. If you could make this cast, then you could compile code that attempted to call one of the "added methods" on this object, which would fail at runtime since that method does not exist in C.
I think you are imagining that the cast would detect the methods that are "missing" from C and delegate them to D automatically. I doubt that would be feasible, although I can't speak to the language design implications.
It seems to me the solution to your problem is:
Define class D, which extends C and implements I
Define a constructor D(C c) which essentially clones the state of the given C object into a new D object.
The D object can be passed to your existing code because it is a C, and it can be passed to code that wants an I because it is an I
I believe what you want is possible by using java.lang.reflect.Proxy; in fact I have done something similar for a current project. However, it's quite a bit of work, and the resulting "hybrid objects" can expose strange behaviour (because method calls on them are routed to different concrete objects, there are problems when those methods try to call each other).
I think you that can't do it because Java is strictly typed. I believe it can be done in languages like Ruby and Python with a usage of mixins.
As for Java it definitely looks like a good usage for the Adapter design pattern (it was already proposed earlier as a "wrapper" object).