如何在Java中使用泛型引用嵌套类型?

时间:2015-09-25 13:28:14

标签: java generics

如何创建引用嵌套泛型类型的泛型类?

我正在尝试创建一个Comparator类,它可以比较B的内部类型,而不想暴露这些类型的内容。在下面的例子中,我得到一个编译器警告,用于将我的T内部嵌套值原始转换为Comparable:

file2.txt

是否可以使用安全允许铸造来表示内部值?

我尝试过的事情:

  • 创建可比较(不可编译)的通配符:

    public class SSCCE {
    
        // Compare my A instances.
        class AComparator<T extends B> implements Comparator<T> {
    
            @Override
            public int compare(final T o1, final T o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        }
    
    
        class A extends B<Integer> {
            @Override Integer getValue() { return 1; }
        }
    
        class A2 extends B<String> {
            @Override String getValue() { return "Test String!"; }
        }
    
        abstract class B<T extends Comparable<T>> {
            abstract T getValue();
        }
    
        public static void main(String[] args) {
            SSCCE sscce = new SSCCE();
            AComparator<A> comparator = sscce.new AComparator<>();
            comparator.compare(sscce.new A(), sscce.new A());
        }
    }
    
  • 声明辅助通用参数类型(U),它只是推迟了问题:

    class AComparator2<T extends B<? extends Comparable<?>>> implements Comparator<T> {
    
        @Override
        public int compare(final T o1, final T o2) {
            Comparable<?> o1value = (Comparable) o1.getValue();
            Comparable<?> o2value = (Comparable) o2.getValue();
            return o1value.compareTo(o2value);
        }
    }
    

这个比较器不是要比较A类的两个实例,而是它们内容的一部分。

6 个答案:

答案 0 :(得分:7)

通配符解决方案不起作用

    class AComparator2<T extends B<?>> {
        public int compare(T o1, T o2)

因为T太宽松了;我们无法确保两个T可以相互比较 - o1可能是B<X1>o2B<X2>,和X1, X2是两种不同的类型。

您的第3个解决方案会将T限制为特定的B<U>

    class AComparator3<T extends B<U>, U extends Comparable<U>>

这完美无缺;除了使用网站必须指定U,即使U可以从T中删除。

    AComparator3<A, Integer>  
                    ^^^^^^^ duh!

这很烦人。之前已经从其他用例中提出了同样的问题。没有好的答案。

幸运的是,在您的情况下,在使用网站的任何地方都不需要U,因此我们可以简单地使用通配符

    AComparator3<A, ?> comparator = sscce.new AComparator3<>();
    comparator.compare(sscce.new A(), sscce.new A());

实际上,比较器是Comparator<A>,这可能就是你所需要的。我们也可以创建一种方便的方法来隐藏new的丑陋。所以你可能会做类似

的事情
    Comparator<A> comparator = sscce.comparator(); 

答案 1 :(得分:3)

您是否考虑过Java 8解决方案?

 Comparator<A> comparator = ((t1,t2)-> t1.getValue().compareTo(t1.getValue()));
  comparator.compare(sscce.new A(), sscce.new A());

答案 2 :(得分:3)

您可能对比较器感兴趣,比较器应该比较延伸B的类型,但前提是它们具有相同的可比类型。这样的比较器可能看起来像

class AComparator<T extends Comparable<T>> implements Comparator<B<T>> {
    @Override
    public int compare(final B<T> o1, final B<T> o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

你可以像

一样使用它
AComparator<Integer> comparator = sscce.new AComparator<>();
comparator.compare(sscce.new A(), sscce.new A());
comparator.compare(sscce.new A(), sscce.new A2());//compilation error

答案 3 :(得分:1)

为了实现您想要的目标,您需要更改一些内容,我相信如果只实现Generic Comparator

首先,AComparator应该如下:

pipe  = subprocess.Popen('...')

timeout =  10

results = pipe.waitOrTerminate(timeout)

您不需要B类,因为A和A2将直接实施Comparable。只需删除它。

你的A和A2课程:

// Compare my A instances.
class AComparator<T extends Comparable<T>> implements Comparator<T> {

    @Override
    public int compare(final T o1, final T o2) {
        return o1.compareTo(o2);
    }
}

请务必阅读Comparable的文档,了解返回值的预期结果。

这有意义吗?

PS:我没有测试这些代码,它们只是我的头脑。

答案 4 :(得分:1)

另一种选择是让B直接实现Comparable,因为你使用getValue()来进行比较。下面摆脱了警告:

import java.util.Comparator;

public class SSCCE {
   class A extends B<Integer> {
      @Override Integer getValue() { return 1; }
   }

   class A2 extends B<String> {
      @Override String getValue() { return "Test String!"; }
   }

   abstract class B<T extends Comparable<T>> implements Comparable<B<T>>{
      abstract T getValue();

      @Override
      public int compareTo(B<T> other)
      {
         return getValue().compareTo(other.getValue());
      }
   }

   public static void main(String[] args) {
      SSCCE sscce = new SSCCE();
      Comparator.naturalOrder().compare(sscce.new A(), sscce.new A());
   }
}

答案 5 :(得分:1)

我想这就是你想要的:

public class SSCCE {

    static class BComparator<E extends Comparable<E>> implements Comparator<B<E>> {

        @Override
        public int compare(final B<E> o1, final B<E> o2) {
            return o1.getValue().compareTo(o2.getValue());
        }
    }

    static class A extends B<Integer> {
        @Override Integer getValue() { return 1; }
    }

    static class A2 extends B<String> {
        @Override String getValue() { return "Test String!"; }
    }

    static abstract class B<T extends Comparable<T>> {
        abstract T getValue();
    }

    public static void main(String[] args) {
        SSCCE sscce = new SSCCE();
        BComparator<Integer> comparator = new BComparator<>();
        comparator.compare(new A(), new A());

        BComparator<String> comparator2 = new BComparator<>();
        comparator2.compare(new A2(), new A2());
    }
}

如果您不希望您的比较器能够比较B的两个不同子类的实例(如A2 extends B<String>A3 extends B<String>),则以下工作:

public class SSCCE {

    static class BComparator<E extends Comparable<E>, T extends B<E>> implements Comparator<T> {

        @Override
        public int compare(final T o1, final T o2) {
            return o1.getValue().compareTo(o2.getValue());
        }
    }

    static class A extends B<Integer> {
        @Override Integer getValue() { return 1; }
    }

    static class A2 extends B<String> {
        @Override String getValue() { return "Test String!"; }
    }

    static abstract class B<T extends Comparable<T>> {
        abstract T getValue();
    }

    public static void main(String[] args) {
        SSCCE sscce = new SSCCE();
        BComparator<Integer, A> comparator = new BComparator<>();
        comparator.compare(new A(), new A());

        BComparator<String, A2> comparator2 = new BComparator<>();
        comparator2.compare(new A2(), new A2());
    }
}