Java Generics FAQs - Type Parameters (转)

本文探讨了Java泛型中的类型参数基础和边界。包括什么是类型参数、有界类型参数、允许的类型参数边界,以及如何使用类型参数作为边界等常见问题。并解释了类型参数边界为类类型时的成员访问权限,以及如何理解'Enum>'这样的泛型约束。
摘要由CSDN通过智能技术生成

Type Parameters

Fundamentals

What is a type parameter?

A place holder for a type argument.
Generic types have one or more type parameters. 

Example of a parameterized type: 

interface Comparable<E>  { 
  int compareTo(E other);
}
The identifier E is a type parameter. Each type parameter is replaced by a type argument when an instantiation of the generic type, such as Comparable<Object> or Comparable<? extends Number> , is used.
LINK TO THIS TypeParameters.FAQ001
REFERENCES How is a generic type defined?
What is a bounded type parameter?
Where is a type parameter visible (or invisible)?

What is a bounded type parameter?

A type parameter with one or more bounds.  The bounds restrict the set of types that can be used as type arguments and give access to the methods defined by the bounds.
When you declare a type parameter T and use it in the implementation of a generic type or method, the type parameter T still denotes an unknown type.  The compiler knows that T is a place holder for a type, but it does not know anything about the type.   This is okay in some implementations, but insufficient in others. 

Example (of a generic type without bounds): 

public class Hashtable<Key,Data> {
  ... 
  private static class Entry<Key,Data> {
    private Key key; 
    private Data value;
    private int hash;
    private Entry<Key,Data> next;
    ...
  }
  private Entry<Key,Data>[] table; 
  ... 
  public Data get(Key key) {
    int hash = key.hashCode() ;
    for (Entry<Key,Data> e = table[hash & hashMask]; e != null; e = e.next) {
      if ((e.hash == hash) && e. key.equals(key) ) {
        return e.value;
      }
    } 
    return null;
  }
}
The implementation of class Hashtable invokes the methods hashCode and equals on the unknown Key type.  Since hashCode and equals are methods defined in class Object and available for all reference types, not much need to be known about the unknown Key type.  This changes substantially, when we look into the implementation of sorted sequence. 

Example (of a generic type, so far without bounds): 

public interface Comparable<T> {
  public int compareTo(T arg);
}
public class TreeMap<Key,Data>{
  private static class Entry<K,V> {
     K key;
     V value;
     Entry<K,V> left;
     Entry<K,V> right;
     Entry<K,V> parent;
  }
  private transient Entry<Key,Data> root;
  ...
  private Entry<Key,Data> getEntry(Key key) {
     Entry<Key,Data> p = root;
     Key k = key;
     while (p != null) {
       int cmp = k. compareTo(p.key) ; // error
       if (cmp == 0)
         return p;
       else if (cmp < 0)
         p = p.left;
       else 
         p = p.right; 
     }
     return null;
  }
  public boolean containsKey(Key key) {
     return getEntry(key) != null;
  }
  ...
}
The implementation of class TreeMap invokes the method compareTo on the unknown Key type.  Since compareTo is not defined for arbitrary types the compiler refuses to invoke the compareTo method on the unknown type Key because it does not know whether the key type has a compareTo method. 

In order to allow the invocation of the compareTo method we must tell the compiler that the unknown Key type has a compareTo method.  We can do so by saying that the Key type implements the Comparable<Key> interface.  We can say so by declaring the type parameter Key as a bounded parameter. 

Example (of the same generic type, this time with bounds): 

public interface Comparable<T> {
  public int compareTo(T arg);
}
public class TreeMap<Key extends Comparable<Key> ,Data>{
  private static class Entry<K,V> {
     K key;
     V value;
     Entry<K,V> left = null;
     Entry<K,V> right = null;
     Entry<K,V> parent;
  }
  private transient Entry<Key,Data> root = null;
  ...
  private Entry<Key,Data> getEntry(Key key) {
     Entry<Key,Data> p = root;
     Key k = key;
     while (p != null) {
       int cmp = k. compareTo(p.key)
       if (cmp == 0)
         return p;
       else if (cmp < 0)
         p = p.left;
       else 
         p = p.right; 
     }
     return null;
  }
  public boolean containsKey(Key key) {
     return getEntry(key) != null;
  }
  ...
}
In the example above, the type parameter Key has the bound Comparable<Key> .  Specification of a bound has two effects: 
  • It gives access to the methods that the bound specifies .  In the example, the bound Comparable<Key> gives access to the compareTo method that we want to invoke in the implementation of our TreeMap class.
  • Only types "within bounds" can be used for instantiation of the generic type.   In the example, a parameterized type such as TreeMap<Number,String> would be rejected, because the type Number is not a subtype of Comparable<Number> .  A parameterized type like TreeMap<String,String> would be accepted, because the type String is within bounds, i.e. is a subtype of Comparable<String> .


Note that the suggested bound Comparable<Key> in this example is not the best conceivable solution.  A better bound, that is more relaxed and allows a larger set of type arguments, would be Comparable<? super Key> .  A more detailed discussion can be found in a separate FAQ entry (click here ).

LINK TO THIS TypeParameters.FAQ002
REFERENCES When would I use a wildcard parameterized with a lower bound?
What is a type parameter bound?
Which types are permitted as type parameter  bounds?
Can I use different instantiations of a same generic type as bounds of a type parameteer?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值