2015-10-12 5 views
2

Просто играя с дженериками и т. Д. На Java, столкнулась с потенциальной проблемой. Вот упрощенная версия того, что я думалМассив дженериков в Java, обеспечить, чтобы все были одного типа?

public class Test<T> { 
    private T[] arrayOfGenerics; 
    int top; 

    public Test(int size) { 
     arrayOfGenerics = (T[]) new Object[size]; 
     top = 0; 
    } 

    public void add(T toAdd) { 
     arrayOfGenerics[top++] = toAdd; 
    } 

    public static void main(String[] args) { 
     Test myTest = new Test(10); 
     myTest.add("Some String"); //First value added is a String 
     myTest.add(12);    //Way to make this NOT work, since myTest should only accept Strings now 
    } 

} 

Очевидно, что это не имеет особого смысла, производство мудрый, но я думал, для более сложных структур данных, где вы хотели бы иметь гибкость дженериков, но по-прежнему обеспечивать все они должны быть одного типа. Который является ужасным способом объяснить это, но, вернувшись к приведенному выше примеру кода, будет ли способ сделать так, чтобы, когда кто-то создал экземпляр и экземпляр Test, они должны были указать тип arrayOfGenerics и застрять с ним , либо через конструктор, либо, возможно, только на основе первого типа значения, которое добавлено?

Другой способ объяснить это, скажем, вы реализуете свою собственную структуру данных Stack или LinkedList. Вы хотите, чтобы это был стек всего одного и того же объекта. Это могут быть строки, целые числа, что угодно, но нужно «выбрать» и придерживаться его.

+4

Вы в настоящее время используют [необработанный тип] (https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html). Попробуйте 'Test test = new Test <>();' –

ответ

4

Я думаю, что вы не используете дженериков эффективно здесь. Напр. выполнив следующие действия:

// With this statement, the types that can be contained in the 
// instance is fixed now. 
Test<String> myTest = new Test<>(10); 
myTest.add("Some String"); // this will work 
myTest.add(12); // this won't compile 

Ты декларировать Test иметь общий тип, но, в исходном коде, вы не использовать его при построении экземпляра. Что эффективно приводит к примеру Test<Object>.

В Java дженерики были модернизированы, и поскольку они не хотели нарушать обратную совместимость, им приходилось разрешать создание «сырых» экземпляров. Тем не менее, компилятор должен по-прежнему давать вам предупреждения о «сырых типах», и, вероятно, IDE попросит вас использовать @SuppressWarnings("unchecked"), чтобы сделать его явным, что вы используете непараметрированные типы.

Что касается обеспечения того, чтобы пользователь удостоверился, что он помещается в правильный тип, лучше всего выполнить проверку времени выполнения. То есть, например. конструктор может принять Class в качестве аргумента. И во всех методах вы убедитесь, что данные аргументы имеют правильный тип. Но это не дает вам возможность проверять время компиляции. Ошибки будут известны только во время выполнения.

Другое дело, что после того, как вы убедитесь, что вы правильно разработали свой API с помощью дженериков, вам, вероятно, не стоит беспокоиться о том, как применять эти типы. Если пользователи API не хотят использовать определенные типы, независимо от предупреждений компилятора, возможно, они действительно хотят использовать raw-type (или, может быть, они не знают лучше, и они не читают Effective Java). Даже собственные API Java не прилагают дополнительных усилий в этой области. Напр. следующий код работает, и не выбрасывает никаких исключений во время выполнения:

List list = new ArrayList<String>(); 
list.add("xyz"); 
list.add(123); 
+0

Хорошо, что работает, да, но это зависит от человека, создающего экземпляр класса для указания типа. Есть ли способ обеспечить выполнение этого требования внутри самого класса? –

0

Вы должны указать тип Generic, как Test<String> myTest = new Test<>(10); для класса, если вы хотите, чтобы весь класс содержит то же самое тип объектов.

Тогда ваш класс не может добавить другой тип Objects. См. Следующий пример.

Test<String> myTest = new Test(10); 
  1. myTest.add("Some String"); //works fine
  2. myTest.add(12); //not works

Вы установили размер массива в Constructor. Таким образом, вы не можете превышать указанный размер. Сделайте следующие изменения, чтобы сделать размер случайным.

//constructor 
public Test() { 
    top = 0; 
    arrayOfGenerics = (T[]) new Object[top]; 
} 

//add method 
public void add(T toAdd) { 
    top++; 
    T[] newArray = (T[]) new Object[top]; 
    newArray[top - 1] = toAdd; 
    System.arraycopy(arrayOfGenerics, 0, newArray, 0, top - 1); 
    arrayOfGenerics = newArray; 
} 
Смежные вопросы