Java Generic: Оператор "*" не может быть применен к T, T.Im трудно понять в общем - PullRequest
0 голосов
/ 23 сентября 2019

У меня есть работа в моем колледже, мы должны реализовать общий код, следуя указанному модулю.

Итак, я делаю класс, который занимает только Integer, Long, Doubleи String

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

Это мой класс:

    public Kubus(T tinggi, T panjang,T lebar ) {

        this.tinggi = tinggi;
        this.panjang = panjang;
        this.lebar = lebar;

    }

    public T getTinggi() {
        return tinggi;
    }

    public T getPanjang() {
        return panjang;
    }

    public T getLebar() {
        return lebar;
    }

    @Override
    public String toString() {
        return "tinggi: " + getTinggi() +
                "  - panjang: " + getPanjang() +
                " - lebar: " + getLebar();
    }

    public T getResultAsLong(){
        T = getPanjang() * getLebar();
    }
}

В методе getResultAslong он должен принимать тип данных Long, но у меня проблема в том, что операнд * нельзя использовать.В чем проблема?

Ответы [ 3 ]

4 голосов
/ 23 сентября 2019

Первое, что я хотел бы отметить, это то, что вы не можете напрямую определить класс, который только принимает определенный список типов.Вы можете связать T, скажем, только как подкласс типа 1 (или пересечение типов).

Для типов, перечисленных в вопросе, единственными общими супертипами этих типов являются Serializable и Object,Вы можете объявить переменную типа как:

class Kubus<T extends Serializable> { // or Kubus<T>, equivalent to T extends Object

, но затем вы можете создать экземпляр с любым T в пределах этой границы, например, Kubus<ArrayList<Frobnicator>>, поскольку ArrayList реализует Serializable.(Serializable также является довольно бесполезным типом для привязки, если вы на самом деле не хотите сериализовать Kubus с помощью встроенной сериализации. Перефразируя совет Джоша Блоха в Effective Java : «не»).

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

private Kubus(T tinggi, T panjang,T lebar ) { ... }

public static Kubus<Integer> ofInteger(Integer tinggi, Integer panjang, Integer lebar ) {
  return new Kubus<>(tinggi, panjang, lebar);
}

public static Kubus<Long> ofLong(Long tinggi, Long panjang, Long lebar ) {
  return new Kubus<>(tinggi, panjang, lebar);
}

// etc for other specific types.

Затем вы можете создавать экземпляры с помощью

Kubus<Integer> first = Kubus.ofInteger(1, 2, 3);
Kubus<Long> second = Kubus.ofLong(1L, 2L, 3L);

Все еще допустимо написать type Kubus<ArrayList<Frobnicator>> (или любой другой произвольныйтипа), но вы просто не можете создать его экземпляр.

Kubus<ArrayList<Frobnicator>> whatever = null;

Это фактически дает вам возможность решить конкретную проблему, о которой вы спрашивали (*).

Проблема в том, что вы не можете умножать произвольные вещи вместе.Здесь вам нужны средства для преобразования «вещи» в long, чтобы умножить ее.Приведение к Long не является безопасным выбором, потому что вы не можете разыграть, скажем, Integer или String до Long.

Поскольку вы хотите ограничить T дотолько определенные типы, вы также можете предоставить конвертер для безопасного преобразования типов.

Такой конвертер можно смоделировать с помощью ToLongFuntion<T>: для этого требуется T и возвращается long.Итак, измените ваш конструктор так, чтобы он принимал другой параметр:

private Kubus(T tinggi, T panjang,T lebar, ToLongFunction<T> converter ) { ... }

public static Kubus<Integer> ofInteger(Integer tinggi, Integer panjang, Integer lebar ) {
  return new Kubus<>(tinggi, panjang, lebar, i -> i.intValue());
}

public static Kubus<Long> ofLong(Long tinggi, Long panjang, Long lebar ) {
  return new Kubus<>(tinggi, panjang, lebar, lng -> lng.longValue());
}

// etc for other specific types.

Назначьте converter полю в конструкторе, а затем примените его в своем методе умножения, чтобы получить значение как длинное, которое можно умножить:

return converter.applyAsLong(getTinggi())
    * converter.applyAsLong(getPanjang())
    * converter.applyAsLong(getLebar());

(*) Я не собираюсь подразумевать, что вы можете использовать этот подход converter только с конструктором private: вы, конечно, можете сделать конструктор не приватными создать экземпляр непосредственно с помощью конструктора.Я просто подозреваю, что вы очень быстро устанете от повторения в письменном виде:

Kubus<Integer> first = new Kubus<>(1, 2, 3, Integer::longValue);
Kubus<Integer> second = new Kubus<>(1, 2, 3, Integer::longValue);
Kubus<Integer> third = new Kubus<>(1, 2, 3, Integer::longValue);
// ...
0 голосов
/ 23 сентября 2019

Если ваш тип T должен быть числом, вы можете определить его с помощью <T extends Number>, что обеспечит возможность вызова Number.longValue на любом T.К сожалению, вы специально заявляете, что это может быть String (который, вероятно, вы хотите преобразовать в long в getResultAsLong).

У вас есть несколько вариантов:

  1. не использовать генерики.Определите interface или abstract class с помощью метода longValue, а затем расширьте его для различных типов, которые вы хотите поддерживать.

  2. конвертируйте в long через Stringс Long.valueOf(getLabar().toString()).Это, по сути, преобразует все в строку перед преобразованием в long.Не элегантно.

  3. используйте instanceof Number и instanceof String, чтобы решить, как преобразовать их в long.

0 голосов
/ 23 сентября 2019

Если вы хотите выполнить операцию умножения (*), то сначала вам нужно привести значения getPanjang () и getLebar () к любому числовому формату, а затем выполнить операцию умножения.

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