Расширение класса таким образом, что любой родительский класс может быть приведен к нему в Java

у меня такое чувство, что это невозможно, но если не было бы очень полезно.

Я пытаюсь расширить родительский класс таким образом, чтобы дочерний класс имел только новые методы, никаких новых конструкторов, никаких новых полей. Таким образом, базовая структура данных дочернего класса идентична родительскому классу. Это имеет тенденцию происходить, когда я хочу дать дополнительные функции встроенному классу java (например,Vector3d). Учитывая, что базовые данные идентичны, возможно ли каким-либо образом понизить объект инициализируется как родительский класс для дочернего класса, поэтому я могу использовать добавленную функциональность. В качестве примера того, что я имею в виду, см. ниже

import javax.vecmath.Vector3d;

public class Vector3dPlus extends Vector3d{
    //same fields, same constructors as Vector3d

    public double extraMethod(){
        return x+y+z;
    }
}

попробуйте использовать новый метод, добавленный в Vector3d

import javax.vecmath.Vector3d;     

public class Test {

    public static void main(String[] args) {
        Vector3d basic=new Vector3d(1,2,3);

        useExtraMethod(basic); //this line correctly raises an exception, but is there a way around that
    }

    public static void useExtraMethod(Vector3dPlus plus){
        System.out.println(plus.extraMethod());
    }
}

очевидно, java расстраивается этим, потому что обычно мы не можем гарантировать это Vector3dPlus методы будут работать со всеми Vector3d. Но есть ли в любом случае я могу сказать java, что базовые структуры данных одинаковы и поэтому позволяют все downcasting от all Vector3d в Vector3dPlus.

в настоящее время я имею дело с этим, чтобы поместить все дополнительные методы в общий класс утилит, но это, очевидно, немного ужасно

4 ответов


Вы можете добиться этого с помощью перегрузки метода и конструктора копий:

public class Vector3dPlus extends Vector3d {
    public Vector3dPlus(Vector3d vector) {
        super( ... ); // parameters from vector
    }

    // rest of your Vector3dPlus code
}

и в вашем тестовом классе перегрузите метод:

    public class Test {

        public static void useExtraMethod(Vector3d vector) {
            useExtraMethod(new Vector3dPlus(vector));
        }

        public static void useExtraMethod(Vector3dPlus plus){
             System.out.println(plus.extraMethod());
        }

        public static void main(String[] args) {
           Vector3d basic=new Vector3d(1,2,3);
           useExtraMethod(basic); // this line works now
        }
    }

Я бы не сосредоточился на базовой структуре данных иерархии классов, а больше на внешнем интерфейсе, который предоставляется.

в вашем примере Vector3DPlus класс имеет дополнительный метод, не найденный на Vector3D. Это отличает его интерфейс базового класса, что делает их полностью взаимозаменяемыми. Компилятор правильно создает исключение, когда базовый тип передается методу, ожидающему подтип.

Я не верю, что вы можете избежать некоторых форма типа проверки для достижения желаемого поведения. Как-то вам нужно убедиться, что только экземпляры Vector3DPlus передаются в метод. Такова цена нисхождения.

public static void main(String[] args) {
       Vector3d basic=new Vector3d(1,2,3);

       if(basic instanceof Vector3dPlus){
       useExtraMethod(basic); //this line correctly raises an exception, but is there a way around that
       }
}

Как насчет этого?

import javax.vecmath.Vector3d;

public class Vector3dPlus extends Vector3d{
    Vector3dPlus {
        super(int a, int b, int c);
    }

    public double extraMethod(){
        return x+y+z;
    }
}

и используйте так:

import javax.vecmath.Vector3d;

public class Test {

    public static void main(String[] args) {
       Vector3d basic=new Vector3d(1,2,3);
       Vector3dPlus plus=new Vector3dPlus(1,2,3);

       useExtraMethod(basic);
       useExtraMethod(plus);
    }

    public static void useExtraMethod(Vector3d vector){
        if (vector instanceof Vector3dPlus) {
            System.out.println(((Vector3dPlus) vector).extraMethod());
        }
    }
}

вы можете достичь этого, как описано ниже [нет другого способа достичь этого, если вы не хотите использовать instanceof это]:

public class Test {

    public static void main(String[] args) {
        Vector3dPlus basicPlus = new Vector3dPlus(1,2,3);
        Vector3d basic=basicPlus;

        useExtraMethod(basic); 
    }

    public static void useExtraMethod(Vector3dPlus plus){
        System.out.println(plus.extraMethod());
    }
}

Java имеет внутренний механизм для проверки типа литья. Вы не можете обойти основной принцип "дочерний класс имеет тип родительского класса", но"родительский класс не имеет типа дочернего класса"