为什么要使用泛型
JDK1.4以前类型不明确,只能用Object替代,从而失去了自己的类型,取出来之后往往需要转型,效率低下。
//例如学生的成绩有多种可能,字符串,整型,浮点型等,此时就应该使用Object,它可以接受任何类型。
public class Student {
//成绩
private Object javase;
public Student() {
}
public Student(Object javase) {
this.javase =javase;
}
public Object getJavase() {
return javase;
}
public void setJavase(Object javase) {
this.javase = javase;
}
}
Object是所有类的根类,这种任意化在具体类使用的时候:需要类型检查;需要类型强制转换的;需要处理转换错误异常,非常麻烦!!!
public class StuApp {
public static void main(String[] args) {
//存入整数 int -->Integer -->Object
Student stu = new Student(80);
Object javase =stu.getJavase();
//类型检查 处理转换异常
if(javase instanceof Integer){
//强制类型转换
Integer javaseScore =(Integer) javase ;
}
stu =new Student("优秀");
javase =stu.getJavase();
//类型检查 处理转换异常
if(javase instanceof String){
//强制类型转换
String javaseScore =(String) javase ;
}
}
}
解决方案:使用泛型,在定义集合的时候同时定义集合中对象的类型。使用泛型时,在实际使用之前类型就已经确定了,不需要强制转换。
泛型的定义
泛型就是参数化类型,如:可拆卸刀头的螺丝刀检查需要拧动的螺丝,根据螺丝选择适合刀头(一字、十字、星形),将正确的刀头插入到螺丝刀柄上后,您就可以使用螺丝刀执行完全相同的功能,即拧螺丝;泛型主要适用在集合中。
泛型的作用
模板:提高代码的重用率;
安全:在编译的时候检查类型安全;
省心:所有的强制转换都是自动和隐式的。
泛型的模板定义
class 类名<字母>{
private 字母 属性名;
setter与getter访问器
}
使用泛型的注意事项
public class MyStudent<T> { //T-->Type类型
private T javase;
//泛型不能使用在静态属性上
//private static T test;
public MyStudent() {
}
public MyStudent(T javase) {
this.javase = javase;
}
public T getJavase() {
return javase;
}
public void setJavase(T javase) {
this.javase = javase;
}
}
1.静态数据不可以使用泛型(因为静态变量为所有实例共享,如果可以使用,那么当使用不同的类型参数实例化对象时会导致编译器插入强制类型转换代码错误(1.5版泛型指南上有实例解释)。)
public class MyStuApp {
public static void main(String[] args) {
//MyStudent<int> stu =new MyStudent<int>();//不可以为基本类型
MyStudent<Integer> stu =new MyStudent<Integer>();
//1、安全:类型检查
//stu.setJavase("优秀");
stu.setJavase(80);
//2、省心:自动类型转换,免去了类型检查
Integer score=stu.getJavase();
System.out.println(score);
}
}
2.指定的类型不可以是基本类型,例如int,但是可以用Integer。
3.命名上可以随意指定,尽量使用单个的大写字母(有时候多个泛型类型时会加上数字),比如T1,T2, 尽可能见名知意。
常见的字母为:
T Type
K V Key Value
E Element
泛型接口
public interface Comparator<T> {
//全局常量
/*public static final*/ int MAX_VALUE=1024;
//公共的抽象方法
/*public abstract */T compare(T t);
}
//PS:/**/表示默认存在
//由于泛型接口中的属性为全局常量,泛型不可以用于全局常量上(一开始就需要初始化),只能使用在方法上。
泛型方法
定义声明方法时使用 <字母> ,泛型方法与所在的类是否为泛型类没有关系,如:
public class MethodDeep{
public static <T extends List> void test(T t){
System.out.println(t);
t.add("aaa");
}
//释放资源
public static <T extends Closeable> void test(T... a){//类型局限在Closeable类型下可用 ...表示可变参数 相当于一个数组
for(T temp:a){
try {
if(null!=temp){
temp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws FileNotFoundException {
test("bjsxt is very good");
test(new FileInputStream("a.txt"));
}
}
泛型的继承,实现
泛型类:
//例如:
public abstract class Father<T1,T2> {
}
//子类处理方法:
//①保留 ---> 泛型子类
//1)全部保留
//class C1<T1,T2,A,B> extends Father<T1,T2> {}
//2) 部分保留
//class C2<T2,A,B> extends Father<Integer,T2> {}
//②不保留 ---> 按需实现
//1)具体类型
//class C3 extends Father<Integer,String>{}
//2) 没有类型 (擦出)
//class C4 extends Father{}
//PS:① 字母的位置没有特别要求,子类的泛型类型要大于等于父类的
//② 子类重写方法的参数类型随父类
//子类中使用父类的属性随父类而定
//子类新增方法的类型随子类而定
//子类中使用自己定义的属性随子类而定
泛型接口与泛型类同理。
public interface Comparator<T> {
//全局常量
public static final int MAX_VALUE=100;
//公共抽象方法
public abstract void test(T t);
}
//实现
class InterC1<A> implements Comparator{
@Override
public void test(Object t) {
}
}
class InterC2<A> implements Comparator<Integer>{
@Override
public void test(Integer t) {
// TODO Auto-generated method stub
}
}
class InterC3<T,A> implements Comparator<T>{
@Override
public void test(T t) {
}
}
泛型擦除
使用/实现/继承时没有指定类型,类似于Object不等同于Object
public class MyStudent<T> {
private T javase;
//private static T test; //泛型不能使用在静态属性上
public MyStudent() {
}
public MyStudent(T javase) {
this.javase = javase;
}
public T getJavase() {
return javase;
}
public void setJavase(T javase) {
this.javase = javase;
}
}
public class MyStuApp {
public static void main(String[] args) {
//擦除 -->没有指定 泛型的具体类型
MyStudent student =new MyStudent();
student.setJavase(100); //100 -->int -->Integer -->Object
Object obj=student.getJavase();
test(student);//编译不会类型检查
MyStudent<Object> student2 =new MyStudent<Object>();
//不等于 Object
//test(student2);//Object编译检查
}
public static void test(MyStudent<Integer> stu){
}
}
泛型的通配符
① ?–> 通配符,类型不确定,用于声明变量/形参上
//例子:
//声明:
List<?> list = new ArrayList<Integer>();
list = new ArrayList<String>();
//形参
public static void test(List<?> list){}
②?通配符不可以使用在创建对象,创建泛型类,泛型方法,泛型接口上。
//不能用在泛型方法上
public static
泛型的上限 extends
①extends:表示泛型的上限
1.一般用于限制操作。
2.不可用于添加数据上,一般都是读取操作
例子:
Object
|
Fruit
/ \
Apple Pear
|
FujiApple
public class Fruit {
}
class Apple extends Fruit{
}
class Pear extends Fruit{
}
class FujiApple extends Apple{
}
public class ExtendsTest {
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<FujiApple>();
test(list4);
//? -->为什么错误 ,因为 ? 等同于 ? extends Object
List<?> list5=new ArrayList<Object>();
List<? extends Object> list6=new ArrayList<Object>();
//test(list6);
List<FujiApple> app =new ArrayList<FujiApple>();
test(app);
}
//? extends Fruit
public static void test(List<? extends Fruit> list){
/*
//不能用于添加数据 因为类型可能是Apple、Pear等你无法确定,所以java为了保护其类型一致,禁止向List<? extends Fruit>添加任意对象,不过却可以添加null,即list.add(null)是可行的。
//为了保证向下兼容的一致性
//假设 List<FujiApple> app =new ArrayList<FujiApple>();
//如果往List中添加一个Apple肯定是不行的。
list.add(new Apple());
list.add(new FujiApple());
list.add(new Pear());
list.add(new Fruit());
*/
list.add(null);
}
//泛型类
static class Test<T extends Fruit>{
}
}
泛型的下界super
public class SuperTest {
public static void main(String[] args) {
// >= 即父类或自身
List<Apple> list1 =new ArrayList<Apple>();
test(list1);
List<Fruit> list2 =new ArrayList<Fruit>();
test(list2);
List<Object> list3 =new ArrayList<Object>();
test(list3);
//规则
List<? super Apple> list4 =new ArrayList<Apple>();
test(list4);
List<? super Fruit> list5 =new ArrayList<Object>();
test(list5);
List<? super FujiApple> list6 =new ArrayList<Object>();
//test(list6);
List<?> list7 =new ArrayList<Object>();
//test(list7);
}
public static void test(List<? super Apple> list){
//不能添加 父类对象 因为你不知道你添加进去的是什么 可能是Fruit可能是Object,要保证其类型的一致性,可以添加其子类,因为子类可以向父类转型 这样子添加进去的都是Apple类型的
//简单的举个例子:看上面list4 =new ArrayList<Apple>();
//这样子要是在里面add一个Fruit对象的话是不可行的。
list.add(new Apple());
list.add(new FujiApple());
//list.add(new Fruit());
}
}
泛型的嵌套
由外到内进行拆分
public class Student<T> {
private T score;
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
}
public class Bjsxt<T> {
private T stu;
public T getStu() {
return stu;
}
public void setStu(T stu) {
this.stu = stu;
}
}
public class StudentApp {
public static void main(String[] args) {
Student<String> stu =new Student<String>();
stu.setScore("优秀");
System.out.println(stu.getScore());
//泛型嵌套
Bjsxt<Student<String>> bjsxt =new Bjsxt<Student<String>>();
bjsxt.setStu(stu);
stu=bjsxt.getStu();
String score =stu.getScore();
System.out.println(score);
//HashMap -->使用泛型嵌套
Map<String,String> map =new HashMap<String,String>();
map.put("a", "java300");
map.put("b", "马士兵javase");
Set<Entry<String,String>> entrySet= map.entrySet();
for(Entry<String,String> entry:entrySet){
String key =entry.getKey();
String value =entry.getValue();
System.out.println(key+"-->"+value);
}
}
}
泛型没有多态,没有数组
public class Others {
public static void main(String[] args) {
//多态
Fruit f =new Apple();
// 泛型没有多态
//List<Fruit> list =new ArrayList<Apple>();//×
List<? extends Fruit> list =new ArrayList<Apple>();//正确
//泛型没有数组
//Fruit<String>[] arr =new Fruit<String>[10];
//jdk1.7泛型简化
List<Fruit> list2 =new ArrayList<>();
}
}