#java #generics #casting
#java #универсальные #Кастинг
Вопрос:
Мне нужно преобразовать строку в значение переменной. Я нашел решение только для C #. Мне это нужно на Java.
public class Property<T> {
T value;
public void setValue(String input){
if(value instanceof String){
value= input; // value is type of T not type of string (compilation error)
// incompatible types: String cannot be converted to T
}
if(value instanceof int){
//parse string
}
if(value instanceof boolean){
//parse string
}
...
}
}
Комментарии:
1. если вы не знаете, что такое T, вы не сможете преобразовать в него. Вы можете выполнить приведение, но это может легко привести к сбою. Плохой дизайн, я бы сказал.
2. Что такое «определенный тип универсальной переменной»?
3. Это не имеет смысла, как это может не быть
String
, если аргумент имеет тип string.4. Я имею в виду тип T, который я распознаю с помощью instanceof
5. @SpeedEX505 Не буду врать, я нашел это методом проб и ошибок. Для меня это тоже очень непонятно. Но я не возражаю против грязных трюков, пока они выполняют мои требования xD
Ответ №1:
Это не так, как это работает. Однако вы можете использовать полиморфизм для достижения полезного результата.
Решение с полиморфизмом
Базовое универсальное (и абстрактное) свойство
public abstract class Property<T> {
T value;
public abstract void setValue(String input);
}
Свойство для строк
public class StringProperty extends Property<String> {
@Override
public void setValue(String input) {
this.value = input;
}
}
Свойство для целых чисел
public class IntegerProperty extends Property<Integer> {
@Override
public void setValue(String input) {
this.value = Integer.valueOf(input);
}
}
Не уверен, какова ваша фактическая цель, но этот подход может сработать.
Обратите внимание, что input instanceof T
произойдет сбой из-за удаления типа. Это не сработает.
Решение с Class<T>
в качестве аргумента
Если подробнее остановиться на вашем подходе, это могло бы сработать, но это НЕКРАСИВО.
Некрасиво и не очень удобно. Понятия не имею, зачем вам это нужно, tbh.
class Property<T> {
public T value;
private final Class<T> clazz;
public Property(Class<T> clazz) {
super();
this.clazz = clazz;
}
@SuppressWarnings("unchecked")
public void setValue(String input) {
if (clazz.isAssignableFrom(String.class)) {
value = (T) input;
} else if (clazz.isAssignableFrom(Integer.class)) {
value = (T) Integer.valueOf(input);
} else if (clazz.isAssignableFrom(Boolean.class)) {
value = (T) Boolean.valueOf(input);
} else if (clazz.isAssignableFrom(Double.class)) {
value = (T) Double.valueOf(input);
} else {
throw new IllegalArgumentException("Bad type.");
}
}
}
Используется примерно так:
Property<String> ff = new Property<>(String.class);
ff.setValue("sdgf");
Property<Integer> sdg = new Property<>(Integer.class);
sdg.setValue("123");
System.out.println(ff.value);
System.out.println(sdg.value);
Решение с Reflection
По-видимому, можно определить параметр, используемый для создания экземпляра property .
Эта маленькая волшебная формула дает вам именно это:
(Class<?>) getClass().getTypeParameters()[0].getBounds()[0]
Я даже не знаю, как мне удалось это найти. Ну, вот и все:
class Property<T> {
T value;
@SuppressWarnings("unchecked")
public void setValue(String input)
{
// BEHOLD, MAGIC!
Class<?> clazz = (Class<?>) getClass().getTypeParameters()[0].getBounds()[0];
if (clazz.isAssignableFrom(String.class)) {
value = (T) input;
} else if (clazz.isAssignableFrom(Integer.class)) {
value = (T) Integer.valueOf(input);
} else if (clazz.isAssignableFrom(Boolean.class)) {
value = (T) Boolean.valueOf(input);
} else if (clazz.isAssignableFrom(Double.class)) {
value = (T) Double.valueOf(input);
} else {
throw new IllegalArgumentException("Bad type.");
}
}
}
И не смотрите на меня, я бы не стал это использовать. У меня есть некоторый здравый смысл.
Комментарии:
1. У меня был этот код раньше, но я пытался его избежать. Я думаю, что я проанализирую string на более высоком уровне, а затем вызову метод setValue (T input) с типом T. Но спасибо.
2. Вам пришлось бы передать класс T в качестве аргумента конструктору Property. Тогда вы могли бы сравнить этот класс с некоторыми известными типами и перейти к нему — но это НЕКРАСИВО. Полуморфизм здесь нужно использовать, а не избегать.
3. Что ж, действительно есть вариант использования man. Представьте, что простой текстовый конфигурационный файл, XML, результат веб-сервиса (что угодно) выдает вам сопоставление <string,строка>, и вам действительно нужен один универсальный метод, скажем
<V> V GetValueByKey(string key)
, который выдает вам подходящее значение для соответствующего ключа, но желаемого типа — вместо строки.
Ответ №2:
Я нашел новый способ, используя Spring.
public static <T> T convertJsonToObject(String json, Class<T> valueType) {
try {
return json != null ? new ObjectMapper().readValue(json, valueType) : null;
} catch (Exception e) {
return null;
}
}
private static void processValidate(Class<?> valueClass, String value) {
Object parsedValue = Utils.convertJsonToObject(value, valueClass);
// logic
}
Ответ №3:
Другой способ, использующий отражение, — это
public <T> T setValue(String value, Class<T> valueType) {
try {
return (T) valueType.getDeclaredMethod("valueOf", String.class).invoke(null, value);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}