流年似水博客开通了,本站主要是写关于Web和大数据方面内容,正在更新中,欢迎大家光临!
  1. 文章:97 篇
  2. 总浏览:69,692 次
  3. 评论:22条
  4. 最后更新:2020-06-08
  5. 分类目录:39 个

Java之泛型详解

Java l, xy 405℃ 0评论

泛型

1.   泛型的理解

  1. 泛型是JDK5推出的新特性,又被称为参数化类型。

2.   泛型和方法参数的对比

 

传递类型

使用范围

泛型(参数化类型)

数据类型(只能是引用类型

类、接口、方法

方法的参数

对应数据类型的值(都可以)

方法

 

3.   泛型的好处

  1. 避免了代码中强制转换,提高了效率
  2. 应用泛型以后,可以将以前运行时的错误提前到编译期间,提高了程序的安全性             
  3. 抑制了编译警告
  4. 案例:



/**
* 演示使用泛型的好处
* */
@Test
public void genericTest(){
List list = new ArrayList();
list.add("鲁雪艳");
list.add("张向杨");
//未使用泛型,可以存放任意类型,程序类型存在潜在的危险
list.add(12);
list.add(new Object());
for (Object o : list){
//未使用泛型,需要强制转换才能调用存放元素的特定方法。此时强制会抛出异常(因为12 和 Object都不能强转成String)
String s = (String) o;
System.out.println(s.length());
}

//使用泛型(本案例中为String)以后,add方法只能添加String,从而避免安全性问题,同时也避免了取出时的强制转换。
List<String> stringList = new ArrayList<>();
stringList.add("aa");
stringList.add("bb");

//以下两句add会编译报错
stringList.add(12);
stringList.add(new Object());

for (String s : stringList){
System.out.println(s);
}
}

 

4.   泛型的表现形式

 


/**
* 演示泛型的表现形式(使用方法)
* */
public void genericTest2(){
//表现形式一:声明部分和初始化部分泛型都不省略,JDK5以后都可以使用此形式,不推荐!
// 原因:JDK7以后可以通过类型推断省略ArrayList<>尖括号的内容
List<String> list = new ArrayList<String>();
//表现形式二:省略初始化部分的泛型,JDK7以后推出的新特性。 推荐使用!
Set<Integer> set = new HashSet<>();
//表现形式三:省略初始化部分泛型
Collection<Integer> collection = new LinkedList();//注意:这里没有<>
/**--------------------------分割线--------------------------*/
//表现形式四:省略声明部分的泛型
Map map = new HashMap<>();
map = new HashMap<String,Object>();
//表现形式五:不使用泛型
Set s = new TreeSet();
}

 

 

注意:

  1. JDK为了兼容以前版本,也是允许不使用泛型的(表现形式五)
  2. 可以省略声明部分的泛型(表现形式四),但是此时泛型是不起作用的。作用同无泛型。
  3. 可以省略初始化部分(表现形式三),此时泛型起作用。
  4. 推荐使用表现形式二

5.   泛型的定义

(1)  定义泛型语法

  1. 泛型的定义使用 <> 和 标识符(一般为一个大写字母,可以任意多个)

 

(2)  泛型类

注意事项:

  1. 定义泛型类的时候,可定义多个泛型(在类名后面)。格式为: <T,U>
  2. 泛型类中不可以创建泛型对象(包括数组),也不可以在静态成员(静态属性、方法)中使用泛型类中定义的泛型。
  3. 泛型类中也可以定义泛型方法(包括静态),并且可以和类上定义的泛型重名

 


/**
* 定义泛型类
* */
class A<T,R> {


/**
* 定义泛型方法
* 注意:此时泛型方法中的泛型T虽然和类中泛型T相同,但是表示的含义并不相同
* 此方法的的T是自己在返回值前面定义的<T>,在使用时不要与类上定义的泛型T混淆
* */
public <T> T genericMethod(T t){
return t;
}

/**
* 静态泛型方法
* */
public static <T> T genericStaticMethod(T t){
return t;
}

/**
* 泛型当做属性
* */
private T t;
private R r;
/**
* 泛型当参数、返回值
* */
public R method(T t){
return r;
}

public A(T t, R r) {
this.t = t;
this.r = r;
}

/**
* 以下两种情况不能使用类上定义的泛型
* 一:泛型不能使用new操作符初始化
* 1.不能new泛型对象
* 2.不能new泛型数组
* 二:类上定义的泛型不能在静态成员(静态方法、静态属性)上使用
* */
//编译报错:泛型不能使用new一起使用,因为泛型是不具体的,在使用的时候才会传入进来。
private T t1 = new T();
private R[] rs = new R[2];

//编译报错:加载类的时候会优先加载静态成员,此时泛型并没有被指定。
public static R getR(){
return r;
}
public static T t2;
}

 

 

 

  1. 一个类实现泛型接口时,

(1)      要么在实现时泛型接口传入相应的泛型类型(不传入默认为Object);



/**
* 泛型接口
*/
interface Interface<K, V> {
/**
* 默认方法上使用泛型
*/
default K method(K k, V v) {
return k;
}
/**
* 方法上使用泛型
*/
V method(K k);
}

/**
* 不传入泛型,默认为Object
* */
class AA implements Interface {
@Override
public Object method(Object o) {
return null;
}
}
/**
* 传入泛型
* */
class BB implements Interface<String,Integer> {
@Override
public Integer method(String s) {
return null;
}
}

 

(2)      要么该类也定义成泛型形式(注意:接口和实现类的泛型符号要相同)。



/**
* 类定义成泛型
* 注意: 类泛型的符号要和接口泛型的符号相同
* */
class CC<T,U> implements Interface<T,U>{

@Override
public U method(T t) {
return null;
}
}

3.泛型类在创建对象的时候一定要指定泛型类型

(3)  泛型接口

  1. 泛型接口的定义和泛型类类似
  2. 泛型接口可以应用在默认方法上



/**
* 泛型接口
*/
interface Interface<K, V> {
/**
* 默认方法上使用泛型
* */
default K method(K k, V v) {
return k;
}
/**
* 方法上使用泛型
* */
V method(K k);
}

 

  1. 一个接口继承泛型接口时,要么在继承时传入相应的泛型;要么该类也定义成泛型形式。注意:父接口和子接口的泛型符号要相同(同类实现泛型接口)
  2. 泛型接口在实现的时候确定泛型类型

 

(4)  泛型方法

  1.      泛型方法的定义在返回值的前面
  2.      泛型方法可以存在泛型类中(见泛型类案例)也可以存在非泛型类中
  3.      方法泛型,在调用的时候确定泛型类型



/**
* 演示泛型方法定义在普通类中
* */
class D{

/**
* 成员泛型方法
* */
public <T> void method(T t){

}
/**
* 静态泛型方法
* */
public static <U> U method2(U u){
return u;
}
}

 

6.   泛型的通配符

 

  1. ? : 代表任意泛型类型 : 除了null,其他不能添加
  2. ? extends 上限类型:代表上限类型或者上限类型的子类型 。 除了null,其他不能添加

 

  1. ? super 下限类型:代表下限类型或者下限类型的父类型(包括实现接口)除了null,只能添加下限类型

 

 

注意:

 

    案例一:使用泛型设计一个可以打印任何Collection集合的方法


/**
* 演示? 通配符
* */
public static void printCollection(Collection<?> collection){
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().getClass().getSimpleName());
}
}

 


/**
* 测试? 通配符
* */
@Test
public void test2(){
List<Integer> list = new ArrayList<>();
list.add(123);
printCollection(list);

Set<String> set = new HashSet<>();
set.add("aa");
printCollection(set);
}

结果:
Integer
String


案例二:使用泛型设计遍历Collection集合中保存元素类型只能是Number或者Number的子类的集合

 


/**
* 演示 <? extends 上限类型> 通配符
* */
public static void printCollection4(Collection<? extends Number> collection){
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().getClass().getSimpleName());
}
}



/**
* 测试<? extends 上限类型> 通配符
* */
@Test
public void test4(){
List<Integer> list = new ArrayList<>();
list.add(123);
printCollection4(list);

Set<String> set = new HashSet<>();
set.add("aa");
//编译错误:因为String类不是Number的子类型
printCollection4(set);
}

案例三:使用泛型设计方法,只能遍历Collection集合保存元素只能是IntegerInteger父类的集合



/**
* 演示 <? super 下限类型> 通配符
* */
public static void printCollection5(Collection<? super Integer> collection){
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().getClass().getSimpleName());
}
}

 


/**
* 测试<? super 下限类型> 通配符
* */
@Test
public void test4(){
List<Integer> list = new ArrayList<>();
list.add(123);
printCollection5(list);

Set<String> set = new HashSet<>();
set.add("aa");
// 编译错误:因为String类不是Integer的父类型 printCollection5(set);
}

 

注意:

1  使用通配符定义的集合泛型,<?> 和 <? extends 上限类型只能添加null值。而<? super 下限类型可以添加下限类型的元素

 


/**
* 演示 < ? super 下限类型>通配符可以添加下限类型的参数(多态)
* 功能: 批量向collection集合中添加元素T
* */
public static <T> boolean addAll(Collection<? super T> collection, T ... ts){
boolean result = false;
for (int i = 0; i < ts.length; i++){
result &= collection.add(ts[i]);
}
return result;
}

 



@Test
public void test(){
List<String> list = new ArrayList<>();
addAll(list,"aa","bb");
for (String s:list){
System.out.println(s);
}
}

结果:
aa
bb


/**
* 演示 < ? extends 限类型>通配符可以添加下限类型的参数
*
* */
public static <Tboolean addAll2(Collection<? extends T> collection... ts){
    boolean result = false;
    //只能添加null
    collection.add(null);
    for (int i = 0i < ts.lengthi++){
        //编译错误
        result &= collection.add(ts[i]);
    }
    return result;
}

 

 

/**
* 演示 < ? >通配符可以添加下限类型的参数
*
* */
public static <Tboolean addAll2(Collection<?> collection... ts){
    boolean result = false;
    //只能添加null
    collection.add(null);
    for (int i = 0i < ts.lengthi++){
       //编译错误:
        result &= collection.add(ts[i]);
    }
    return result;
}

 

 

 

 

7.   注意事项

  1. 使用泛型传递的是类型(数据类型)而不是具体类型的值。并且只能是引用类型。
  1. 使用带泛型的类时,可以不指定泛型,此时默认为Object
  2. 泛型可以在类、接口、方法中定义。
  3. 泛型传入父类,也是可以添加子类类型的。

List<Comparable> list = new ArrayList<>();
//使用泛型可以保存传入泛型类型或者传入泛型的子类型
list.add("aa");
for (Comparable s:list){
    System.out.println(s);
}

 

  1. 泛型不支持继承

//编译报错:
List<Object> list = new ArrayList<String>();

 

 

 

 

 

转载请注明:流年似水 » Java之泛型详解

喜欢 (0)or分享 (0)

Warning: copy(https://cn.gravatar.com/avatar/?s=54&d=%2Fwp-content%2Fthemes%2Fyusi1.0%2Fimg%2Fdefault.png&r=g): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /usr/share/nginx/html/timewentby/wp-content/themes/yusi1.0/functions.php on line 239

Warning: copy(/wp-content/themes/yusi1.0/img/default.png): failed to open stream: No such file or directory in /usr/share/nginx/html/timewentby/wp-content/themes/yusi1.0/functions.php on line 243
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址