一.泛型的注意事项
1.1泛型的概念
用一对尖括号表示<>:全称泛化类型
1.2泛型的作用
安全省心
1.3自定义泛型类
(1) ‘<>’ 尖括号中尽量写单个字母,尽可能见名知意
例如:T代表 Type
K V 分别代表Key和Value
E 代表Element
(2) 使用时不能为基本类型,只能是引用类型
(3) 只能用在非静态成员变量上,不能使用在静态变量上
示例代码: |
package Day1; /** * 自定义泛型类 * 1.<> --> 尖括号中尽量写单个字母,尽可能见名知意 * 例如:T Type * K V Key Value * E Element * 2.使用时不能为基本类型 * 3.泛型不能使用在静态属性上 * @author asus * */ public class MyStudent<T> { //注意点:泛型不能使用在静态属性上 private Tscore; public MyStudent(){
} /* * 注意:静态方法可以用引用类型参数, * 但是必须是自声明,不能由这个类来声明 * 相当于是声明了一个泛型方法 * */ public static <T1> T1/*void*/ m(T1t){ return null;
} public MyStudent(T score){ this.score = score;
} public T getScore() { return score; } public void setScore(T score) { this.score = score; }
}
|
|
(4) 对于静态方法,静态初始化块及静态变量的声明和初始化不能使用泛型的原因:
1.因为泛型是要在对象创建的时候才知道是什么类型的,而对象创建的代码执行先后顺序是static的部分,然后才是构造函数等等。所以在对象初始化之前static的部分已经执行了,如果你在静态部分引用的泛型,那么毫无疑问虚拟机根本不知道是什么东西,因为这个时候类还没有初始化。因此在静态方法、数据域或初始化语句中,为了类而引用泛型类型参数是非法的
2.这个原理是这样的,静态方法中所能引用的属性必须是静态的,而引用参数是无法声明为静态的,因为静态的属性必须在声明时赴值或者实例化,泛型引用变量在声明的时候根本不知道是什么类型,自然不可能实例化,当然也不能放进静态方法了。
1.4自定义泛型接口
1. 接口中泛型类型只能使用在公共抽象方法上(包括设置方法的返回类型或者方法的形参类型),不能使用在全局常量中
实例代码: |
package Day1; /** * 定义泛型接口 * 注意:接口中泛型字母只能使用在公共抽象方法上,不能使用在全局常量中 * @author asus * */
//接口中的方法默认都是public abstract和常量默认都是public static final public interface Comparator<T> { //全局变量 public static final int MAX_VALUE = 1024; //公共的抽象方法 T compare(T t); }
|
1.5自定义泛型方法
1. 泛型方法可以在泛型类中,也可以在非泛型类中
2. 非泛型类中定义泛型方法
其中该方法可以是静态方法,也可以是非静态方法
3. 泛型方法的定义:
在返回值前面加上<字母>
4. 通过在泛型上加extends和 super关键字来设置泛型的上下限(后面详细介绍)
示例代码: |
package Day1;
import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.List;
/** * 泛型方法可以在非泛型类中也可以在泛型类型中 * 非泛型类中定义泛型方法 * 其中方法可以是静态方法也可以是成员方法 * 泛型方法定义: * 在返回类型前面加上<字母> * @author asus * */ public class Method {
public static <T>void test(T t){ System.out.println(t); } public static <Textends List>void test(T t){ System.out.println(t); t.add("aa"); System.out.println(t); }
public static <Textends Closeable>void test(T...a){ for(T temp:a){ try{ if(temp !=null){ temp.close(); } }catch(IOException e){ e.printStackTrace(); } } } public static void main(String[] args)throws Exception { test("bjsxt is very good"); test(new FileInputStream("a.txt")); }
}
|
1.6泛型父类的继承问题
1. 泛型父类的两种子类实现,子类为富二代
1. 保留父类泛型--->子类为泛型
1).全部保留
2).部分保留
2. 不保留父类泛型--->子类按需实现
1).具体类型
2).没有类型(类似于Object,泛型的擦除)
注意:子类也可以添加自己需要的泛型。
3. 子类重写方法的类型--->随父类而定
4. 子类新增方法的类型--->随子类而定
5. 子类中使用父类的属性--->随父类而定
6. 子类使用自己的属性--->随子类而定
总之:属性及方法--->随位置而定
示例代码: |
package day2; /** * 泛型父类 * 1.保留父类泛型---->子类为泛型子类 * 2.不保留父类泛型--->子类按需实现 * @author asus * 属性及方法类型--->随位置而定 * 1.子类重写方法的类型--->随父类而定 * 子类新增方法的类型--->随子类而定 * 2.子类中使用父类的属性--->随父类而定 * 子类中使用自己的属性---->随子类而定 */ public abstract class Father<T1,T2> { T1 age; public abstract void test(T2 name); }
//保留 -->泛型子类 //1)全部保留 class C1<T1,T2,A,B>extends Father<T1,T2>{
@Override public void test(T2 name) { //this.age --->T1 }
} //2)部分保留 class C2<T2,A,B>extends Father<Integer,T2>{
@Override public void test(T2 name) { //this.age---->Integer }
} //不保留 -->按需实现 //1)具体类型 class C3<A,B>extends Father<Integer,String>{
@Override public void test(String name) { //this.age--->Integer }
} //2)没有类型 擦除 类似于Object class C4<A,B>extends Father{
@Override public void test(Object name) { //this.age---->Object }
} |
1.7泛型接口
泛型接口的用法同泛型父类的用法一样,此处可以参考泛型父类笔记,下面仅提供示例代码
示例代码: |
package day2; /** * 泛型接口与泛型类同理 * @author asus * */ public interface Comparator<T> { //接口只包含公共的抽象的方法和全局常量 public static final int MAX_VALUE=100;
public abstract void test(T t); }
//实现 /** * 泛型擦除: * 定义 :泛型擦除是指在继承、实现、或者使用时没有指定具体的类型 * 特点 : 一旦擦除之后按Object处理 * --依然存在警告,加上Object可以去除,但是有些画蛇添足 * --不完全等同于Object,编译不会类型检查 */ class InterC1<String,T>implements Comparator<T>{
@Override public void test(Object t) {
} } class InterC2<A>implements Comparator<Integer>{
@Override public void test(Integer t) {
} } class InterC3<T,A>implements Comparator<T>{
@Override public void test(T t) {
} }
|
1.8泛型的擦除
泛型擦除:
定义 :泛型擦除是指在继承、实现、或者使用时没有指定具体的类型
特点 :一旦擦除之后按Object处理
--依然存在警告,加上Object可以去除,但是有些画蛇添足
--不完全等同于Object,编译不会类型检查
注意:泛型的擦除是在编译时期
示例代码: |
package day2; /** * 泛型的擦除:使用时或者实现或者继承 没有指定类型 * 类似于Object,不等同于Object * @author asus * */ public class MyStuApp {
public static void main(String[] args) { //此处使用了 擦除-->即 没有指定 泛型的具体类型 MyStudent student = new MyStudent(); student.setScore(100);//100-->int--->Integer---->Object
MyStudent<Object> student2 = new MyStudent<Object>();
test(student);
//不等于Object //test(student2);
}
public static void test(MyStudent<Integer> stu){
}
}
|
1.9泛型的通配符 (?)
1. ? --> 表示类型不确定,用于声明变量或者形参上
2. 不能用在:创建对象上,创建泛型类上,泛型方法,泛型接口上
示例代码: |
package day3;
import java.util.ArrayList; import java.util.List;
/* * ? -->表示类型不确定,用于声明变量或者形参上 * 不能用在: * 1.创建对象上 * 2.创建泛型类,泛型方法,泛型接口上 */ public class WildCardsTest {
public static void main(String[] args) { // 声明 List<?> list = new ArrayList<Integer>(); list = new ArrayList<String>(); list = new ArrayList<Object>(); test(list);
// 编译错误,不能用在创建对象上 // list = new ArrayList<?>();
}
// 编译错误,不能用在创建泛型类上 // class Test<?>{}
// 编译错误,不能用在泛型方法上 //public static <?> void test2(){}
public static void test(List<?> list) {
}
}
|
2.0 泛型的上限
使用extends : 泛型的上限 <= 即:子类或者自身
1. 一般用于限制操作
2.不能使用在添加数据上面,一般都是读取操作
extends还可以和通配符一起使用
3.规则
List<Fruit> ---> List<? extends Fruit>
List<Apple> ---> List<? extends Fruit>
List<? extends Apple> ---> List<? extends Fruit>
不能存放的是:List<?>,因为他等同于List<? extends Object>
示例代码: |
package day3;
import java.util.ArrayList; import java.util.List;
/* * extends : 泛型的上限 <= 即:子类或者自身 * 1.一般用于限制操作 * 2.不能使用在添加数据上面,一般都是读取操作 * extends 还可以和通配符一起使用 * 3.规则 * List<Fruit> ---> List<? extends Fruit> * List<Apple> ---> List<? extends Fruit> * List<? extends Apple> ---> List<? extends Fruit> * 不能存放的是:List<?>,因为他等同于List<? extends Object> * * * * */ public class ExtenndsTest {
public static void main(String[] args) { //extends 为上限 Test<Fruit> t1 = new Test<Fruit>(); Test<Apple> t2 = new Test<Apple>(); Test<Pear> t3 = new Test<Pear>();
//调用方法 List<? extends Fruit> list1 =new ArrayList<Fruit>(); test(list1); List<Fruit> list2 = new ArrayList<Fruit>(); test(list2); List<Apple> list3 = new ArrayList<Apple>(); test(list3);
//? extends Apple List<? extends Apple> list4 =new ArrayList<Apple>(); test(list4);
//? ---> 为什么错误,因为?可以接收所有类型,等同于? extends Object /*List<?> list5 = new ArrayList<Apple>(); test(list5);*/ }
public static void test(List<?extends Fruit> list){
}
/*定义一个内部类*/ static class Test<Textends Fruit>{
}
}
|
2.1泛型的下限
使用supper:泛型的下限 >=即:父类或者自身
2. 一般用于下限制操作
2.能够添加数据在上面,但不能添加父类对象
Supper还可以和通配符一起使用
3.规则
List<Fruit> ---> List<?super Fruit>
List<Apple> ---> List<?super Apple>
List<? super Fruit> ---> List<?super Apple>
不能存放的是:List<? super FujiApple> ---> List<? super Apple>,因为,FujiApple是Apple的子类。
2.2泛型的嵌套
1. 总之一句话,由外到内一层一层的展开。
2.3泛型没有多态和数组
参考下面的示例代码
示例代码: |
package day3;
import java.util.ArrayList; import java.util.List;
/* * 1.泛型没有多态 * 2.泛型没有数组 * * */ public class Polymorphism { public static void main(String[] args) {
//多态 Fruit f =new Apple();//ok //泛型没有多态 //List<Fruit> list = new ArrayList<Apple>();//编译出错 List<? extends Fruit>list =new ArrayList<Apple>();//这样是OK的
//泛型没有数组 //Fruit<String>[] arr = new Fruit<String>[];//编译出错 } }
|
2.4 JDK1.7关于泛型的简化
1. Fruit<String> list = new ArrayList<>();这样定义在JDK1.7中是可以的,但是在JDK1.6中必须把后面的也补全,像这样:Fruit<String> list = new ArrayList<String>();