Простой вопрос о динамической Java, это выполнимо?или совсем не возможно? - PullRequest
0 голосов
/ 21 декабря 2018

Простой вопрос, касающийся динамической Java, это выполнимо, или совершенно невозможно

//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();

Теперь мне нужно изменить модель ClassA, он становится суперклассом, иего методы и члены помещаются в его подкласс, скажем, в ClassB, поэтому ClassB расширяет ClassA, а метод doIt () переходит в ClassB , все, как обычно, знают, что мне нужно изменить приведенный выше код нижелибо вручную, либо с помощью современных возможностей рефакторинга IDE

//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();

Я знаю это, но мой вопрос, без внесения в него изменений

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

Есть ли какие-нибудь хитростичто заставит его работать с новой моделью? это означает, что я могу как-то вернуть реальный экземпляр ClassB в

ClassA obj = new ClassA();

, но компилятор Java не позволит мне перейти с

obj.doIt();

, поскольку метод doIt () больше не находится внутри ClassA, даже возвращаемая копия является настоящим ClassB,

есть ли хитрость, чтобы обмануть компилятор или заставить идею работать?

1 Ответ

0 голосов
/ 21 декабря 2018

Если вы звоните new ClassX, вы всегда получите экземпляр класса X, если только вы не сможете взломать JVM (не уверен)?Однако было бы возможно создать «динамические» объекты, если вы инкапсулируете создание объектов в методы, подобные этому:

До рефакторинга:

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"
}

После рефакторинга:

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"
}

Если вы хотите, чтобы оно было «динамическим», вы можете инкапсулировать создание объектов в методы.

Перед рефакторингом:

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"
}

После рефакторинга:

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
}
...