Универсальная переменная экземпляра в неуниверсальном классе

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

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

String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);

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

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

public class MyClass {
    // This doesn't work as T isn't defined
    final List<T extends Comparable<? super T>> values;

    public <T extends Comparable<? super T>> MyClass (T... values) {
        this.values = new ArrayList<T>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable<? super T>> List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

ошибка на строке объявления переменной:

Syntax error on token "extends", , expected

Любая справка очень ценилась бы.

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

@Mark: От всего я читал, я действительно хочу сказать "T, тип, который сопоставим с собой", не только "T тип, который сопоставим". Однако следующий код не работает также:

public class MyClass {
    // This doesn't work
    final List<? extends Comparable> values;

    public <T extends Comparable> MyClass (T... values) {
        this.values = new ArrayList<T>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable> List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

ошибка на добавляет строку:

The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)

ошибка на строке вида:

Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>

Заключение:

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

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

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

11
задан RHSeeger 7 July 2010 в 04:50
поделиться

7 ответов

Я думаю, что простой ответ заключается в том, что вы не можете этого сделать. Если тип одного из атрибутов класса зависит от параметра типа, этот параметр должен быть объявлен на уровне класса. И я не думаю, что это «имеет смысл» иначе.

Если T в вашем примере не является параметром типа класса, что это такое? Это не может быть параметром типа метода, потому что этот тип определяется способом вызова метода. (Если метод вызывается в разных статических контекстах с разными предполагаемыми типами для T , каков условный тип T в контексте объявления атрибута?)

Итак, чтобы верните это к тому, что вы пытаетесь сделать здесь, экземпляр MyClass будет содержать элементы определенного типа, и вы хотите иметь возможность вставлять и удалять элементы статически безопасным способом. Но в то же время вы не хотите, чтобы вы могли сказать, что это за тип. Итак, как компилятор должен статически различать экземпляр MyClass , который содержит (скажем) Integer объектов, и экземпляр, содержащий объекты String ?

Я даже не думаю, что вы могли бы реализовать это с помощью явной динамической проверки типов. (Я думаю, что стирание типа означает, что реализация метода getSortedList () не может определить, какой фактический тип привязан к его возвращаемому типу.)

Нет. Реальное решение - сделать MyClass универсальным классом, который объявляет параметр типа T ; например

public class MyClass <T extends Comparable<T>> {

и удалите объявление параметра типа уровня метода T из двух методов.

7
ответ дан 3 December 2019 в 09:40
поделиться

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

public class MyClass {

    final private List<Comparable> values;

    public <T extends Comparable<? super T>>MyClass(T... values){
        this.values = new ArrayList<Comparable>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable<? super T>> List<T> getSortedLst() {
        Collections.sort(this.values);
        return (List<T>)this.values;
    }

}

Быстрый тест с использованием следующего показывает, что для классов, реализующих Comparable (таких как Integer и String) MyClass ведет себя как ожидалось, но выдаст ошибку компиляции для классов, не реализующих Comparable:

    class Junk { }

    public static void main(String[] args){
        MyClass s = new MyClass(1,2,3);
        System.out.println(s.getSortedLst());

        MyClass a = new MyClass("c", "a", "b");
        System.out.println(a.getSortedLst());

        MyClass c = new MyClass(new Junk());
    }
2
ответ дан 3 December 2019 в 09:40
поделиться

Рассмотрите это так (то, что я собираюсь сказать, не соответствует действительности. Но это иллюстрирует, почему вам нужно делать то, что вам нужно):

class Foo<T>
{
    private T value;

    T getValue() { return value; }
    void setValue(T val) {value = val; }
}

// some code that uses the above class

Foo<Integer> iFoo = new Foo<Integer>();
Foo<String> sFoo = new Foo<String>();
iFoo.setValue(5);
sFoo.setValue("Hello");

Когда это происходит, компилятор ( НЕ ДЕЙСТВИТЕЛЬНО ДЕЛАЕТ ТО, ЧТО Я НАСКОЛЬКО СКАЗАТЬ!) Генерирует следующий код:

class IntegerFoo
{
    private Integer value;

    Integer getValue() { return value; }
    void setValue(Integer val) {value = val; }
}

class StringFoo
{
    private String value;

    String getValue() { return value; }
    void setValue(String val) {value = val; }
}

// some code that uses the above class

IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");

Если бы вы могли параметризовать переменные / методы экземпляра без параметризации класса, вышеуказанная вещь (ЭТО НЕ РЕАЛЬНОСТЬ!) Не сработала бы. .

То, что вы пытаетесь сделать, должно быть возможно с помощью статических методов, но я не думаю, что вы этого хотите.

Можете ли вы объяснить, почему вы хотите выполнить код, который пытаетесь сделать? Возможно, мы сможем придумать лучший способ делать то, что вы хотите, в рамках языка.

1
ответ дан 3 December 2019 в 09:40
поделиться

Я считаю, что следующее достигнет того, что вы хотите (более сильная типизация Comparable). Это предотвратит добавление в список объектов Comparable, не относящихся к вашему интерфейсу, и позволит использовать несколько реализаций.

public class test<T extends ComparableType> {


final List<T> values = new ArrayList<T>();
  public test (T... values) {
      for(T item : values) {
          this.values.add(item);
      }
  }

  public List<T> getSortedLst() {
      Collections.sort(this.values);
      return Collections.unmodifiableList(this.values);
  }
}

public interface ComparableType extends Comparable<ComparableType> {}

public class ConcreteComparableA implements ComparableType {
  @Override
  public int compareTo(ComparableType o) {
    return 0;
  }
}

public class ConcreteComparableB implements ComparableType {
  @Override
  public int compareTo(ComparableType o) {
    return 0;
  }
}

edit:

Я знаю, что это может быть очевидно; но если вы не хотите, чтобы класс был Generic, это решение также будет работать с:

 public class test {
  final List<ComparableType> values = new ArrayList<ComparableType>();

  public test (ComparableType... values) {
      for(ComparableType item : values) {
          this.values.add(item);
      }
  }

  public List<ComparableType> getSortedLst() {
      Collections.sort(this.values);
      return Collections.unmodifiableList(this.values);
  }
}
1
ответ дан 3 December 2019 в 09:40
поделиться

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

static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}

final MyList<?> values;

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

0
ответ дан 3 December 2019 в 09:40
поделиться
public class MyClass<T extends Comparable<? super T>> {
    // This doesn't work as T isn't defined
    final List<T> values;

    public MyClass (T... values) {
        this.values = new ArrayList<T>(Arrays.asList(values));
    }

    public List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}
-1
ответ дан 3 December 2019 в 09:40
поделиться

Я бы сделал так (я сделал это в виде списка или массива), если вам не нужны переменные/методы экземпляра:

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class MyClass
{
    public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
    {
        final List<T> temp;

        temp = new ArrayList<T>(vals.length);
        temp.addAll(Arrays.asList(vals));
        Collections.sort(temp);

        return (Collections.unmodifiableList(temp));
    }

    public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
                                                              final T ...    vals)
    {
        final T[] temp;

        temp = (T[])Array.newInstance(clazz,
                                 vals.length);
        System.arraycopy(vals,
                         0,
                         temp,
                         0,
                         vals.length);
        Arrays.sort(temp);

        return (temp);
    }

    public static void main(final String[] argv)
    {
        final List<String> list;
        final String[]     array;

        list = MyClass2.asSortedList("c", "a", "b");
        System.out.println(list);

        array = MyClass2.asSortedArray(String.class, "z", "y", "x");
        System.out.println(Arrays.deepToString(array));
    }
}
1
ответ дан 3 December 2019 в 09:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: