JAVA范型-基础

JAVA范型-基础

一、泛型的概念

1、实现了参数化类型

2、用于编写可应用于多种类型的代码,即所编写的代码可应用于许多许多的类型。

3、范型容器、范型接口、范型方法都是经典的用法。

二、泛型与多态

1、多态是一种泛化机制。在使用类型说明的地方,使用多态确实具备一定的灵活性。但,多态是受限制的:只能接受基类或其子类(拘泥于单继承体系,使程序受限太多)。而且,在实际编写代码时,只能使用已存在的基类或接口。同时,一旦指明了接口,程序就会要求你的代码必须使用特定接口(方法)。

2、泛型:使我们能够编写比多态更具灵活性、更加通用的代码,它使代码能够适用于“某种不具体类型”,而不是一个具体接口或类。

3、使用泛型机制编写的代码要比那些杂乱地使用Object变量,然后进行强制类型转换具有更好的安全性和可读性。

4、泛型另一个优点:能够在编译时检测错误,而不是在运行时。例如:

JDK1.5前 : public interface Comparable{public int comparaTo(Object 0)}

//编译通过、运行错误

Comparalbe c = new Date();   //Date实现了Comparalbe

c.compareTo(“red”);

JDK1.5:public interface Comparable<T>{public int comparaTo(T 0)}

//编译错误,因为传递给compareTo()的参数必须为Date类型

Comparalbe<Date> c = new Date();   //Date实现了Comparalbe

c.compareTo(“red”);

三、泛型的限制

1、基本类型不能使用作为类型参数。例如:

Comparalbe<int>是错误的,应该是Comparalbe<Integer>。

2、不能使用泛型类型创建实例。例如:

E object = new E();

3、不能使用泛型类型创建数组。例如:

E[] elements = new E[10];

(可以创建一个Object数组,然后将它的类型转换为E[]来规避这个限制)

(E[] elements = (E[]) new Object[10];)

(有编译警告)

4、不允许使用范型类创建泛型数组。例如:

ArrayList<String>[] list = new ArrayList<String>[10];

(可以使用:ArrayList<String>[] list = (ArrayList<String>[])new ArrayList [10];)

(有编译警告)

5、在静态环境下(静态域、静态方法、静态块)不允许类的参数是泛型类型。

public class test<E>{    //类的参数是泛型

private static E o;   //静态域

public static void m(E 0){} //静态方法

static{ }  //静态块

}

6、异常类不能是泛型的。例如:

public class MyException<T> extends Exception{

}

四、泛型方法(参数化方法)

1、泛型方法可以在泛型类中,也以在非泛型类中。即,是否拥有泛型方法,与其是否是泛型类没有关系。

2、泛型方法使得该方法能够独立于类而产生变化。如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法。

3、泛型方法定义:只需要将泛型参数列表置于返回类型之前。例如:

private <T> void m(T t){}

public static <T> T m(){return t;} //T t

4、泛型方法调用:与普通方法的调用一样。

五、泛型接口和类

1、泛型接口和类的定义:用尖括号括住类型参数,放在接口(类名)后面。例如:

public class Holder<T>{}

public interface Inter<T>{}

2、读作:具有T类型参数的类。

3、泛型接口和类的经典用法:泛型容器。

六、边界(泛型参数类型限定):<T extends BoundingTypeList>

1、T:为界限列表BoundingTypeList的的子类或子接口

2、BoundingTypeList:界限列表至多只能有一个类,或多个接口,并且类必须放在界限列表的第一位。界限列表使用&连接,例如,

BoundingTypeList:class & interfaceA & interfaceB

注:其中,class称为第一边界,interfaceA为第二边界,以此类推。如果没有界限列表,Object为第一边界。

3、泛型类型限定,也称为泛型类型的边界。它使得我们可以在用于泛型的参数类型上设置限制条件,规定了泛型可以应用的类型(这些泛型类型应该满足限制条件)。另一个更重要的效果就是可以按照自己的的边界类型来调用方法,而无界泛型参数调用的方法只是那些可用Object调用的方法(在下一节详解)。

七、泛型翻译:擦除

1、擦除的神秘之处

1)ArrayList<String>和ArrayList<Integer>

//main()

Class c1 = new ArrayList<String>().getClass();

Class c2 = new ArrayList<Integer>().getClass();

System.out.println(c1 == c2);

//output

ture

显然,我们都认为ArrayList<String>和ArrayList<Integer>是不同的类型。然而,程序运行的结果显示:ArrayList<String>和ArrayList<Integer>是同一类型。这是因为:在泛型代码内部,无法获得任何有关泛型参数类型的信息(这也是泛型的使用受限的原因之一,例如,不能创建泛型数组)。

2)擦除带来的问题:在使用泛型时,任何具体类型信息都被擦除,而我们只知道在使用一个原生对象(Object)(如果没有使用边界的话),因此我们只能调用的方法只是那些可用Object调用的方法。

class HasF{ public void f(){System.out.println(“HasF”);}}

class Temp<T>{

T obj;

public Temp(T aObj){obj = aObj;}

public void meth(){obj.f();} //compile error

}

//main()

new Temp<HasF>(new HasF()).meth();

这是因为编译器无法将meth()必须能够在obj上调用f()这一需求映射到HasF拥有f()这一事实。为了解决这一问题,我们就需要到泛型边界(泛型类型参数将擦除到它的第一边界,而没有边界则擦除到原生Object)。

class Temp<T extends HasF>{    //边界HasF,可调用所有HasF暴露的方法

T obj;

public Temp(T aObj){obj = aObj;}

public void meth(){obj.f();} //

}

2、泛型类

无论何时定义一个泛型类型,相应的原始类型(raw type)都会被自动提供。原始类型的名字就是删去了类型参数的泛型类型的名字。类型参数T会被擦除(erased),并用第一边界(无限定类型的变量用Object)替换。例如:

//泛型                               //原始类型(类型参数擦除)

public class Pair<T>{                   public class Pair{

private T frist;                         private Object frist;

private T second;                       private Object second;

public T getFrist(){ retrun frist;}           public Object getFrist(){ retrun frist;}

public void setSecond(T aSecond){…..}     public void

setSecond(Object aSecond){…..}

}                                   }

3、泛型方法

1)也会进行类型擦除,泛型方法的类型参数T会被擦除(erased),并用第一边

界(无限定类型的变量用Object)替换。例如:

public <T extends Comparable> T m(){…….}  //泛型方法

public Comparable m(){…….}              //擦除后的方法

2)泛型方法擦除带来的问题:与多态冲突

//擦除前

class DateInterval extends Pair<Date>{

public void setSecond(Date aSecond){…..}

}

//擦除后

class DateInterval extends Pair{

public void setSecond(Date aSecond){…..}

}

//与此同时,DateInterval从Pair中继承方法

public void setSecond(Object aSecond){…..}

//显然,DateInterval有两个setSecond()方法,若执行下面语句

DateInterval interval = new DateInterval();

Pair<Date> pair = interval;

pair.setSecond(aDate);

// 对setSecond()的调用是多态的,pair引用了DateInterva对象,我们希望调用

// DateInterval. setSecond()。问题在于类型擦除与多态发生了冲突。解决办法:

//编译器在DateInterval中生成一个桥方法。

public void setSecond(Object aSecond){setSecond((Date)second)}

3)泛型表达式:返回类型被擦除,编译器插入强制类型转换

Pair<Employee> buddies = …..;

Employee buddy = buddies.getFrist();

//对getFrist()的调用是对原始方法getFrist()的调用,然后将返回的Object强制转//换为Employee

时间: 2024-10-15 15:24:37

JAVA范型-基础的相关文章

Java范型随笔

最近在帝都好无聊啊, 排遣寂寞就只有让自己不要停下来,不断的思考了 QWQ; 最近做ndk, java有点忘了,突然看到了一些java范型方面的问题, 踌躇了一会, 想着想着,决定还是写个随笔记录下来. 范型语法这个网上找度娘可以要到一大把, 我就不记了, 主要是范型上下限问题. 案例: public class Test { public static class Base{ } public static class A extends Base{ } public static class

由Cannot create a generic array of ArrayList&lt;xx&gt;引出的学习--Java范型

最近在用Java写某个程序时希望写出一个包括ArrayList<xx>的数组 自己定义如下: ArrayList<edge>[] edges = new ArrayList<edge>()[10]; 然后编译器报错如下: Cannot create a generic array of ArrayList<edge>; 在C++里可以这样比较方便的定义:  vector<edge> a[100]; 在Java里报错,查询了一下,见已经有人在sta

java范型集合中的成员排序

范型集合中的类是JsonObject,不是自定义类,如果是自定义类就直接取要比较的字段值. 1 ArrayList<JSONObject> TList = new ArrayList<JSONObject>(); 2 3 for(int i=0;i<10000;i++) 4 { 5 JSONObject object=new JSONObject(); 6 Random rand = new Random(); 7 int randNum = rand.nextInt(200

Java 范型中的super和extends的区别

其实一句话就是: super最好用来作为输出参数,extends最好用来作为输入参数: 看看下面的例子: private class A { // } private class B extends A { // } private class C extends B { // } public void test() { List<? super B> test = new ArrayList(); test = new ArrayList<A>(); test = new Ar

Java范型之T extends Comparable&lt;? super T&gt;

在观察Java源码的时候,发现了这么一个写法T extends Comparable<? super T>.不禁纳闷为什么要这么写呢?有什么好处吗,extends和super在这里的作用着实让人有点不清楚. 接下来,我将结合代码跟大家分享一下我关于这里泛型应用的看法. 1.<T extends Comparable<? super T>>代表什么意思 大家可以明白的是这里应用到了Java的泛型,那么首先向大家说明一下这里extends的作用 extends后面跟的类型,

java 范型的那点事

1. 泛型概念 顾名思义,类型参数化(Generics) 2.未检查的类型转换 给一个原生类型赋值一个泛型类型 Box rawBox = new Box(); // rawBox is a raw type of Box<T> Box<Integer> intBox = rawBox; // warning: unchecked conversion 使用一个原生类型引用调用一个泛型类型引用的泛型方法时 Box<String> stringBox = new Box&l

Java千百问_05面向对象(014)_如何获取范型的类Class

点击进入_更多_Java千百问 1.如何获取范型的类Class java中,无法获取范型的类型,例如: public class Box<T> { public static void main(String[] args) { System.out.printf(T);//编译错误 } } 其实,由于java是强类型语言,在编译时我们并不知道T是什么具体类型,只有在编译后,不同场景指定之后才会知道,所以在编译前是无法获取T的类型.如果想获取T的类型,可以在泛型类中声明一个对象,通过对象获取当

分布式计算(一)基本范型

对于分布式的概念既模糊又有些理解,总是无法很好的把握,似乎与我们工作无关,但又天天在用,  究竟什么是分布式, 它能做什么?从那下手,网上可以查到很多,都使我越来越糊涂,大概是分布式计算.分布式存储.分布式缓冲等.日日梳理这些 模糊的东西,希望能有一天,能从这里走出一条光明的路. 1. 根据分布式计算抽象层次和封装层次的不同,可以将分布式的计算范型分为以下几类: 2.消息传递范型 消息传递(Message Passing) 范型利用网络API,完成将用户请求进行打包.传送和解包的工作,必要时还要

Java语言的基础知识4

第五章(数组) 1.在Java中可以将数组看做是一个对象虽然基本数据类型不是对象但有基本数据类型组成的数组是对象. 2.对于二维数组求第二维就用array[0].length, array.length就是默认的是第一维的长度. 3.foreach并不是一个新的语法它是for的循环的格式化主要执行遍历功能的循环,example: int arry ={1,2,3,4,5}; for(int i :array){ system.out.println(): } 4.数组元素定义完以后可通过Arra