Первое, что я хотел бы отметить, это то, что вы не можете напрямую определить класс, который только принимает определенный список типов.Вы можете связать 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);
// ...