handle different instance variables in method - java

So if I have a method where a variable can be an instance of a bunch of different classes where only some of them have a specific instance variable, how do I use this instance variable in the method without getting the cannot be resolved or is not a field error?
consider this code:
void method1(){
SuperType randomInstance = getRandomInstance();
if(randomInstance.stop == true) //do something
}
where SuperType is a super class to all possible instances that randomInstance can hold.
However, an instance doesn't necessarily have the variable stop so I get an error saying stop cannot be resolved or is not a field
So my question is, is there a way to get around this or would I have to create different methods for different instances depending on if they have the variable stop or not?

If having a stop property can be viewed as a behavior shared by some of the sub-classes of SuperType, you can consider defining an interface - let's call it Stoppable - having methods getStop (or perhaps isStopped if it's a boolean) and setStop.
Then your code can look like :
void method1(){
SuperType randomInstance = getRandomInstance();
if (randomInstance instanceof Stoppable) {
Stoppable sInstance = (Stoppable) randomInstance;
if(sInstance.getStop() == ...) //do something
}
}

Give the classes in question a common supertype or interface (they seem, from your code, to have one — SuperType), and define the instance field (it's not a "variable") on the supertype or define a getter function on the interface. (Actually, even if the supertype is a class, it's commonly best practice to define the field using a getter anyway, even if you could make it a public or protected instance field.)

If you cannot change your class hiearchy with the introdution of an Interface (Stoppable for example) can resort to reflection to detect if the class has a provate field named stop.
You can find an example of field "listing" from a class here and Field is documented here

Related

How is my private member getting set to null?

I have been programming java professionally for more than ten years. This is one of the weirdest bugs I've ever tried to track down. I have a private member, I initialize it and then it changes to null all by itself.
public class MyObject extends MyParent
{
private SomeOtherClass member = null;
public MyObject()
{
super();
}
public void callbackFromParentInit()
{
member = new SomeOtherClass();
System.out.println("proof member initialized: " + member);
}
public SomeOtherClass getMember()
{
System.out.println("in getMember: " + member);
return member;
}
}
Output:
proof member initialized: SomeOtherClass#2a05ad6d
in getMember: null
If you run this code, obviously it will work properly. In my actual code there are only these three occurrences (five if you count the printlns) in this exact pattern.
Have I come across some bug in the JVM? Unless I'm wrong, the parent class can't interfere with a private member, and no matter what I put between the lines of code I've shown you, I can't change the value of member without using the identifier "member".
This happens because of the order in which member variables are initialized and constructors are called.
You are calling callbackFromParentInit() from the constructor of the superclass MyParent.
When this method is called, it will set member. But after that, the subclass part of the object initialization is performed, and the initializer for member is executed, which sets member to null.
See, for example:
What's wrong with overridable method calls in constructors?
State of Derived class object when Base class constructor calls overridden method in Java
Using abstract init() function in abstract class's constructor
In what order constructors are called and fields are initialized is described in paragraph 12.5 of the Java Language Specification.
Assignment of null to field member happens after executing parent constructor.
The fix is to change:
private SomeOtherClass member = null;
to:
private SomeOtherClass member;
Never, never ever call a non final method from the superclass' constructor.
It's considered bad practice, precisely because it can lead to nasty, hard-to-debug errors like the one you're suffering.
Perform initialization of a class X within X's constructor. Don't rely on java's initialization order for hierarchies. If you can't initialize the class property i.e. because it has dependencies, use either the builder or the factory pattern.
Here, the subclass is resetting the attribute member to null, due to superclass and subclass constructors and initializer block execution order, in which, as already mentioned, you shouldn't rely.
Please refer to this related question for concepts regarding constructors, hierarchies and implicit escaping of the this reference.
I can only think about sticking to a (maybe incomplete) set of rules/principles to avoid this problem and others alike:
Only call private methods from within the constructor
If you like adrenaline and want to call protected methods from within the constructor, do it, but declare these methods as final, so that they cannot be overriden by subclasses
Never create inner classes in the constructor, either anonymous, local, static or non-static
In the constructor, don't pass this directly as an argument to anything
Avoid any transitive combination of the rules above, i.e. don't create an anonymous inner class in a private or protected final method that is invoked from within the constructor
Use the constructor to just construct an instance of the class, and let it only initialize attributes of the class, either with default values or with provided arguments

Safety of subclass data when returned as superclass

I'm having some trouble finding the specifics on what happens when you return a subclass in a method of superclass type in Java. For example:
public class SuperClass
{
int a;
}
public class SubClass extends SuperClass
{
int b;
}
SuperClass superObj;
SubClass subObj;
private SuperClass getObject ()
{
return subObj;
}
public static void main (...)
{
superObj = getObject();
}
What exactly happens to subObj when it's returned as its superclass? I realise while typing this example that I could probably just as easily test it myself, but i'm still curious as to what the process is exactly when this happens, and whether it's considered good (if it works, that is) or bad practice.
I'm asking because I'm currently working on a project in which I have two abstract base classes, and several subclasses for each of them. I'm trying to find out good/bad ways to handle having to change from one subclass to another while still using the convenience polymorphism adds when using abstract base classes.
EDIT: I fixed main and the class declarations, sorry about that.
Casting does not fundamentally change an object to a different type, it simply tells the compiler to view the object as its superclass (or subclass, when downcasting). In your example, superObj is still an instance of the SubClass type, but it now appears to be a SuperClass. What this means is that if you try to reference superObj.b, you will get a compilation error (since b does not exist in SuperClass). However you could reference (SubClass)superObj.b. In this case you are telling the compiler to consider subClass as an instance of SubClass (which it really is).
Let's take this a step further and add another class to your code:
public class SisterClass extends SuperClass
{
int c;
}
Without changing anything else in your code (other than the syntax problems), you try to reference ((SisterClass)superObj). This will compile but fail with a ClassCastRuntime runtime error. Although SisterClass is a subclass of SuperClass, superObj is not an instance of SisterClass. So, you can only cast to what the object actually is.
There are some oddities in your code (defining a method inside main?), but that not withstanding... The method getObject will not change your subObj, it will simply return a reference to it that looks like type SuperClass. By "looks like" I mean that it will only expose any methods or members from SuperClass. However, if you take that returned value and attempt to downcast it to SubClass, the cast will succeed and you will find the field/methods from SubClass will work as you expect without any loss of information from having been returned as SuperClass.
SubClass is extension of SuperClass
you are just casting it down to its base class, all extensions are not available, you should not be looking to try and get them back to Implementations as you would be guessing what that are, as you could extend it numerous times in various ways,
The returned class would have a but not b

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.

inheritance and class members

GIVEN:
class A
{
String s = "A";
}
class B extends A
{
String s = "B";
}
public class C
{
public static void main(String[] args){ new C().go();}
void go()
{
A a = new B();
System.out.println(a.s);
}
}
Question:
What are the mechanics behind JVM when this code is run? How come a.s prints back as "A".
Field references are not subject to polymorphism, so at compile time the compiler is referencing A's field because your local variable is of type A.
In other words, the field behavior is like the Java overloading behavior on methods, not the Java overriding behavior.
You probably expect fields to be overridden like method, with dynamic dispatch based on the runtime type of the object.
That's not how Java works. Fields are not overridden, they are hidden. That means an object of class B has two fields named "s", but which of them is accessed depends on the context.
As for why this is so: it wouldn't really make sense to override fields, since there is no useful way to make it work when the types are different, and simply no point when the type is the same (as you can just use the superclass field). Personally, I think it should simply be a compiler error.
This isn't polymorphism (as tagged).
Java has virtual methods, not virtual member variables - i.e. you don't override a property - you hide it.
Although member variables are inherited from a base class, they are not invoked polymorphically (i.e dynamic invocation does not apply to member variables).
So, a.s will refer to the member in the base class and not the derived class.
Having said that, the code is not following OO principles. The members of a class need to be private/protected (not public or default) depending on the business use case and you need to provide public methods to get and set the values of the member.

Uninstantiated Anonymous Classes in Java

It's been about 6 years since I've written Java, so please excuse the rust.
I'm working with a library method that requires that I pass it Class objects. Since I'll have to invoke this method a dynamic number of times, each time with a slightly different Class argument, I wanted to pass it an anonymous class.
However, all the documentation/tutorials I've been able to find so far only talk about instantiating anonymous classes, e.g.:
new className(optional argument list){classBody}
new interfaceName(){classBody}
Can I define an anonymous class without instantiating it? Or, perhaps more clearly, can I create a Class object for an anonymous class?
Unfortunately, there's no way you can dodge the instantiation here. You can make it a no-op, however:
foo((new Object() { ... }).getClass());
Of course, this might not be an option if you have to derive from some class that performs some actions in constructor.
EDIT
Your question also says that you want to call foo "each time with a slightly different Class argument". The above won't do it, because there will still be a single anonymous inner class definition, even if you put the new-expression in a loop. So it's not really going to buy you anything compared to named class definition. In particular, if you're trying to do it to capture values of some local variables, the new instance of your anonymous class that foo will create using the Class object passed to it will not have them captured.
short answer
you cannot (using only JDK classes)
long answer
give it a try:
public interface Constant {
int value();
}
public static Class<? extends Constant> classBuilder(final int value) {
return new Constant() {
#Override
public int value() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}.getClass();
}
let's creating two new class "parametric" classes:
Class<? extends Constant> oneClass = createConstantClass(1);
Class<? extends Constant> twoClass = createConstantClass(2);
however you cannot instantiate this classes:
Constant one = oneClass.newInstance(); // <--- throws InstantiationException
Constant two = twoClass.newInstance(); // <--- ditto
it will fail at runtime since there is only one instance for every anonymous class.
However you can build dynamic classes at runtime using bytecode manipulation libraries such ASM. Another approach is using dynamic proxies, but this approach as the drawback that you can proxy only interface methods (so you need a Java interface).
You can only reference an anonymous class ONCE. If you do not instantiate it there, you cannot instantiate it since you do not have a name for it.
Hence I believe that anonymous classes can only be used in conjunction with a "new BaseClass()".
In your situation you would pass a BaseClass object to your method doing the work, and instantiate the anonymous object in the source code when you need the object to pass.
You can't access the Class object of an anonymous class without instatiating it. However, if you only need access to the class, you could define local classes within your method and refer to these using the ClassName.class literal syntax.
You can assume the name of an anonymous class and call Class.forName("mypackage.MyBaseClass$1") to get a handle to an anonymous class. This will give you the first anonymous class defined in your MyBaseClass, so this is a rather fragile way to refer to a class.
I suspect whatever you are trying to do could be done a better way. What are you really trying to achieve? Perhaps we can suggest a way which doesn't require you to pass a Class this way.
You can access the class object of an anonymous class by calling .getClass() on it immediately after creation. But what good would that do?
I think the key is in this part of what you said:
I'm working with a library method that requires that I pass it Class
objects.
Why does it want you to pass it Class objects? What does this library do with the Class objects you pass it? Instantiate objects? But if so, what constructor does it use and how does it decide what arguments to pass? I don't know what library you are using or what it does, but I would guess that it always creates objects using the no-argument constructor. However, that will not work for anonymous classes anyway, since they have no public constructor (and in any case, to instantiate any non-static inner class, a reference to the outer instance must be provided, so there is no no-argument constructor).

Categories

Resources