黑马程序员——JAVA学习笔记九(泛型)

1,    泛型机制是JAVA5才支持,使用泛型机制编写的代码比那些杂乱地使用Object变量,然后再强制类型转换的代码具有更好的安全性和可读性。
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用,在泛型出来以前,泛型程序设计是继承Object来实现的。但是有缺点:1,当获取一个值必须要强制类型转换。2,没有类型检查错误,运行时才会出错。泛型提供了类型参数,解决了此问题。
 
2,    定义泛型类(generic class)。格式:
public class Pair<T, U>{.....}
T ,U 为类型变量
类定义中的类型变量指定方法的返回类型以及域和局部变量的类型,如
private T  var;
public T getFirst( T a) {
    return var;
}
调用时:Pair<String, Integer>
 
泛型方法,格式:
class ArrayLog {
public  static <T> getmiddle(T ...a)
     {
        return a[a.length];
      }
}
这是在普通类中定义的,不是在泛型类中定义的,这是一个泛型方法。类型变量放在修饰符的后面,返回类型的前面。(既可以定义在普通类中,也可以定义在泛型类中)。
调用时,在方法名前加入具体的类型(大多数情况下,编译器能够推断出来,寻找共同的超类型)。
 
3,    类型变量的限定,类和方法需要对类型变量加以约束。
T  extends Parents  ;    上限定,表示T是Parents的子类型。
有多个限定可以用"&"符号隔离类型变量,可以有多个接口,但是至多只有一个类。
 
4,    虚拟机中没有泛型类型,所有的对象都是普通类。
无论什么时候定义个泛型类型,都提供了一个原始类型(raw type),原始数据类型名字就是删去类型参数后的泛型类型名。擦出类型变量,并替换限定类型(无限定替换为Object).
原始类型用第一个限定的类型变量来替换,如果没有就用Object来替换。
 
翻译类型表达式:
当调用泛型方法时,如果擦出返回类型,编译器将会插入强制类型转换。例:
Pair <Employer> budies =...
Employer buddy = buddies.getFirst();
编译器将会插入强制类型转换代码。
当存取一个泛型域时也要强制插入类型转换代码。
 
翻译泛型方法,方法的擦出带来了两个问题。例子:
class DateInterval extends Pair<Date> {
public void setSecond(Date second) 
{
    .....
}
...}
然而当擦出后,变成:
class DateInteval extends Pair {
    public void setSecond(Date second) {
}
}
然而还存在着父类中继承的setSecond方法,public void setSecond(Object second);
希望调用具有多态性,所以需要生成一个桥方法(brige method)。
public void setSecond(object second) {
setSecond((Date) second);
}
还有可能存在两个返回值类型不同的方法:
Date getSecond() {
return (Date) super.getSecond().clone() ;
} 自己定义
Ojbect getSecond()覆盖继承。
不能这样写代码,但是编译器能正确处理,虚拟机也能正确处理,比如clone方法。
总之:需呀记住以下 泛型转化事实
虚拟机中没有泛型类型
所有的类型参数都用他们的限定类型代替
桥方法被合成保持多态
为保持类型安全,必须要插入强制类型转换
 
 
5,    约束和局限性
不能用基本类型数据作为类型化参数。
运行时类型查询只适用与原始数据,只要使用instaceof或者强制类型转换涉及到泛型类型时,都会有一个都会有一个编译器警告。
不能创建参数化类型的数组,但是允许声明类型化数组。Pair<String> []  p = new Pair<String>[10];//ERROR
可变参数传递一个泛型参数,只会产生警告,而不是出错。
 
不能实例化类型变量,如new T().T.class等。
first = T.class.newInstance()//error
但可以这样设计: pulic static <T> Pair<T> makePair (Class<T> cl) {
    {
        try { return new Pair<> (cl.newInstance(), cl.newInstance()) }
        catch(Exception ex) { return null;}
    }
Pair<String>p = Pair.makePair(String.class);
不能创建泛型数组:T [] P = new T[10]//error; 相当于 object [] p = new object [10];
如果有类型变量,可以这样,如:
public static <T extends Comparable> T[] minamx(T ...a) {
    T[] mm = (T[]) Array.newInstance(a.getClass.getComponentType(), 10);
}
例如Arrays类中的,Object[] toArray(); T[] toArray(T[] result);
 
不能再静态域或方法中引用类型变量。
不能抛出或捕获泛型类的实例。Public class Problem<T exents exceptino>{...}//error
Catch字句不能使用类型变量。catch (T e) //error  .
不过在异常规范中使用是正常的。
public static <T extends Throwable> void doWork(T t) throw T
{
try {
    do work;
} catch (Throw realcautse) {
t.initCase(realcasu) ;
    throw t;
}
}
可以用来消除对已检查异常的检查。必须为每个已检查异常提供一个处理器,在线程中麻烦。可以简化:
public Block{
public static <T extends Throwable> void throwAs(Throwable e ) throw T 
{
    throw (T) e;
}
}
以下代码将会转化为未检查异常:
try {
    do work
} catch ( Throwable t ) {
   Block.<Exceptions>throwAs(t);
}
在多线程中非常有用:用户只需要覆盖body方法来提供一个具体调用toThread时,会得到Thread类的对象,它的run方法不会介意已检查的异常。欺骗了编译器。

public abstract class Block{

publci abstract void body() throws Exception;

public Thread toThread() {

return new Thread() {

public void run() {

try {

body();

}

catch (Throwable t) {

Block.<RuntimeException> throwAs(t);

}

};

}

public static <T extends Throwable> void throwAs(Throwable e ) throw T

{

throw (T) e;

}

}

当泛型类型擦出时,无法创建引发冲突的条件。

class Pair<T>{

public boolean equals( T o){ //error

return true;

}

类型擦除后,并没有覆盖Ojbect中的equals方法。是重载,但是两个有冲突。
要想支持擦出转换,就需要强行限制一个类或类型变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数。
 
6,    泛型通配符:?extends Parents :上限: ? super Son  :下限,超类型。
时间: 2024-10-10 14:10:58

黑马程序员——JAVA学习笔记九(泛型)的相关文章

黑马程序员——JAVA学习笔记十(IO)

1,    可以从其中读入一个字节序列的对象成为输入流,可以向其中写入一个字节序列的对象就做输出流.这些字节序列的来源地可以是文件,也可以是网络连接或者内存块.抽象类InputStream和OutputStream构成了I/O层次的基础.因为字节流不便于处理以Unicode存储的信息,所以有了Writer和Reader抽象类,这些从其中继承的类都是读入和写入基于2个字节的Unicode码元,而不是单个字节.   2,    InputStream 与OutputStream: abstract

黑马程序员——JAVA学习笔记十四(高新技术三)

10 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代

黑马程序员——JAVA学习笔记五(异常)

1,     异常:是在运行时期发生的不正常情况. 在java中用类的形式对不正常情况进行了描述和封装对象.描述不正常的情况的类,就称为异常类. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高阅读性. 其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述. 不同的问题用不同的类进行具体的描述.比如角标越界.空指针异常等等. 问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系. 不正常情况分成了两大类: Throwabl

黑马程序员——JAVA学习笔记十一(文件操作File)

为了很方便的代表文件的概念,以及存储一些对于文件的基本操作,在java.io包中设计了一个专门的类——File类. 在File类中包含了大部分和文件操作的功能方法,该类的对象可以代表一个具体的文件或文件夹,所以以前曾有人建议将该类的类名修改成FilePath,因为该类也可以代表一个文件夹,更准确的说是可以代表一个文件路径. 1.创建文件 1)boolean java.io.File.createNewFile() throws IOException用来创建文件,如果文件存在,创建失败,返回fa

黑马程序员——JAVA学习笔记十二(高新技术一)

 1,    静态导入: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.solaire.enhance; import static java.lang.Math.max;  //import   语句可以导入一个类或某个包中的所有类 //import static  静态导入 JDK5以后才有.语句导入一个类中的某个静态方法或所有静态方法 //无名包和有包名中的类在一起,没有package,则为无名包. //一个类

黑马程序员——JAVA学习笔记十三(高新技术二)

8,    注解 Annotation(注解)是JDK5.0及以后版本引入的. 注解是以 @注解名 的形式标识 注解不会影响程序语义,只作为标识 注解是新的类型(与接口很相似),它与类.接口.枚举是在同一个层次,它们都称作为java的一个类型(TYPE). 它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素进行说明,注释. 它的作用非常的多,例如:进行编译检查.生成说明文档.代码分析等 注释类型 是一种特殊的接口 用 @interface 声明如 [email prote

黑马程序员——JAVA学习笔记六(多线程)

1,    什么是多线程?一个程序可以执行多个任务,每一个任务称为一个线程,运行多个线程的程序称为多线程程序. 进程:正在进行中的程序(直译). 线程:进程中一个负责程序执行的控制单元(执行路径).   多线程的好处:解决了多部分代码同时运行的问题.多线程的弊端:线程太多,会导致效率的降低. 其实,多个应用程序同时执行都是CPU在做着快速的切换完成的.这个切换是随机的.CPU的切换是需要花费时间的,从而导致了效率的降低 2 ,    创建线程方式:  创建线程方式一:继承Thread类 1.定义

黑马程序员——JAVA学习笔记四(继承、接口、内部类)

1,    通过extends关键字让类与类之间产生继承关系.多个类中存在相同属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需定义这些属性和行为,只要继承那个类即可,已存在的类叫做超类,基类,或父类.新类称为子类,派生类,孩子类. 子类可以直接访问父类中的非私有的属性和行为.子类无法继承父类中私有的内容.JAVA不支持多继承,只支持单继承,多实现. 继承提高了代码复用性,让类与类之间产生了关系.为多态提供了前提. 2,    super关键字代表父类中成员变量内存空间的标示.两个作用

黑马程序员——JAVA学习笔记二(语法基础)

1,     Java程序都是以类的形式存在的,所以需要告诉虚拟机需要加载类的位置,那么可以设置classpath变量.classpath变量如果有;,则表示还会在当前目录查找,没有;则不会在当前目录查找. 当然如果没有classpath也会在当前目录查找. 2,    rd删除目录,加/S可以删整个目录,Windows从里向外删除. 3,    一个文件只有一个public类,文件名必须和类名相同,如果不是友好类,则不需要同名. 4,    JAVA一共有50个关键字 关键字是电脑语言里事先定