Comparing generic types (extends vs implements and within the context of LinkedList using nodes private class)

huangapple go评论61阅读模式
英文:

Comparing generic types (extends vs implements and within the context of LinkedList using nodes private class)

问题

I have a standard LinkedList class with nodes that have data fields of generic type and I'm trying to compare them but not sure how I should go about it.

我的标准LinkedList类具有泛型数据字段的节点,我试图比较它们,但不确定该如何操作。

My node class

我的节点类

private static class Node<E>
{
E data;
Node<E> prev;
Node<E> next;
}

Basically, I'm trying to do

基本上,我尝试执行以下操作

if(nodeA.data > newData)
//do something

如果(nodeA.data > newData)
//执行某些操作

Should I be doing something like

我应该像这样做吗?

public class MyLinkedList<E extends Comparable<E>>
or
public class MyLinkedList<E> implements Comparable<E>

是这样做吗?

And for both ways, do I implement my own compareTo method?

对于这两种方式,我是否需要实现自己的compareTo方法?

I've tried this but the compareTo usually looks like

我尝试过这个,但compareTo通常如下所示

public int compareTo(E data)
{
if(this > data)
return 1;
//add others
}

这里,"this"将引用我的LinkedList类,而不是泛型类型E。

在这里,"this"将引用我的LinkedList类,而不是泛型类型E。

Thank you

谢谢

英文:

I have a standard LinkedList class with nodes that have data fields of generic type and I'm trying to compare them but not sure how I should go about it.

My node class

private static class Node&lt;E&gt; 
{
	E data;
	Node&lt;E&gt; prev;
	Node&lt;E&gt; next;
}

Basically, I'm trying to do

if(nodeA.data &gt; newData)
     //do something

Should I be doing something like

public class MyLinkedList&lt;E extends Comparable &lt;E&gt;&gt;

or
public class MyLinkedList&lt;E&gt; implements Comparable &lt;E&gt;

And for both ways, do I implement my own compareTo method?
I've tried this but the compareTo usually looks like

public int compareTo(E data)
{
	if(this &gt; data)
		return 1;
    //add others
}

And here, the 'this' would refer to my LinkedList class, not the generic type E.

Thank you

答案1

得分: 1

If you want to compare the data contained in the node, then public class MyLinkedList&lt;E extends Comparable&lt;E&gt;&gt; is the way to go, since this guarantees that the generic type E provides a compareTo(...)-method. In this case, implementing the compareTo-method is a job for the developer writing the type.

如果您想比较节点中包含的数据,那么public class MyLinkedList&lt;E extends Comparable&lt;E&gt;&gt;是合适的方式,因为这确保了泛型类型E提供了compareTo(...)方法。在这种情况下,实现compareTo方法是开发人员编写类型的任务。

英文:

If you want to compare the data contained in the node, then public class MyLinkedList&lt;E extends Comparable&lt;E&gt;&gt; is the way to go, since this guarantees that the generic type E provides a compareTo(...)-method. In this case, implementing the compareTo-method is a job for the developer writing the type.

If you define public class MyLinkedList&lt;E&gt; implements Comparable&lt;E&gt; then you make a node comparable to E, but since E is unbound, it basically gets erased to Object <s>and this really would not give you any real possibility to compare objects</s>. Since one can access the variable of type E only as if it were an Object, one basically has no access to relevant information to implement a meaningful order. I would question such an order, or at least ask for the specific use case for this order.



Two Remarks:

Since Java does not support operator overloading, one cannot write

nodeA.data &gt; something

but call the compareTo-Method and evaluate its return value, e.g.:

nodeA.data.compareTo(something) &gt; 0

There is also another way to allow types that do not implement Comparable by enforcing that a Comparator&lt;E&gt; is passed along. PriorityQueue uses this approach.

答案2

得分: 0

Unless I've completely misunderstood your question, then since you said...

Basically, I'm trying to do

if(nodeA.data > newData)
     //do something

...then to me it makes more sense to have the type parameter of your Node implement Comparable instead of the one of your List...

public class LinkedList<E> { 

    public static class Node<E extends Comparable<E>> {

        E data;

        Node<E> next;
 
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.data = element;
            this.next = next;
            this.prev = prev;
        }
        
        public E getData() { return this.data; }
    }
}

Then whatever your data is, it would have to implement Comparable...

public class Foo implements Comparable<Foo> { 

    private int x;
    
    public Foo(int x) { this.x = x; }
    
    public int compareTo(Foo that) { 
        return this.x < that.x ? -1 : this.x == that.x ? 0 : 1;
    }
}

...allowing you to do something closer to what you specified with your if(nodeA.data > newData) pseudocode...

public class DeduperAnswer { 

    static public void main(String... args) { 
        
        LinkedList.Node<Foo> node1 = new LinkedList.Node<>(null, new Foo(10), null);
        LinkedList.Node<Foo> node2 = new LinkedList.Node<>(null, new Foo(20), null);
 
        if (node2.getData().compareTo(node1.getData()) > 0) { 
            /* ...this is NOT how you'd use it, of course...*/
        }
    }
}

You can see a quick and dirty working example here.

英文:

Unless I've completely misunderstood your question, then since you said&hellip;

> Basically, I'm trying to do
>
> if(nodeA.data > newData)
> //do something

&hellip;then to me it makes more sense to have the type parameter of your Node implement Comparable instead of the one of your List&hellip;

public class LinkedList&lt;E&gt;{ 

    public static class Node&lt;E extends Comparable&lt;E&gt;&gt; {

        E data;

        Node&lt;E&gt; next;

        Node&lt;E&gt; prev;


        Node(Node&lt;E&gt; prev, E element, Node&lt;E&gt; next) {

            this.data = element;

            this.next = next;

            this.prev = prev;

        }
    
        public E getData( ){ return this.data; }

    }
}

Then whatever your data is, it would have to implement Comparable&hellip;

public class Foo implements Comparable&lt;Foo&gt;{ 
    
    private int x;
    
    public Foo(int x){ this.x = x; }
    
    public int compareTo(Foo that){ 
        return this.x &lt; that.x ? -1 : this.x == that.x ? 0 : 1;
    }
}

&hellip;allowing you to do something closer to what you specified with your if(nodeA.data &gt; newData) pseudocode&hellip;

public class DeduperAnswer{ 
    
    static public void main(String... args){ 
        
        LinkedList.Node&lt;Foo&gt; node1 = new LinkedList.Node&lt;&gt;(null, new Foo(10), null);
        LinkedList.Node&lt;Foo&gt; node2 = new LinkedList.Node&lt;&gt;(null, new Foo(20), null);
 
        if (node2.getData().compareTo(node1.getData()) &gt; 0){ 
            /* ...this is NOT how you&#39;d use it, of course...*/
        }
    }
}

You can see a quick and dirty working example here.

答案3

得分: 0

TL;DR: 尽管发生类型擦除,但绝对可以比较两个参数化实例化的_Comparable_某些泛型类型_T<E>_,而不考虑类型擦除。

一个回答说: 但由于_E_未绑定,它基本上被擦除为_Object_,这实际上不会给您任何实际比较对象的可能性。

类型擦除会发生。然而,在上述引用假设的上下文中,类型擦除不是该上下文中的问题。该上下文和原始问题的问题是: 当在使用现实类型参数实例化给定参数化类型时,_E_最终将成为某个特定类型。

@Turing85的假设提出了这个问题:

Q: _无论_E_的最终类型是什么,它是否必须实现_Comparable_以便有"任何实际比较对象的可能性"?

A: 。在原始问题的上下文中,与_E_实现_Comparable_无关。在那个上下文中,与_MyLinkedList_实现_Comparable_有关。

声明一个带有未绑定类型参数_E_的泛型类不排除比较对象的可能性。例如,可能存在某种用例,需要_MyLinkedList<MyLinkedList<Foo>>,其中外部参数化类型中的_未限定 E_是 MyLinkedList<Foo>,而内部参数化类型中的_未限定_ E_是 Foo

这个工作演示中,我实现了一个简化的链表的代表模型。在我的简化模型中,Bar_不实现_Comparable。_MyLinkedList<E>本身确实实现_Comparable<E>

一个使用示例...

public class Bar { 

    private int y;

    public Bar(int y){ 
        this.y = y;
    }				
}
...
MyLinkedList&lt;Bar&gt; list1 = new MyLinkedList&lt;&gt;();
MyLinkedList&lt;MyLinkedList&lt;Bar&gt;&gt; list2 = new MyLinkedList&lt;&gt;();
MyLinkedList&lt;Bar&gt; list3 = new MyLinkedList&lt;&gt;();
...
list1.add(new Bar(100));
list2.add(list3);  
list3.add(new Bar(101));
...
if (list2.compareTo(list1) != 0){ ... }
...

单击演示顶部的绿色开始按钮。然后,您可以观察到_E_在_MyLinkedList<E>_的声明中没有界限并不重要。_Bar_不实现_Comparable_也不重要。

还值得重申: 在我的演示模型中,Bar_不实现_Comparable

还值得指出的是,无论发生类型擦除,_stdout_中观察到的内容都显示出,无论此处显示的_节点_的运行时类型是什么,它都具有_类型_Bar_的所有公共、非静态成员。

英文:

TL;DR: It is absolutely possible to compare two Comparable parameterized instantiations of some generic type T&lt;E&gt; regardless of type erasure.


One answer said&hellip;

> „&hellip;but since E is unbound, it basically gets erased to Object and this really would not give you any real possibility to compare objects&hellip;“

Type erasure happens. However — at least in the context of the quoted hypothesis above — type erasure is not the issue in that context. The issue in that context and in that of the original question is: E will ultimately be some specific type when a given parameterized type is instantiated by an actual type argument at the use site.

@Turing85's hypothesis raises this question:

Q: Whatever the ultimate type of E is, is it mandatory for it to implement Comparable in order for there to be „any real possibility to compare objects“?

A: No. In the context of the original question, it's not about E implementing Comparable. In that context, it's about MyLinkedList implementing Comparable.

Declaring a generic class with an unbound type parameter E does not preclude the possibility to compare objects. For example there could be some use case where it's necessary to have MyLinkedList&lt;MyLinkedList&lt;Foo&gt;&gt;; where the unbounded E is MyLinkedList&lt;Foo&gt; in the outer parameterized type and the unbounded E is Foo in the inner parameterized type.

In this working demonstration I've implemented a simplified representative model of a linked list. In my simplified model,Bar does not implement Comparable. MyLinkedList&lt;E&gt; itself does implement Comparable&lt;E&gt; though.

A usage example&hellip;

public class Bar { 

    private int y;

    public Bar(int y){ 
        this.y = y;
    }				
}
...
MyLinkedList&lt;Bar&gt; list1 = new MyLinkedList&lt;&gt;();
MyLinkedList&lt;MyLinkedList&lt;Bar&gt;&gt; list2 = new MyLinkedList&lt;&gt;();
MyLinkedList&lt;Bar&gt; list3 = new MyLinkedList&lt;&gt;();
...
list1.add(new Bar(100));
list2.add(list3);  
list3.add(new Bar(101));
...
if (list2.compareTo(list1) != 0){ ... }
...

Click the green Start button at the top of the demo. Then you can observe that it doesn't matter that E has no bounds in the declaration of MyLinkedList&lt;E&gt;. It does not matter that Bar does not implement Comparable.

It is absolutely possible to compare two Comparable parameterized instantiations of MyLinkedList&lt;E&gt; with no problem&hellip;

...
[node -&gt; [node -&gt; Bar: y=101]] is greater than [node -&gt; Bar: y=100]
...

It's worth repeating: In my demonstration model, Bar does not implement Comparable.

It's worth pointing out too that regardless of type erasure, what's observed in stdout shows that whatever the runtime type of the node displayed here is, it has all the public, non-static members of type Bar.

huangapple
  • 本文由 发表于 2020年8月2日 03:41:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63209375.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定