<--------------Generic-------------->
同cpp中的模版
<< 描述泛型优点
<< 使用泛型类和接口
<< 定义泛型类和接口
<< 解释为什么泛型类型可以提高可靠性和可读性
<< 定义并使用泛型方法和受限泛型类型
<< 使用原始类型向后兼容
<< 解释为什么有必要有通配的泛型类型
<< 描述泛型消除并列出一些由类型消除引起的泛型类型上的限制和局限性
泛型指参数化类型的能力。
可以定义带泛型类型的类或方法,随后编译器会用具体的类型来替换它。
例如,它可以定义一个泛型栈类,它存储的是泛型元素。可以从这个泛型类生成一个包含字符串的栈对象
和一个包含数字的栈对象。
泛型类或方法允许用户指定可以和这些类或方法一起工作的对象类型,若试图使用一个不相容的对象,编
译器则会检测出这个错误。
package java.lang;
public interface Comparable<T>{
public int compareTo(T o);
}
<T>表示形式泛型类型,随后可用一个实际具体类型来替换它。
替换泛型类型称为泛型实例化。
<JDK1.5之前>
Comparable c = new Date();
System.out.println(c.comparTo("red"));
将c声明为一个引用变量,它的类型为Comparable,然后调用compareTo方法来比较Date对象和一个字符串。
这样代码可以编译,可是会产生一个运行时错误,因为Date对象不能和字符串比较。
<JDK1.5>
Comparable<Date> c = new Date();
System.out.println(c.comparTo("red"));
将c声明为一个引用变量,它的类型为Comparable<Date>,然后调用comparTo方法来比较Date对象和一个
字符串。因为传递给compareTo方法的参数必须是Date类型的。由于这个错误可以在编译时而不是运行时
被检测到,因而泛型使程序更可靠。
public class Generic {
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericStack<String> gs = new GenericStack<String>();
gs.push("dddd");
System.out.println(gs.pop());
String[] list = {"London","Paris","New York"};
Generic.<String>print(list);
}
//泛型方法
public static <E> void print(E[] list){
for(int i=0;i<list.length;i++)
System.out.println(list[i]+" ");
System.out.println();
}
}
//泛型类
public class GenericStack<E> {
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
public int getSize(){
return list.size();
}
public void push(E o){list.add(o);}
public E pop(){
E o = list.get(getSize()-1);
list.remove(getSize()-1);
return o;
}
public boolean isEmpty(){
return list.isEmpty();
}
}
可以将泛型指定为另一种类型的子类型。这样的泛型类型称为受限的。
public static <E extends GeometricObject> boolean equalArea(
E object1,E object2){
return object1.getArea() == object2.getArea();
}
<--------------原始类型和向后兼容-------------->
可以使用泛型而不需指定具体类型:
GenericStack stack = new GenericStack();---------------------1
等价与:
GenericStack<Object> stack = new GenericStack<Object>();-----2
不需要使用类型参数的泛型类称为“原始类型”。(如1)
原始类型不安全,会引起运行时错误。
<-------“通配类型”--------->
通配符类型有三种形式:
?为非受限通配,和? extends Object是一样的。
? extends T 为受限通配,表示T或T的一个未知子类型。
? super T 为下限通配,表示T或T的一个未知父类型。
(T为某个泛型类型)
public class WildCardDemo1{
public static void main(String[] args){
GenericStack<Integer> instack = new GenericStack<Integer>();
instack.push(1);
instack.push(2);
instack.push(-2);
System.out.println("the max num is "+max(instack));
}
}
public static double max(GenericStack<? extends Number> stack){
while(!stack.empty()){
System.out.println(stack.pop() + " ");
}
}
什么时候需要 <? super T> 通配符?
public class WildCarDemo3{
public static void main(String[] args){
GenericStack<String> stack1 = new GenericStack<String>();
GenericStack<Object> stack2 = new GenericStack<Obeject>();
stack2.push("Java");
stack2.push(2);
stack1.push("Sun");
add(stack1,stack2);
}
public static <T> void add(GenericStack<T> stack1,
GenericStack<? super T> stack2){
while(!stack1.isEmpty())
stack2.push(stack1.pop());
}
}
<------消除泛型和对泛型的限制------>
泛型是使用一种类型消除的方法实现的。
编译器使用泛型类型信息来编译代码,但是随后会消除它。
泛型信息在运行时不可用。这种方法可以使泛型代码向后兼容用原始类型的遗留代码。
泛型存在与编译时。一旦编译器确认泛型类型是安全使用的,就会将它转换成原始类型。
当编译泛型类,接口和方法时,编译器用Object类代替泛型类型。
注:泛型类是被它的实例共享的。尽管编译时候出现ArrayList<String>和ArrayList<Integer>两种类型
但是,在运行时只有一个ArrayList类被加载进JVM中。
限制:
1.不能用new E();
运行时,泛型类型不可用。
2.不能使用new E[];
不能使用泛型类型参数创建数组。
可以通过创建一个Object类型的数组,然后将它的类型转换为E[]来规避这个限制:
E[] elements = (E())new Object[capacity];
可是遇到new Object是Integer类,而E是String,则会导致ClassCastException异常,这个无法避免。
不允许使用泛型类创建泛型数组。
ArrayList<String>[] list = new ArrayList[10];
可以规避:ArrayList<String>[] list = (ArrayList<String>[])new ArrayList[10];
ArrayList<?>[] a = new ArrayList<?>[10]; 成立
3.在静态环境下,不允许类的参数是泛型类型;
在静态方法,数据域或初始化语句中,为了类而引用泛型类型参数是非法的。
public class Test<E>{
public static void m(E o1){ // Illegal
}
public static E o1; // Illegal
static{
E o2; // Illegal
}
}
4.异常类不能是泛型的。
同cpp中的模版
<< 描述泛型优点
<< 使用泛型类和接口
<< 定义泛型类和接口
<< 解释为什么泛型类型可以提高可靠性和可读性
<< 定义并使用泛型方法和受限泛型类型
<< 使用原始类型向后兼容
<< 解释为什么有必要有通配的泛型类型
<< 描述泛型消除并列出一些由类型消除引起的泛型类型上的限制和局限性
泛型指参数化类型的能力。
可以定义带泛型类型的类或方法,随后编译器会用具体的类型来替换它。
例如,它可以定义一个泛型栈类,它存储的是泛型元素。可以从这个泛型类生成一个包含字符串的栈对象
和一个包含数字的栈对象。
泛型类或方法允许用户指定可以和这些类或方法一起工作的对象类型,若试图使用一个不相容的对象,编
译器则会检测出这个错误。
package java.lang;
public interface Comparable<T>{
public int compareTo(T o);
}
<T>表示形式泛型类型,随后可用一个实际具体类型来替换它。
替换泛型类型称为泛型实例化。
<JDK1.5之前>
Comparable c = new Date();
System.out.println(c.comparTo("red"));
将c声明为一个引用变量,它的类型为Comparable,然后调用compareTo方法来比较Date对象和一个字符串。
这样代码可以编译,可是会产生一个运行时错误,因为Date对象不能和字符串比较。
<JDK1.5>
Comparable<Date> c = new Date();
System.out.println(c.comparTo("red"));
将c声明为一个引用变量,它的类型为Comparable<Date>,然后调用comparTo方法来比较Date对象和一个
字符串。因为传递给compareTo方法的参数必须是Date类型的。由于这个错误可以在编译时而不是运行时
被检测到,因而泛型使程序更可靠。
public class Generic {
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericStack<String> gs = new GenericStack<String>();
gs.push("dddd");
System.out.println(gs.pop());
String[] list = {"London","Paris","New York"};
Generic.<String>print(list);
}
//泛型方法
public static <E> void print(E[] list){
for(int i=0;i<list.length;i++)
System.out.println(list[i]+" ");
System.out.println();
}
}
//泛型类
public class GenericStack<E> {
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
public int getSize(){
return list.size();
}
public void push(E o){list.add(o);}
public E pop(){
E o = list.get(getSize()-1);
list.remove(getSize()-1);
return o;
}
public boolean isEmpty(){
return list.isEmpty();
}
}
可以将泛型指定为另一种类型的子类型。这样的泛型类型称为受限的。
public static <E extends GeometricObject> boolean equalArea(
E object1,E object2){
return object1.getArea() == object2.getArea();
}
<--------------原始类型和向后兼容-------------->
可以使用泛型而不需指定具体类型:
GenericStack stack = new GenericStack();---------------------1
等价与:
GenericStack<Object> stack = new GenericStack<Object>();-----2
不需要使用类型参数的泛型类称为“原始类型”。(如1)
原始类型不安全,会引起运行时错误。
<-------“通配类型”--------->
通配符类型有三种形式:
?为非受限通配,和? extends Object是一样的。
? extends T 为受限通配,表示T或T的一个未知子类型。
? super T 为下限通配,表示T或T的一个未知父类型。
(T为某个泛型类型)
public class WildCardDemo1{
public static void main(String[] args){
GenericStack<Integer> instack = new GenericStack<Integer>();
instack.push(1);
instack.push(2);
instack.push(-2);
System.out.println("the max num is "+max(instack));
}
}
public static double max(GenericStack<? extends Number> stack){
while(!stack.empty()){
System.out.println(stack.pop() + " ");
}
}
什么时候需要 <? super T> 通配符?
public class WildCarDemo3{
public static void main(String[] args){
GenericStack<String> stack1 = new GenericStack<String>();
GenericStack<Object> stack2 = new GenericStack<Obeject>();
stack2.push("Java");
stack2.push(2);
stack1.push("Sun");
add(stack1,stack2);
}
public static <T> void add(GenericStack<T> stack1,
GenericStack<? super T> stack2){
while(!stack1.isEmpty())
stack2.push(stack1.pop());
}
}
<------消除泛型和对泛型的限制------>
泛型是使用一种类型消除的方法实现的。
编译器使用泛型类型信息来编译代码,但是随后会消除它。
泛型信息在运行时不可用。这种方法可以使泛型代码向后兼容用原始类型的遗留代码。
泛型存在与编译时。一旦编译器确认泛型类型是安全使用的,就会将它转换成原始类型。
当编译泛型类,接口和方法时,编译器用Object类代替泛型类型。
注:泛型类是被它的实例共享的。尽管编译时候出现ArrayList<String>和ArrayList<Integer>两种类型
但是,在运行时只有一个ArrayList类被加载进JVM中。
限制:
1.不能用new E();
运行时,泛型类型不可用。
2.不能使用new E[];
不能使用泛型类型参数创建数组。
可以通过创建一个Object类型的数组,然后将它的类型转换为E[]来规避这个限制:
E[] elements = (E())new Object[capacity];
可是遇到new Object是Integer类,而E是String,则会导致ClassCastException异常,这个无法避免。
不允许使用泛型类创建泛型数组。
ArrayList<String>[] list = new ArrayList[10];
可以规避:ArrayList<String>[] list = (ArrayList<String>[])new ArrayList[10];
ArrayList<?>[] a = new ArrayList<?>[10]; 成立
3.在静态环境下,不允许类的参数是泛型类型;
在静态方法,数据域或初始化语句中,为了类而引用泛型类型参数是非法的。
public class Test<E>{
public static void m(E o1){ // Illegal
}
public static E o1; // Illegal
static{
E o2; // Illegal
}
}
4.异常类不能是泛型的。