Как вернуть разные типы в метод, используя дженерики? - PullRequest
1 голос
/ 28 марта 2019

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

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

Вот код:

public class Client {
    public static void main(String[] args) {
        Client c = new Client();
        A a = c.gets(1);
        System.out.println(a.aFiled);
        B b = c.gets(2);
        System.out.println(b.bFiled);
    }


    public <T extends Root> T gets(int type) {
        switch (type) {
            case 1:
                return new A();
            case 2:
                return new B();
            default:
                throw new RuntimeException();
        }
    }


    class Root {
        String name;
    }

    class A extends Root {
        int aFiled;
    }

    class B extends Root {
        int bFiled;
    }
}


Ошибка возникает внутри switch

«несовместимые типы»
Требуется: T
Найдено: Client.A

Я имею в виду возвращение некоторого расширения классов Root, я не знаю, почему это неправильно.
Буду признателен, если кто-нибудь сможет мне это объяснить.

Ответы [ 3 ]

4 голосов
/ 28 марта 2019

В обобщенных методах тип выводится компилятором с использованием фактических аргументов. Но ваш аргумент не имеет типа T. Вы можете отправить другой параметр Class<T>, чтобы указать тип возвращаемого значения:

public <T extends Root> T gets(int type, Class<T> c) {
    switch (type) {
        case 1:
            return c.cast(new A());
        case 2:
            return c.cast(new B());
        default:
            throw new RuntimeException();
    }
}

Но в вашем случае вы не знаете тип, прежде чем вызывать этот метод.

Так что все, что вы можете сделать, это сделать этот метод не универсальным и изменить тип возвращаемого значения на Root. Затем вы можете выполнить instanceof проверку, чтобы определить класс, выполнить приведение, а затем получить соответствующие поля.

Не имеет смысла делать этот метод универсальным, так как универсальные методы могут работать с различными типами предоставленных данных. Но в вашем случае это всегда int. Так что я бы сказал, что ваш метод на самом деле не универсальный .

0 голосов
/ 28 марта 2019

Вы можете изменить свой метод, как показано ниже, приведя к T.

    public <T extends Root> T gets(int type) {
        switch (type) {
            case 1:
                return (T) new A();
            case 2:
                return (T) new B();
            default:
                throw new RuntimeException();
        }
    }
0 голосов
/ 28 марта 2019

Метод указывает, что существует T, расширяющий Root, который является типом возврата.Однако, пока метод не используется где-то, вы не знаете, какой это класс.Вы не знаете, будет ли T А, или В, или что-то еще.Каждый раз, когда он используется, это будет ровно один подкласс Root.

Но здесь ваш код предполагает, что это будут и A, и B одновременно.На самом деле, Т может быть ни тем, ни другим.Если T является A, вы не можете вернуть экземпляр B. Если T является B, вы не можете вернуть экземпляр A. Если T не является ни A, ни B, вы не можете вернуть ни экземпляр A, ни B.

Вы должны вернуть экземпляр T.

Одна вещь, которую вы можете сделать, это не использовать дженерики и просто вернуть Root.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...