泛型例子:
HashMap<String, Integer> maps = new HashMap<String, Integer>();
maps.put("zxx", 28);
maps.put("lhm", 35);
maps.put("flx", 33);
Set<Map.Entry<String, Integer>> entrySet = maps.entrySet();
for(Map.Entry entry: entrySet){
System.out.println(entry.getKey()+":"+entry.getValue());
}
对在jsp页面中也经常要对Set或Map集合进行迭代
<c:forEach items="${map}" var="entry">
${entry.key}:${entry.value}
</c:forEach>
泛型的实际类型只能是引用类型,不能是基本类型
Java的泛型方法没有C++模版函数功能强大,java中的如下代码无法通过编译:
<T> T add(T x. T y){
return (T)(x+y);
//return null;
}
交换数组中的两个元素的文职的泛型方法语法定义如下:
static <E> void swap(E[] a, inti, int j){
E t = a[i];
a[i] = a[j];
a[j] = t;
}
用于防止泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示
只有引用类型才能作为泛型方法的实际参数,swap(new int[3], 3, 5);语句语句会报告编译错误。
除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如,<V extends Serializable&cloneable> void method(){}
普通方法、构造方法和静态方法中都可以使用泛型。编译器也不允许创建类型变量的数组。
也可以用类型变量表示异常,成为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。
在泛型中可以同事有多个类型参数,在定义他们的尖括号中用都好分隔,例如:public static <K,V> V getValue(K key){return map.get(key)}
只有引用类型才能作为泛型方法的世纪参数,对于add方法,使用基本类型的数据进行测试没有问题,到这时因为自动装箱和拆箱了,swap(new int[3], 3,5)语句会报告编译错误,这是因为编译器不会对new int[3]中的int自动拆箱和装箱了,因为new int[3]本身已经是对象了,你想要的有可能就是int 数组呢,就会弄巧成拙了
类型参数的类型推断
编译器判断范性方法的世纪类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种非常复杂的过程。
根据通用泛型方法时世纪传递的参数类型过返回值的类型来推断,具体规则如下:
当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:
swap(3,5) --? static <E> void swap(E[] a, int i, int j)
当某个类型变量在整个参数列表中的所有参数和返回值中的多出被应用了,如果调用方法时这多出的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:
add(3,5) -- > static <T> T add(T a, Tb)
当某个类型变量在整个参数列表中的所有参数的返回值中的多出被应用了,如果调用方法时这多出的世纪应用类型对应到了不同的类型,且没有使用返回值,这时候取了多个参数中的交集类型,例如:下面的语句世纪对应的类型就是Number,编译没问题,只是运行时。
fill(new Integer[3], 3, 5f) = static <T> void
定义泛型的类型
dao 是 data access object 数据访问对象
crud对数据库的增删改查
dao完成crud
如果类的实力对象中的多出都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,只是后就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:
public vlass GenericDao<T>{
private T field1;
public void save(T obj)
public T getById(int id)
}
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的。例如,如下两种方式
GenericDao<String> dao = null;
new GenericDao<String>();
注意:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数
通过反射获得泛型的参数化类型
因为去类型化 所以不能用class来获取泛型类型
可以获取类中的方法,从方法中获取泛型类型
类加载器
Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每隔类负责加载特定文职的类
BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,就是BootStrap (c++)
Java虚拟机中的所有类装载器采用具有斧子关系的树形结构进行组织,在实例化每隔类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载
BootStrap(JRE/lib/rt.jar)
|
|
ExtClassLoader(JRE/lib/ext/*.jar)
|
|
AppClassLoader(CLASSPATH指定的所有jar或目录)
**************************************
模版方法设计模式
一个总体的流程在父类里面已经规定好了
而做这个流程的一些细节父类无法确定
就把他空出来留给子类去完成
**************************************
编写自己的类加载器
自定义的类加载器必须继承ClassLoader
loadClass方法不需要去重写
必须重写findClass方法
用defineClass方法将二进制数据转换为Class字节码
有包名的类不能调用无包名的类