0

A simple question, regarding dynamic java, is it do-able, or totally not possible

//you have an instance of classA and it has a method doIT(), for example,
ClassA obj = new ClassA();
//you call method doIT() of ClassA
obj.doIt();

Now I have to re-model ClassA it becomes a superclass, and its methods and members are pushed down into its subclass, let's say ClassB, so ClassB extends ClassA, and method doIt() is moving into ClassB now, everyone knows as usual I need to change the above code to below, either manually or with help of modern IDE refactoring capacity

//you create an instance of ClassB, 
ClassB obj = new ClassB(); 
//or ClassB obj = new ClassA(); you have little code in the ClassA constuctor, etc.
//then you call a method
obj.doIt();

I know that, but my question is, without make changes to it

ClassA obj = new ClassA();
obj.doIt();

is there any tricks that will make it works with the new model? that means, some how I could return a real instance of ClassB to

ClassA obj = new ClassA();

but java compiler won't let me go with

obj.doIt();

because method doIt() is not inside ClassA anymore, even the return copy is a real ClassB,

is there any trick to fool compiler or make the idea working?

SebastianX
  • 142
  • 1
  • 5
  • What's a problem to use inheritance and type casting when necessary? – Anton Hlinisty Dec 21 '18 at 13:05
  • I mean, think about javascript, the code will still work after re-model, because at runtime the return copy IS a classB, no problem there, javascript is not compiling that give me the freedom, but Java compiler won't let me go with it, that is my question, is it possible to kind of , script java to work as I want? – SebastianX Dec 21 '18 at 13:06
  • 1
    @SebastianX That's doing away with type safety and defeats the purpose of the type system. You'd be better off just using a dynamically typed language if you want dynamic typing. Dynamically typed languages exist that run on the JVM, like Clojure. – Carcigenicate Dec 21 '18 at 13:14
  • To answer the question though, no, I don't believe that's possible without inheritance and casting(, or maybe screwing with reflection?). – Carcigenicate Dec 21 '18 at 13:14
  • The methods you may invoke on an object are those provided by its runtime class. This is managed by the VM. The method invocation expressions that the Java compiler will accept are those where the static type of of the invocation target *expression* is a class or interface type that provides a matching method, and this furthermore guides which overloads are considered. This is managed by the compiler. – John Bollinger Dec 21 '18 at 13:15
  • Therefore, if class `ClassA` does not define or inherit an accessible, concrete method `doIt()`, then you cannot by any means successfully invoke a method of that name on an object of that class. Whether there exists some subclass of `ClassA` that has such a method has no bearing whatever. The compiler and VM can consider and use only the *actual* class of the object and the declared types of references to it. – John Bollinger Dec 21 '18 at 13:20

1 Answers1

0

If you are calling new ClassX then you will always get an instance of class X unless maybe you can hack the JVM (not sure)? However, it would be possible to create "dynamic" objects, if you encapsulate object creation in methods like this:

Before Refactoring:

class ClassA {
    public void doIt(){ System.out.println("ClassA"); }
}
public static void main(String[] args){
    ClassA a1 = new ClassA();
    a1.doIt(); // "ClassA"
    // ... somewhere else
    ClassA a2 = new ClassA();
    a2.doIt(); // "ClassA"
}

After Refactoring:

class ClassA {
    public void doIt(){ System.out.println("ClassA"); }
}
class ClassB extends ClassA {
    public void doIt(){ System.out.println("ClassB"); }
}
public static void main(String[] args){
    // You can't make `new ClassA()` return a `ClassB`, unless maybe you hack the JVM?
    // if you want a `ClassB` instance instead
    // then you'd have to change ALL `new ClassA()` to `new ClassB()`
    ClassA a1 = new ClassB(); // <-- had to change
    a1.doIt(); // "ClassB"
    // ... somewhere else
    ClassA a2 = new ClassB(); // <-- also had to change
    a2.doIt(); // "ClassB"
}

If you want it to be "dynamic" then you could encapsulate object creation in methods.

Before refactoring:

class ClassA {
    // private constructor
    private ClassA(){}
    public newInstance(){ return new ClassA(); }
    public void doIt(){ System.out.println("ClassA"); }
}
public static void main(String[] args){
    ClassA a1 = ClassA.newInstance();
    a1.doIt(); // "ClassA"
    // ... somewhere else
    ClassA a2 = ClassA.newInstance();
    a2.doIt(); // "ClassA"
}

After Refactoring:

abstract class ClassA {
    private ClassA(){}
    // this is the only change, returning a `ClassB` instance instead
    public newInstance(){ return new ClassB(); }
    public void doIt(){ System.out.println("ClassA"); }
}
class ClassB extends ClassA {
    public void doIt(){ System.out.println("ClassB"); }
}
public static void main(String[] args){
    // No changes needed in here
    ClassA a1 = ClassA.newInstance();
    a1.doIt(); // "ClassB" <-- updated output
    // ... somewhere else
    ClassA a2 = ClassA.newInstance();
    a2.doIt(); // "ClassB" <-- updated output
}
xtratic
  • 4,600
  • 2
  • 14
  • 32