Java内部类与外围类泛型参数
在Java的编程中,经常使用常规内部类和静态内部类(即嵌套类),当外围类和内部类都是用泛型参数时,会存在一些需要注意的问题。
问题的起源
LinkedList
的Java实现:
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyLinkedList<T> implements Iterable<T> {
// 静态内部类,定义节点结构
private static class Node<T> {
private T data;
private Node<T> prev;
private Node<T> next;
public Node(T data,Node<T> prev,Node<T> next) {
this.data=data;
this.prev=prev;
this.next=next;
}
}
private int size;
private int modCount=0;
private Node<T> begin;
private Node<T> end;
/*一些方法实现
*clear()
*size()
*isEmpty()
*add(T x)
*add(int index, T x)
*get(int index)
*remove(int index)
*/
public MyLinkedList() {
// TODO Auto-generated constructor stub
// clear();
}
@Override
public Iterator<T> iterator() {
// TODO Auto-generated method stub
return new LinkedListIterator();
}
// 非静态内部迭代类
private class LinkedListIterator implements Iterator<T> {
private Node<T> current=begin.next;
private int expectedModCount=modCount;
private boolean okToRemove=false;
/*一些方法实现
*hasNext()
*next()
*remove()
*/
}
}
泛型类实现泛型接口
- 泛型类声明的泛型参数占主导地位,如泛型类声明的参数为
<T>
,则泛型接口的泛型参数也应为<T>
; - 当泛型类声明的参数为
<T>
时,泛型接口的参数<T>
可以不写; - 当泛型接口的参数为
<T>
时,潜在表明泛型类的参数为<T>
,必须在泛型类中声明<T>
。
// 规范写法
public class MyClass1<T> implements Iterator<T> {
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
@Override
public T next() {
// TODO Auto-generated method stub
return null;
}
}
// 不规范写法
public class MyClass1<T> implements Iterator {
/* implementaion */
}
// 错误写法: T cannot be resolved to a type
public class MyClass1 implements Iterator<T> {
/* implementaion */
}
非静态内部类会自动继承外围类泛型参数
在LinkedList
实现中:存在一个静态内部类private static class Node<T>
,一个非静态内部类LinkedListIterator
,并且该非静态内部类实现了Iterator<T>
。
按照规范写法,LinkedListIterator
的形式应当是在LinkedListIterator
中声明泛型参数<T>
,如下所示。
private class LinkedListIterator<T> implements Iterator<T> {
private Node<T> current=begin.next;
private int expectedModCount=modCount;
private boolean okToRemove=false;
/* implementaion */
}
但这样private Node<T> current=begin.next;
就会报错,类型不匹配,
Type mismatch: cannot convert from MyLinkedList.Node to MyLinkedList.Node
经过Google一番得知,对于非静态内部类,会自动继承外围类的泛型参数,即LinkedListIterator
已经有默认的泛型参数<T>
,而这里又重新声明一个新的泛型参数<T>
,两者并不相同。
结论:对于非静态内部类,无需再次声明泛型参数
静态内部类不会自动继承外围类泛型参数
事实上,Node<T>
中的泛型参数<T>
与MyLinkedList<T>
中的<T>
没有任何联系,只是这里使用相同的符号T
而已。
一些测试
对内部类和外围类的泛型参数之间的关系进行一些测试
import java.util.Iterator;
public class GenericType<T> {
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericType<Integer> a=new GenericType<>(new Integer(5));
MyClass<Integer> b=new MyClass<>(a.getX());
MyClass2<Integer> c=new MyClass2<>();
}
private T x;
public GenericType(T x) {
// TODO Auto-generated constructor stub
this.x=x;
}
public GenericType() {
// TODO Auto-generated constructor stub
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
// 非静态内部类会自动继承外部类的泛型
// 这里又重新声明了一个新的泛型<T>
// Inner1<T>中声明的<T>与Demo11<T>中的<T>不同
// 导致T y=x;报错:Type mismatch: cannot convert from T to T
private class Inner1<T> {
// T y=x;
}
private class Inner5<K> {
// K y=x; // Type mismatch: cannot convert from T to K
}
// 需去掉<T>
private class Inner2 {
T y=x;
}
// 需去掉<T>,接口应写为<T>
private class Inner6 implements MyInterface<T> {
T y=x;
}
// 接口写为其他,如<E>均报错
// private class Inner7 implements MyInterface<E> {
// E y; // E cannot be resolved to a type
// }
// 静态内部类不会自动继承外部类的泛型,相当于独立于外部类
// 可以自己声明泛型
private static class Inner3<T> {
T z=new GenericType<T>().x;
}
// 可以自己声明泛型,并且不需要和外部类的泛型声明相同
private static class Inner4<V> {
V v=new GenericType<V>().x;
}
}
interface MyInterface<E> {
}
class MyClass<R> {
private R r;
public MyClass(R r) {
// TODO Auto-generated constructor stub
this.r=r;
}
}
class MyClass1<T> implements Iterator<T> {
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
@Override
public T next() {
// TODO Auto-generated method stub
return null;
}
/* implementation */
}
class MyClass2<V> implements Iterator {
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
@Override
public Object next() {
// TODO Auto-generated method stub
return null;
}
}
刚学编程不久,欢迎大家探讨交流!