目录 :
1 ) . 入门泛型的基本应用
2 ) . 泛型的内部原理及更深应用
3 ) . 泛型的通配符扩展应用
4 ) . 泛型集合的综合应用案例
5 ) . 自定义泛型方法及其应用
6 ) . 自定义泛型方法的练习与类型推断总结
7 ) . 自定义泛型类的应用
8 ) . 通过反射获得泛型的实际类型参数
一 . 入门泛型的基本应用
1 ) . 泛型是一种约束,就是将一组数据分门别类的 有条不絮的 分配存储方式
2 ) . Demo :
package cn.ittext.day02;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
public class GenericTest
{
public static void main(String[] args ) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
/**
* 庖丁解牛 : 泛型基本应用
*
* [1] 集合方面
*
* [2] 反射方面
*
*
* 小结 : 泛型是一种约束,就是将一组数据分门别类的有条不絮的分配存储方式
*
*
*/
//------------------------------------ 集合方面
Collection<String> arry = new ArrayList<String>();
arry .add( "A" );
arry .add( "S" );
arry .add( "D" );
for (String col : arry )
{
sop ( col );
}
//---------------------------------------反射方面 ,通过反射过去StringBuffer构造方法进行实例化
Constructor<String> constructor = String. class .getConstructor(StringBuffer. class ); //获取StringBuffer的构造方法字节码文件
String newInstance = constructor .newInstance( new StringBuffer( "ASD" )); //通过构造犯法实例化一个StringBuffer并赋值
sop ( newInstance );
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
二. 泛型的内部原理及更深应用
1 ) . 理论基础:
1.1 泛型的必备术语 ,例子 : ArrayList<E>类 定义 和ArrayList<Integer>类引用涉及的术语
[1] ArrayList<E> 称为 泛型类型
[2] ArrayList<E> 中的E 称为 类型变量或类型参数
[3] ArrayList<Integer> 称为 参数化类型
[4] ArrayList<Integer> 中的 Integer称为 类型参数的实例或 实际类型参数
[5] ArrayList<Integer> 中的 <> 称为 typeof
[6] ArrayList 称为 原始类型
1.2 参数化类型与原始类型的兼容性 :
[1] 参数化类型可引用一个原始类型的对象,编译仅报告警告 : Collection<String> c =new Vector()
[2] 原始类型的对象可引用参数化类型,编译仅报告警告 : Collection c =new Vector<String>();
1.3 参数化类型不考虑类型参数的继承关系:
[1] Vector<String> v =new Vector<Object>(); -->错误
[2] Vector<Object> v =new Vector<String>(); --->错误
1.4 在创建数组实例时,数组的元素不能使用参数化类型
[1] Vector<String> vectorList[] = new Vecotr<Integer>[10];
1.5 思考:以下代码会报错吗?为什么?
Vector v1 =new Vector<String>() ;
Vector<Object> v =v1;
[1] 表示不会报错, 一 因为编译器是一行一行编译的 ,二因为对于编译器而言 ,Vector的引用是无类型约束的,因此 可以 新添加一个类型来约束 三是因为 Object是String的父类型
2 ) . Demo:
package cn.ittext.day02;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;
public class GenericTest01
{
public static void main(String[] args ) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException
{
/**
* 庖丁解牛 : 泛型的底层原理
*
* [3] 泛型是对编译时的约束 ,因此我们可通过反射 隔过泛型 直接进入 运行时
*
* [4] 加泛型的集合与不加泛型的集合底层字节码是同一张
*
* 小结 :
*
* [1] 泛型是作用于编译器的,可限定集合中的输入类型,以此挡住源程序的非法输入
*
* [2] 加不加泛型的集合底层的字节码表都是一张,因为加了泛型的集合在编译器编译后会去掉"类型"信息,也就是泛型
*
* [3] 我们可通过反射的方式,将不同类型的字符传入同一个泛型约束的集合中
*
*
*/
//------------------------------------ [3]集合方面,通过反射避开泛型插入其它类型
Collection<String> arryRe = new ArrayList<String>();
arryRe .getClass().getMethod( "add" ,Object. class ).invoke( arryRe , 12); //通过反射调用集合中的add方法然后成功插入了 int 类型的数字
arryRe .add( "A" );
arryRe .add( "S" );
arryRe .add( "D" );
for (Object col : arryRe )
{
sop ( col );
}
//------------------------------------ [4]集合方面 ,判断加泛型与不加泛型是不是一张字节码表
//----结果是同一张,因此可知结论泛型是作用于编译器的
Collection arr = new ArrayList ();
Collection<String> arryR = new ArrayList<String>();
if ( arr .getClass() == arryR .getClass())
{
sop ( true );
}
//-------------------以下代码不报错的原因是,对编译器而言 ,Vector引用是没有用泛型限定的,因此可在下边进行重新的泛型限定
Vector v1 = new Vector<String>() ;
Vector<Object> v = v1 ;
sop ( v );
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
小结 :
1. 泛型作用于集合,数组 ,可以用来限定一切可以装值的容器
2. 泛型可以帮助我们更好的有条不絮的管理我们的数据
三. 泛型的通配符扩展应用
1 ) . Dem o :
package cn.ittext.day02;
import java.util.ArrayList;
import java.util.Collection;
public class genericTest02
{
public static void main(String[] args )
{
Collection<String> arry = new ArrayList<String>();
arry .add( "A" );
arry .add( "S" );
arry .add( "D" );
// printColliection( arry );
Collection<Integer> arryInt = new ArrayList<Integer>();
arryInt .add(88);
arryInt .add(77);
arryInt .add(99);
// printColliectionFull(arryInt);
// printCollectionEx( arry );
// printCollectionEx(arryInt);
printCollectionExFull ( arryInt );
}
/**
* 庖丁解牛 :
*
* 1. 通配符的使用 ?
*
*
* 如何让一个方法接受任意类型的集合
*
* [1] 传什么那么方法就定义什么类型
*
* [2] 通配符?搞定,无论传什么类型都OK
*
* 小结:使用?可引用其他各种参数化的类型,?通配符定义的变量主要作为引用,可调用与参数化无关的方法,不能调用与参数化有关的方法
*
*
*
*
*/
public static void printColliection(Collection<String> clo ) // [1]
{
for (Object obj : clo )
{
sop ( obj );
}
}
public static void printColliectionFull(Collection<?> clo ) // [2]
{
//clo.add("111"); // add()与 参数化有关,因此不可调用
//clo.size(); //size() 与参数化无关,因此可调用
for (Object obj : clo )
{
sop ( obj );
}
}
/**
* 庖丁解牛:
*
* 2.通配符的扩展
*
* [1] 限定通配符的上边界
*
* Vector <? extends Number> = new Vecotr <Integer> (); --> 指 引用参数化类型可以是 Number或者Number的子类
*
* [2] 限定通配符的下边界
*
* Vector <? super Integer> = new Vecotr <Integer> (); --> 指引用参数化类型可以是Integer或者Integer的父类
*
* 小结 :
*
* 通过泛型限定通配符上边界与下边界可对类型化参数范围进行限定,以实现类型继承体系的实现
*
*
*/
public static void printCollectionEx(Collection<? extends Number> clo ) //传入的类型是 number或者number 的子类
{
for (Object obj : clo )
{
sop ( obj );
}
}
public static void printCollectionExFull(Collection<? super Integer> clo ) //传入的类型是Integer或者是Integer的父类
{
for (Object obj : clo )
{
sop ( obj );
}
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
2 ) . 须知 :
2.1 泛型限定通配符的使用 ?
2.2 泛型限定通配符对于参数化类型范围的继承体系的扩展
四. 泛型集合的综合应用案例
1 ) . 操作Map集合的三个维度
1.1 只获取所有值
1.2 只获取所有键
1.3 获取所有键值(组合体)
2 ) . Demo :
package cn.ittext.day02;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class GenericTest03
{
public static void main(String[] args )
{
/**
* 庖丁解牛:
*
* 需求 : 对HashMap进行处理,存值,取值
*
* [1] entrySet() ; 专门用来迭代map集合的方法
*
*
*
*/
HashMap<Integer,String> map = new HashMap<Integer,String>();
map .put(1, "SUMMER" );
map .put(2, "AUTUMN" );
map .put(3, "winter" );
Set<Entry<Integer, String>> entrySet = map .entrySet();
for (Entry<Integer, String> es : entrySet )
{
sop ( es .getKey()+ ":::" + es .getValue());
}
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
小结 :
1. HashMap底层是 键值不可重复 的
五 . 自定义泛型方法及其应用
1 ) . Demo :
package cn.ittext.day02;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class GenericTest03
{
public static void main(String[] args )
{
// PrintColection();
Type (1,2); //将鼠标放到泛型方法上可以看到类型推断出来的参数类型
Type ( "as" , "ww" );
}
public static <T> void Type(T start ,T end ) //T 指 方法的接收参数类型是通用的
{
/**
* 庖丁解牛:
*
* [1] 通过泛型实现类型的通用
*
* [2] 泛型的应用 : 集合内数据交换 --> 此章为实现
*
* [3] 泛型的多个类型参数实现
*
* 小结 :
*
* 只有引用类型可做泛型的参数化类型
*
* [1] 泛型可作用于 集合 和数组
*
* [2] 泛型可作用于类
*
* [3] 泛型可作用于方法
*
* [4] 反省可作用于参数类型
*
* [5]泛型可作用于异常
*
*
*/
sop ( start );
sop ( end );
int [] ts = new int []{11,22,33};
swap ( ts ,1,2);
getValue (1,2,3);
}
private static <T extends Exception> void sayHello() throws T //异常泛型的应用
{
try
{
} catch (Exception e )
{
throw (T) e ;
}
}
public static <K,V,S> void getValue(K key ,V value ,S start ) //多参数实现
{
sop ( key + "::" + value + "::" + start );
}
public static <T> void swap ( int [] ts , int start , int end ) //数据位置的交换
{
int temp = ts [ start ];
ts [ start ] = ts [ end ];
ts [ end ] = temp ;
for ( int i =0; i < ts . length ; i ++)
{
sop ( ts [ i ]);
}
}
public static void PrintColection()
{
/**
* 庖丁解牛:
*
* 需求 : 对HashMap进行处理,存值,取值
*
* [1] entrySet() ; 专门用来迭代map集合的方法
*
*
*
*/
HashMap<Integer,String> map = new HashMap<Integer,String>();
map .put(1, "SUMMER" );
map .put(2, "AUTUMN" );
map .put(3, "winter" );
Set<Entry<Integer, String>> entrySet = map .entrySet();
for (Entry<Integer, String> es : entrySet )
{
sop ( es .getKey()+ ":::" + es .getValue());
}
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
小结 :
1. 泛型可做用于类,方法,参数类型,异常等应用上
六. 自定义泛型方法的练习与类型推断总结
1 ) . Demo:
package cn.ittext.day02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator ;
/**
* @author winter
* @describe 类功能描述
*/
public class GenericTest04 {
public static void main(String[] args )
{
//------------------------------------- [1]
Object obj = "1223" ;
autoConvert ( obj ); //转换成任意类型
//------------------------------------- [2]
String[] in = new String[] { "1" , "2" , "3" };
String fullObject = FullObject ( in , new String());
// sop (fullObject.length());
//--------------------------------------------- [3]
Collection<String> cols = new ArrayList<String>();
cols .add( "A" );
cols .add( "S" );
cols .add( "D" );
// PrintCollection( cols );
//------------------------------------------- [4]
String[] str = new String[1024];
// copyArray( cols , str );
//------------------------------------------- [5]
String[] strArr = new String[] { "liuziqiang" , "zhangxiaojian" , "zhangshaui" };
String[] strSrr = new String[1024];
copyArrays ( strArr , strSrr );
}
/**
*
* 庖丁解牛: 泛型应用
*
* [1] 编写一个泛型方法,将Object类型的对象转化为其他任意类型
*
*[2] 定义一个方法,可将任意类型的数组中的所有元素值填充为相应类型的某个对象
*
*[3] 采用自定泛型方法的方式打印出任意参数化类型的集合中的所有元素
*
*[4] 定义一个方法,把任意参数类型的集合中的元素数据安全的复制到相应类型的数组中
*
*[5] 定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中
*
*/
private static <T> void copyArrays(T[] strArr , T[] strSrr ) //[5]
{
strSrr = strArr ; //取出原数组数据,赋给新数组
for (Object obj : strSrr ) //迭代新数组的数据
{
sop ( obj );
}
}
private static <T> void copyArray(Collection<T> cols , T[] str ) //[4]
{
str = (T[]) cols .toArray() ;
for ( int i =0 ; i < str . length ; i ++)
{
sop ( str [ i ]);
}
}
private static void PrintCollection(Collection<?> cols ) //[3]
{
for (Object col : cols )
{
sop ( col );
}
}
private static <T> T FullObject(T[] cols ,T obj ) // [2]
{
for ( int i =0 ; i < cols . length ; i ++)
{
obj = cols [ i ];
}
return obj ;
}
private static <T> T autoConvert(Object obj ) //[1]
{
return (T) obj ;
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
2 ) . 类型参数的类型推断:
2.1 引入 : 编译器判断泛型方法的实际参数的过程称为类型推断 --》类型推断是相对于知觉推断的,其实现方法是一种非常复杂的过程
2.2 特点 :根据调用泛型方法时传递的参数类型和返回值的类型来推断
【1】 根据泛型方法定义的参数化类型 进行推断
【2】 根据调用方法时传入的 参数类型 进行推断
【3】 若是泛型方法定义的参数化类型是多类型的,则根据 这多个类型的最大交集类型推断
2.3 如何查看泛型方法的推断类型是什么?
--》将鼠标放到泛型方法上,而后会弹出一个框框,开头就是推断类型
小结 :
1. 此章讲述了泛型的相关应用以及泛型类型推断
七. 自定义泛型类的应用 --》 在Dao层的应用
1 ) . Demo”
package cn.ittext.day02;
import java.util.Set;
/**
* @author winter
* @describe crud 操作
*/
public class GenericDao<E> {
/**
*
* @param key
* @return 对象
* @describe 键找值
*/
public E selectProper( int key )
{
return null ;
}
/**
* @param 对象
* @describe 增加
*/
public void add(E obj )
{
}
/**
* @param 键
* @describe 删除
*/
public void delete( int key )
{
}
/**
* @param 对象
* @describe 删除
*/
public void delete(E obj )
{
}
/**
*
* @param 对象
* @describe 修改
*/
public void update(E obj )
{
}
/**
* @param 条件
* @return 一组对象
* @describe 条件查找
*/
public Set<E> findByConditions(String where )
{
return null ;
}
/**
*
* @param user
* @return password
* @describe 登陆 -- 》 先判断数据库中是否有此用户名,在获取密码跟web端的密码进行比较
*/
public E findByUserName(String name )
{
return null ;
}
}
4 ) . 若类中的有多个方法需要使用泛型,则使用类级别的泛型;若类中只有一个方法需要使用泛型,则使用方法级别的泛型
小结 :
1. 在某一个泛型的方法或者集合的类型不确定的时候可使用泛型的方式实现
2. 在类上加泛型是为了让类中的所有方法的泛型类型进行规范统一,此时静态方法是不可用泛型的
八 . 通过反射获得泛型的实际类型参数-->框架底层
1 ) . Demo :
package cn.ittext.day02;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
/**
* @author winter
* @describe 通过反射的方式获取泛型的实际类型
*/
public class GenericTest05 {
public static void main(String[] args ) throws NoSuchMethodException, SecurityException
{
/**
* 庖丁解牛: Hibernate 底层 ,泛型的高级应用
*
* [1] 如何获取泛型当中的参数化类型
*
*/
ArrayList<String> arr = new ArrayList<String>();
// String typeName = arr.getClass().getTypeName(); //实验证明 普通的将此 集合进行反射是获取不到的
//调用获取泛型的参数化类型的方法
applyArrayList ( arr );
}
//获取泛型的参数化类型的方法
public static void applyArrayList(ArrayList<String> arr ) throws NoSuchMethodException, SecurityException
{
Method method = GenericTest05. class .getMethod( "applyArrayList" , ArrayList. class ); //通过方法获取到该方法的字节码文件
Type[] genericParameterTypes = method .getGenericParameterTypes(); //通过该方法的字节码文件获取到其传入的泛型的参数化类型
sop ( genericParameterTypes [0]); //获取第一个
}
public static void sop(Object obj )
{
System. out .println( obj );
}
}
2 ) . 在框架的底层,都是通过反射的方式获取其对象/集合/方法的泛型参数化类型以此判断该封装成什么容器的值
九 . 总结
1 ) . 浅显理解泛型不仅仅是 对类/方法/参数/集合的一种约束, 更是一种规范,使其数据更好地分门别类的进行管理进行传输 ;
2 ) . 反射,注解,泛型,枚举,框架的故事详解:
假如有一栋毛胚房 :
框架就是毛胚房, 反射就是 毛胚房中的 底层元素的调用方式 , 注解就是 毛胚房中自定义元素的调用方式 , 泛型就是 毛胚房 的规划设计方式 ,枚举就是 毛胚房中的公共设施
小结 :
1. 反射是 从我要我调用到 我做好你拿 , 从客户端编变成服务端的思维的转变,是令一种 调用方法的方式,是框架的底层逻辑
2. 注解是 为自定义的相关元素属性 提供了简便的调用方式,以达到优化代码,提供可读性
3. 泛型是 对数据分门别类的有条不絮的分配存储传输的管理方式 ,以此 增强代码可读性和扩展性
4. 枚举是 如同公地一样,资源有限,即用即取,公共使用,封装成的一个类型,以此减少内存资源消耗
5 . 框架是 通过大量的反射,注解,泛型,枚举 融合为一起的大的通用容器