2014-11-09 5 views
0

Previous questionИспользование ArrayList <Class?> для литья?

У меня есть следующий код:

ArrayList<Object> list = new ArrayList<Object>(); 
list.add("StringType"); 
list.add(5); 
list.add(new RandomClass()); 

List<Class<?>> classes = new ArrayList<>(); 
classes.add(String.class); 
classes.add(int.class); 
classes.add(RandomClass.class); 

for (int i = 0; i < list.size(); i++) { 
    if (classes.get(i).isInstance(list.get(i))) { 
     ... 
    } 
} 

if (isvalid) 
mymethod(...); 


public void mymethod(String string, int num, RandomClass randomClass){ } 

Теперь я пытаюсь преобразовать объект в правильный тип с методом, используя строку в качестве аргумента.

Вместо:

mymethod((String) list.get(0), (int) list.get(1), (RandomClass) list.get(2)); 

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

mymethod((define.get(0)) list.get(0), ....); 

Я также пытался использовать Class.cast (obj), но, конечно, он возвращает тип '?' который снова побеждает цель повторного использования его (String).

+0

Это ** не может быть безопасным по типу, поскольку вы можете изменять типы во время выполнения, вызывая «ClassCastException». Поэтому вы ** не можете ** иметь то, что хотите. –

ответ

2

Что такое безопасность типа?

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

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

String getName() { 
    return "name"; 
} 

компилятор знает, что «имя» должно быть String так что он может убедитесь, что этот код никогда не вызовет ошибку типа.

После того, как вы делаете что-то вроде:

int getNumber() { 
    (int) number; 
} 

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

Как это повлияет на вас?

Ваш код:

define.get(0).cast(list.get(0)) 

Вы хотите возвращаемый тип этого заявления быть типа get(0). Но компилятор не знает, во время компиляции, что возвращает define.get(0). Это подлежит обратному типу.

У вас есть List<Class<?>>, то есть a List класса «Мне все равно, какой тип». Затем вы используете члена этого List, чтобы наложить другого члена List - единственным результатом может быть «Мне все равно, какой тип».

Вы можете взломать вокруг этого с:

<T> T get(final int i) { 
    return (T) define.get(i).cast(list.get(i)); 
} 

Это будет счастливо компилировать:

final String thing = get(0); 

Как будет:

final int thing = get(0); 

т.е. все, что вы сделали это endogenise бросать. Условие ошибки все еще существует.

+0

Это решает проблему «взломать» там. Прежде чем я назову их методом, я бы проверил, был ли каждый объект правильного типа (часть isInstance в forloop). и если бы все параметры были действительными, я бы затем вызвал метод. Это я предполагаю, что это не должно приводить к ошибкам неправильного типа с помощью взлома. Разум, объясняющий, как работает (t) литье и возвращаемое значение T. Или, может быть, ссылку на чтение. – Tim

+0

Вы говорите, что никогда раньше не видели [generics] (https://docs.oracle.com/javase/tutorial/java/generics/)? Hm ... –

+0

О, ладно. Я видел это и читал его, но на самом деле не прочитал, как это работает. Школа действительно не учит таким вещам, так что да. – Tim

2

define.get(0).cast(list.get(0)) будет пытаться нанести list.get(0) на требуемый тип.

+0

Да, я знаю, но, например, get (0), это возвращаемое значение не типа String. Определение моего метода - метод (String string, int num, RandomClass randomclass) – Tim

+0

@ user755053 невозможно сделать то, что вы хотите. Найдите другой подход. Это похоже на проблему XY. –

0

, Вам не нужно хранить класс объекта отдельно

list.get(0).getClass() 

поможет вам класс хранимого объекта, а затем вы можете использовать то, что предложил @Eran

и

list.get(0).getClass().getName() 

доставит вам название строки вашего класса

1

Для того, чтобы иметь возможность выберите соответствующий метод, компилятор должен знать во время компиляции, каковы типы аргументов. Или, по крайней мере, общая категория, такая как List<?> и т. Д.

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

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

Вот соответствующий раздел от Java Language Specification.

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

+0

Я всегда думал, что перегрузка метода происходит во время выполнения? Где вы читали о том, как это происходит во время компиляции? Не могли бы вы разместить ссылку? –

+0

@ GermannArlington общеизвестно, что Java подключена во время компиляции. Вы можете вводить в заблуждение методы _overloaded_ с методами _overridden_, которые выбираются во время выполнения - последний называется полиморфизмом. –

+0

@ GermannArlington Добавлен ответ. – RealSkeptic

Смежные вопросы