Access super field from subclass object - java

This may be a strange question, but I don't understand how have I managed to get this to work. My intention was to access the super's field from an object that overrides the field. First, what did work (1):
class Foo {
protected int i = 0;
}
public class Bar extends Foo {
int i = 1;
Foo f() {
return this;
}
public static void main (String[] args) {
Bar b = new Bar();
System.out.println(b.i);
System.out.println(b.f().i);
}
}
I first tried to use something like (2):
System.out.println(b.super.i);
which didn't work. I then tried to use (3):
Foo f() {
return super;
}
and that didn't work either.
So, referring to the numbered parts above:
Why does return this cast to Foo return a reference to the b.super object?
In main, I would have thought b.super would be the reference to the instantiated object "b" 's super reference. Is there any way to access the reference to the super object from the containing object? Maybe something from reflection, but I don't want access to the .class object (b.getClass().getSuper()), but rather the instantiated Foo contained within b.
Why does return.super not return a reference to the b.super object?

My intention was to access the super's field from an object that overrides the field.
You are not "overriding" the field. You are creating a second, unrelated field with the same name. The resulting name clash is the direct cause of your difficulty.
If the two fields are unrelated, give them different names.
If, on the other hand, you are trying to achieve polymorphic behaviour, turn them into methods:
class Foo {
protected int get_i() { return 0; }
}
public class Bar extends Foo {
#Override
protected int get_i() { return 1; }
}

since fields can not be overridden, they remains hidden when you use the same name in sub classes. Thats why you can not access those super class fields if you have redefined field in subclasses.
if you want to access those, you should provide getters/setters in superclass.

Because fields are not accessed in a polymorphic, dynamic way. The declared type of the object returned is Foo, so Foo's field is accessed. Fields can't be overridden. Defining i in the subclass creates another field that happens to have the same name as the one in the superclass, and thus hides it.
There's no way. You should amost never access fields of an object directly. Use methods instead.
Because that's invalid Java code. return super makes no sense. super is not a different object. super and this are the same object.

You don't need reflection, you need to define setter and getter methods in your superclass.

Your questions answered:
Why does return.this cast to Foo return a reference to the b.super object?
It does not, exactly. It returns a reference to 'this' which is an instance of Bar and also of Foo, because Bar extends Foo.
In main, I would have thought b.super would be the reference to the instantiated object "b" 's super reference. Is there any way to access the reference to the super object from the containing object? Maybe something from reflection, but I don't want access to the .class object (b.getClass().getSuper()), but rather the instantiated Foo contained within b.
b and b.super are one and the same. You can access Foo protected fields from Bar code without a problem
Why does return.super not return a reference to the b.super object?
Again, b and b.super are the same instance.

Related

Use class level field or method variable?

I have a object I initialize in a method like :
public void something()
{
Dummy obj = Factory.getDummy();
method2(obj);
}
now, this Dummy object is to be used by many methods
public void method2(Dummy obj)
{
method2(obj);
....
}
Now, my doubt is how this scenario must be handled, the way I am doing it. Or, make obj in something a class level field and initialize in something.
like:
private Dummy obj;
public void something()
{
obj = Factory.getDummy();
method2(obj);
}
And use in subsequent methods. (Removing parameters from the methods).
So, what is the best way of handling this situation? and Why?
If it's strongly associated with the class, make it static.
If it's strongly associated with an instance, make it a non--static member.
If it's strongly associated with a method invocation, or the current thread, or you can't decide about (1) or (2), make it method-local.
Generally you should minimize the scope of one variable. But, if the variable is very used within your class, you should declare it as class-level, as instance variable.
You should declare obj as a class-level field and then instantiate it in the constructor.
But more points to clear:
if something() and the methods like method2() that expect the Dummy object, are located inside the same class, then you even don't need to pass the object. In that case, the above statement is upheld
if not located in the same class, then pass the object by invoking the methods through their instances or classes based on what type they're.
If some property is associated to class, then that property should be static. That is, if some property is same among all the instances of classes, then that property should be the static in class.
If some property is differing for every instance of class, then that property should be member variable ( non-static variable ) of the class.
If some property needs on temporary basis for some operation then make that property as local variable of the operation ( method ).

How does Object.toString() work for different underlying types?

I don't understand why this works in java:
If I have an Integer object in a object, example:
Object myIntObj = new Integer(5);
Now if i do:
System.out.println(myIntObj);
the output is: 5
I now that the Integer class has an ovveride of the toString method but in this case is different (I think).
For the polymorphism, if I have a "child object" in a "father variable" the object doesn't change its real type (in this case Integer) But... it (in the Object variable) can just use the method of the Object Class, so why if I write:
System.out.println(myIntObj);
I can see directly the number 5 and not the reference of this object? Because toString method in the object class by default return just a string of the reference of the object.
like:
Object currentPlayer = new Player();
System.out.println(currentPlayer);
In this case the output is the reference of the Player objecet because is called the toString method in the object class.
So why in the example of before I don't see the reference but directly the number?
by logic, the rules of the polymorphism says that: if u have a "child" object in a "father" variable, this object, inside, remanis the same but he is used like an istance of object, so he can just uses the class object and so just the method of object, so is really strange that I don't see the reference but directly the number.
I hope you understand what I mean.
Your last paragraph where you explain your reasoning is slightly incorrect.
so why in the example of before i don't see the reference but directly
the number? by logic, the rules of the polymorphism says that: if u
have a "child" object in a "father" variable, this object, inside,
remanis the same but he is used like an istance of object, so he can
just uses the class object and so just the method of object, so is
really strange that i don't see the reference but directly the number.
The beginning is correct, but the part I bolded is an incorrect conclusion you drew from it.
You are correct that with polymorphism, the object truly remains whatever type it is, but the reference type (the type of the variable) defines what you can do with it. However, the reference type does not describe what the object does
That is the intent behind polymorphism. It is an abstraction to define what can be done separately from how it works. For example, if you have this example:
public class Vehicle {
public int getWheelCount() {
return 1;
}
}
public class Car extends Parent {
public int getWheelCount() {
return 4;
}
public void blowHorn() {
System.out.println("Honk honk!");
}
}
public class Bicycle extends Parent {
public int getWheelCount() {
return 2;
}
}
Car car = new Car();
car.getWheelCount(); // 4
car.blowHorn(); //"Honk honk!"
Vehicle v = new Car();
v.getWheelCount() // 4
v.blowHorn(); // COMPILE ERROR HERE! Unknown method
Bicycle b = new Bicycle();
b.getWheelCount(); // 2
Vehicle v = new Bicycle();
v.getWheelCount(); // 2
What you can conclude from this is that when over-riding a method in a sub-class, the child version is always called. A car is always a car whether you are referring to it as a vehicle or as a car. But by referring to it as a vehicle, you are limited to invoking methods which are defined on all vehicles.
To tie it to the example, all Vehicle objects have a wheel size, therefore getWheelCount() is always callable whether it's Vehicle.getWheelCount() or Car.getWheelCount(). However, Car.getWheelCount() is what executes because Car over-rides it.
If the reference type is Vehicle, you cannot call blowHorn() because that method is only available on Car.
Going back to your example, an Integer is an Integer.
Object i = new Integer(5);
i.toString(); // 5
This prints 5 because i is an integer. The Integer class over-rides toString. The reference type (the type you are referring to the object as) only determines which methods you can call, but not which parent/child class's version of the method is called.
By defining it as Object this means you will only have access to methods that are defined in the Object class.
This includes toString().
So when you instantiate new Player() you still only have access to the methods from Object, but if you override this (like Integer.toString() does), you will still have the output as defined in the instantiated class.
PS: Father -> Parent
This is how the concept of overriding methods works: once an object somewhere in the inheritance hierarchy provides an implementation, it is this implementation that is going to be called, unless it is overridden by another class further down the inheritance hierarchy.
Since java.lang.Integer provides an override of toString(), this override is called instead of the implementation provided by the java.lang.Object.
There is no difference between System.out.println(myIntObj) and System.out.println(myIntObj.toString()), because println will call toString internally on all objects which it does not know how to print.
The reason your Player class behaves differently is that it does not override toString(). If it did, you would see its results printed. With no override, however, the default implementation provided by java.lang.Object is called, which prints some generic object info.
Object myIntObj = new Integer(5);
Here you're creating a new Integer instance, not a bare Object instance. The fact that you're assigning it to an Object reference doesn't transform it into a bare Object. It's still an Integer, but you can reference it as an Object because it extends Object. So when you call myIntObj.toString(), you're calling that instance's toString() method. That instance turns out to be an Integer instance. And so Integer.toString() is called.
Object currentPlayer = new Player();
In this case the same rules apply when calling currentPlayer.toString(): you're actually calling Player.toString(). If Player class does not override toString(), then first ascending parent class toString() implementation is called. If Player directly extends Object, then Object.toString() is called, but if for example Player extends Human and Human extends Object, then Human.toString() is going to be called if it exists. If not, then Object.toString().
Consider this case where Employee has a subclass Manager that has a method getDetails() overridden,
Employee e=new Employee();
Employee m=new Manager();
If you invoke e.getDetails() you will get the behavior associated with Employee.
If you invoke m.getDetails() you will get the behavior associated with Manager.
In general, you get the behavior associated with the object to which the variable refers at runtime. This behavior is often referred to as virtual method invocation.
So the reason why you are getting the behavior associated with Integer when your reference is an object is because you are referring to an Integer object at runtime.

Why variables are not behaving as same as method while Overriding.? [duplicate]

This question already has answers here:
why java polymorphism not work in my example
(3 answers)
Closed 6 years ago.
Generally Overriding is the concept of Re-defining the meaning of the member in the sub class.Why variables are not behaving like methods while Overriding in java ?
For instance:
class Base {
int a = 10;
void display() {
System.out.println("Inside Base :");
}
}
class Derived extends Base {
int a = 99;
#Override
// method overriding
void display() {
System.out.println("Inside Derived :");
}
}
public class NewClass {
public static void main(String... a) {
Derived d = new Derived();
Base b = d;
b.display(); // Dynamic method dispatch
System.out.println("a=" + b.a);
}
}
Since data member a is package access specified, it is also available to the Derived class. But generally while calling the overridden method using the base class reference, the method that is redefined in derived class is called (Dynamic method dispatch)..but it is not the same for the variable..why.?
EXPECTED OUTPUT
Inside Derived :
a=99
OBTAINED OUTPUT:
Inside Derived :
a=10
Prints 10 - why the variable does not behave similar to method in the derived class?
Why the variables are not allowed to be overridden in the sub class?
You typed b as an instance of Base. So when the compiler needs to resolve b.a, it looks to the definition of Base for the meaning of b.a. There is no polymorphism for instance fields.
Because the only thing that polymorphism ever applies to in Java is instance method.
Hence, you can neither override static members, nor the instance member fields. By, having these members in a derived class with the same names you're simply hiding them with a new definition.
System.out.println("a="+b.a);
Although, Base b may point to a sub-class object (at runtime) the a above has already been bound to Base class at compile time (static binding). Hence, it prints 10.
Variables behave like that because they lack behavior. In other words, variables are passive.
There is nothing about a variable's definition that a derived class can reasonably change by overriding:
It cannot change its type, because doing so may break methods of the base class;
It cannot reduce its visibility, because that would break the substitution principle.
It cannot make it final without making it useless to the base class.
Therefore, member variables declared in derived classes hide variables from the base class.
There is no way to override a class variable. You do not override class variables in Java you hide them. Overriding is for instance methods.
In this case, it might be a good idea to write a getter method:
public int getA(){
return 99;
}
Now you can override it in a derived class.
First, we don't override any class variable. Methods only.
Second, if you would like to see that the variable value has been updated or replaced, you should rather declare it as "static int" instead of "int". In this way, it will work as everybody is sharing the same variable, and the new value will be put on it.
Third, if you would like to see that the variable value being assigned and used differently, you could design it as passing a parameter in constructor, or something similar, to make it work accordingly as you desire.
The answer to this has to do with variable scoping, not polymorphism. In other words, you're overriding that variable in the class scope. So, d.a will return the variable in Derived's class scope, but b.a will return the variable in Base's class scope.
In OOP (Object Oriented Programming) the idea is to hide the data in the object and let object only communicate with invoking methods. That's why variables cannot be overloaded, in fact they are "scoped"/"attached" to a specific class.
Also the derived class should not define a again, it is already defined in the base class, so simply set a on the object to the desired value, e.g:
class Base {
private int a = 10;
public int getA() { return a; }
public void setA(inta) { this.a = a; }
}
class Derived extends Base {
// adding new variables, override methods, ...
}
// then later:
Derived d = new Derived();
d.setA(99); // override the default value 10
What would happen if variables could override other variables? Suddenly your class has to be aware of what variables the parent class is using, lest you accidentally override one and break whatever was using it in the parent class. The whole point of encapsulation is to avoid having that kind of intimate knowledge of another object's internal state. So instead, variables shadow same-named other variables, and which one you see depends on what type you're trying to reach the variable through.
There's hope, though. If all you want is to override the value, you don't have to redeclare the variable. Just change the value in an init block. If the base class is harmed by you doing that, then it chose the wrong visibility for that variable.
class Base {
int a = 10;
}
class Derived extends Base {
{ a = 99; }
}
Of course, this doesn't work very well for final variables.
we don't override any class variable. Methods only.
If you would like to see that the variable value has been updated or
replaced, you should rather declare it as "static int" instead of
"int". In this way, it will work as everybody is sharing the same
variable, and the new value will be put on it.
If you would like to see that the variable value being assigned and
used differently, you could design it as passing a parameter in
constructor, or something similar, to make it work accordingly as
you desire.
Moreover, if variables are overridden then what is left with a parent class of its own,it breaches the class security if java would give the access to change the value of variable of parent class.

How can I create an object of this class?

In class B, how can I create an object of class A other than the process of object creation (i.e. without creating an object having null)?
class A
{
public int one;
A(A a)
{
a.one=1;
}
}
class B
{
public static void main(String...args)
{
//now how to create an object of class A over here.
}
}
To construct an object of type A you need to pass to the constructor either a reference to another object of type A, or else the null reference. So you have only two options:
A a1 = new A(null);
A a2 = new A(a1);
The first time you create an object of type A you must use the null reference because you don't have any other objects of type A.
Update
After you changed your question, I don't think it's possible to construct an object of type A.
If I understand your question correctly, you want to create an object a without having to pass it a pre-existing object of the same type.
To do so you have to add a constructor to class A that does not take a parameter of type A or modify the existing one:
class A
{
A() {
// Constructor logic.
}
A(A a) {
// Constructor logic when passing an existing object of the same type, perhaps to create a clone.
}
}
If for some reason you can't modify class A, you'll have to follow Mark Byers' answer and pass a null reference to the constructor.
Update
With the update to your code, this problem (or thought experiment) is unsolvable: class A can not be instantiated as written.
You cannot normally do this in Java.
However, it's possible with heavy cheating. Don't do this in production code. But for the sake of argument:
1) With Mockito (But won't work with a security manager):
import org.mockito.Mockito;
class B {
public static void main(String... args) {
A mockedA = Mockito.mock(A.class);
A realA = new A(mockedA);
System.out.println(realA);
}
}
2) Here's another way to do it overriding finalize().
Only way to create A object is by giving him other A object in constructor, but that other A object also needs another A object in constructor. This will stop only when you put null reference in constructor.
Edit
My answer was based on your previous version of code. Now you can't create object because you can't put null in constructor (null desn't have one field). If you want to create A object, you have to do test for null in constructor like if (a!=null){ a.one=1;} and pass null or already created A object in constructor.
If A is sealed (not editable) you could only extend that class and give the one a default constructor to pass it into a new instance of A. There is no other solution without modifying the source code of A.
You can not instantiate A in your example. It is a chicken and egg problem. You need an instance of A to create an instance of A, but you can not create an instance of A without having an instance of A.
So, without changes to A (be it either adding a 'null' check or adding a default constructor) you can not create an instance of A in this scenario.

Java reflecting nested anonymous classes

Why does this code return "class java.lang.Object" ?
Object a = new Object() {
public Object b = new Object(){
public int c;
};
};
System.out.println(a.getClass().getField("b").getType());
Why does the inner-inner type get lost? How can I reflect the c field ?
Edit:
This one works (as pointed out in some answers):
a.getClass().getField("b").get(a) ...
But then I have to invoke a getter, is there any way to reflect c with only reflection meta data?
Because b is declared as Object:
public Object b = ...;
There is a distinction between type of variable (static type) and type of the object referenced by that variable (runtime type).
Field.getType() returns static type of the field.
If you want to get runtime type of the object referenced by the field, you need to access that object and call getClass() on it (since a is declared as Object and therefore b is not visible as its member you have to use reflection to access it):
System.out.println(
a.getClass().getField("b").get(a).getClass());
UPDATE: You can't reflect c without accessing the instance of object containing it. That's why these types are called anonymous - a type containing c has no name, so that you can't declare field b as a field of that type.
Let's look at this line carefully:
System.out.println(a.getClass().getField("b").getType());
First, your take the a variable. It is of some anonymous subclass of the Object. Let's call that class MyClass$1. Okay, so far so good.
Next, you call the getClass() method. It returns the class of a, that is, a description of the MyClass$1 class. This description is not tied to any particular instance of that class, though. The class is the same for all instances, be it a or whatever else (unless different class loaders are used). In this particular case, however, there can be only one instance, because the class is anonymous, but the mechanism is still the same.
Now, from the class, you get the field b. As the class isn't directly tied to any of this instances, the field has nothing to do with a either. It's just a description of what exactly the field a of the class MyClass$1 is.
Now you get its type. But since it isn't tied to any instance, it can't know the runtime type. In fact, if the class wasn't anonymous, you could have numerous instances of MyClass$1, each having different value in a. Or you could have no instances at all. So the only thing getType() can possibly tell you is the declared type of b, which exactly what it does. The b field could in fact be null at that point, and you'd still get Object as the result.
The Field class provides the get() method to actually access that particular field of some object, like this:
System.out.println(a.getClass().getField("b").get(a).getClass());
Now you get something like MyClass$1$1, which is the name of the anonymous class of the object that field b references to, in the a instance.
Why does the inner-inner type get lost?
Because you are getting the type type of the field "b" (Object), not the type of the anonymous inner class of which you assigned the instance to "b".
How can I reflect the c field ?
You could use this
System.out.println(a.getClass().getField("b").get(a).getClass().getField("c"));
instead. This gets the value of the field "b" and it's class, but this only works if "b" is guaranteed be not null.
Doing this seems to indicate a bad design, there might be other ways to archive what you want to do with this. But without knowing the purpose, this is everything I can answer.

Categories

Resources