泛型

  • 泛型技术
  • 泛型的表现
  • 泛型代码示例
  • 泛型练习(强转)
  • 泛型类
  • 泛型方法
  • 泛型接口
  • 通配符
  • 限定

泛型技术

  • 在jdk1.4版本之前,容器什么类型的对象都可以存储,但在取出时,需要用到对象的特有内容时,需要做向下转型。
  • 但有时存入的对象类型不一致,会导致向下转型过程中出现ClassCastException。
  • 为了避免出现这个问题,只能在主观上控制,往集合中存储的对象类型保持一致。
  • jdk1.5后解决了这个问题,在定义集合时,就直接明确集合内存储元素的具体类型。这样,编译器在编译时,可以对集合中存储的对象类型进行检查,一旦发现类型不匹配,就编译失败。

好处

  • 将运行时期的问题转移到编译时期,可以更好的让程序员发现并解决问题。
  • 避免了向下转型的麻烦。

总结

  • 泛型是应用在编译时期的一项安全机制

泛型的擦除

  • 编译器通过对元素类型进行检查,只要检查通过,就会生成class文件,但在class文件中,就将泛型标识去掉了。

泛型的表现

  • 泛型在集合框架中应用的范围很大。
  • 什么时候需要写泛型呢?
    • 只要看到类,或者接口在描述时右边定义了<>,就需要泛型。
    • 其实是容器在不明确操作元素类型的情况下,对外提供一个参数<>
    • 使用容器时,只要将具体的类型实参传递给该参数即可
    • 简单的说,泛型就是传递类型参数

泛型代码示例

  • 当我们使用增强for循环或者迭代器取出list的元素时,可以正常取出,即使是往这个集合中存不同数据类型的元素,比如字符串类型和int。但其实在编译运行的过程中,JVM会对存入的元素进行自动装箱和拆箱,

//list.add(4)等于list.add(Integer.valueOf(4))
  • 而在使用迭代器时,使用的是Object类型接收,所以元素也可以正常取出。
    而当我们将取出的类型定义为String时,无论是想要获取长度还是内容,运行时都会报错,抛出ClassCastException异常。而代码在编译时是没有报错的。
package com.rqy.day19;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;/*** 泛型*/
public class GenericDemo {public static void main(String[] args) {List list = new ArrayList();list.add("abc");list.add(4);//list.add(Integer.valueOf(4))//       for(Object obj : list){//           System.out.println(obj);
//       }for(Iterator it = list.iterator();it.hasNext();){//Object obj = it.next();//System.out.println(obj.toString());String str = (String) it.next();System.out.println(str.length());System.out.println(str);}}
}

  • 为了运行时期不出现类型异常,可以在定义容器时,就明确容器中元素的类型,这样在编译期间,类型不符的元素就无法存入,会更安全。
  • 且当明确了类型后,就不需要使用强转。

泛型练习(强转)

  • 加入泛型,对自定义的对象进行存入取出
  • 按照自然排序(年龄),和自定义排序(姓名)

自然排序

package com.rqy.day18;public class Person implements Comparable<Person> {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person() {super();}public Person(String name, int age) {super();this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Person o) {int temp = this.getAge() - o.getAge();return temp == 0?this.getName().compareTo(o.getName()):temp;}
}
 Set<Person> set = new TreeSet<Person>();

自定义排序

package com.rqy.day18;import java.util.Comparator;public class CompaByName implements Comparator<Person> {//当指定泛型后,不需要使用强转@Overridepublic int compare(Person o1, Person o2) {int temp = o1.getName().compareTo(o2.getName());return temp==0?o1.getAge() - o2.getAge():temp;}//@Override
//    public int compare(Object o1, Object o2) {//        Students s1 = (Students)o1;
//        Students s2 = (Students)o2;
//        int temp = s1.getName().compareTo(s2.getName());
//        return temp == 0?s1.getAge()-s2.getAge():temp;
//        return 0;
//    }
}
package com.rqy.day19;import com.rqy.day18.CompaByName;
import com.rqy.day18.Person;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
/*** 加入泛型,对自定义的对象进行存入取出* 按照自然排序(年龄),和自定义排序(姓名)* 自定义排序*/
class GenericExample_1 {public static void main(String[] args) {//自定义排序,按照姓名Set<Person> set = new TreeSet<Person>(new CompaByName());set.add(new Person("lily",20));set.add(new Person("angle",20));set.add(new Person("vincy",29));set.add(new Person("lucy",25));set.add(new Person("zero",25));set.add(new Person("mary",24));for(Iterator<Person> it = set.iterator(); it.hasNext();){System.out.println(it.next());}}
}

  • 注意:若使用HashSet,需要覆盖HashCode和equals方法,但在equals方法中,参数就是Object,如果改成自定义的对象,就不是覆盖了
package com.rqy.day19;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*** HashSet演示 */
public class HashDemo {public static void main(String[] args) {Set<Person1> set = new HashSet<Person1>();set.add(new Person1("lucy",23));set.add(new Person1("lucy",22));set.add(new Person1("lucy",23));set.add(new Person1("zero",20));set.add(new Person1("lucy",29));for(Iterator<Person1> it = set.iterator();it.hasNext();){System.out.println(it.next());}}
}
package com.rqy.day19;import java.util.Objects;public class Person1  {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person1() {super();}public Person1(String name, int age) {super();this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Override//该处的Object不可修改public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person1 person1 = (Person1) o;return age == person1.age &&Objects.equals(name, person1.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

泛型类

package com.rqy.day19;class Tool{private Object obj ;public Object getObj() {return obj;}public void setObj(Object obj) {this.obj = obj;}
}
/*** 定义一个可以操作所有对象的工具类,可以降低对对象设置和获取的局限性* 但需要类型向上抽取*/
public class GenericDemo_1 {public static void main(String[] args) {Tool tool = new Tool();tool.setObj(new Women());Women wo = (Women) tool.getObj();//需要强制类型转换System.out.println(wo);}
}

  • 但正是因为使用了强制类型转换,代码在编写时可能会产生一些错误,而这些错误在编译时期是不会被检查出的,但到了运行时期,就会抛出ClassCastException异常


  • jdk1.5之后,提供了新的解决方案。当类型不确定时,对外提供参数,使用者通过传递参数的形式来完成类型的确定。
//在类定义时就明确参数,由使用该类的调用者,来传递具体的类型
class Util<W>{private W obj;public W getObj() {return obj;}public void setObj(W obj) {this.obj = obj;}
}
     Util<Women> ut = new Util<Women>();ut.setObj(new Women());//若类型不匹配,会直接编译失败Women wo = ut.getObj();//避免了向下转型System.out.println(wo);

当类型不匹配时,会直接编译失败

泛型方法

package com.rqy.day19;class Test<W >{void show(W w){System.out.println("show:"+w);}void  prin(W w){System.out.println("print:"+w);}
}
public class GenericExample_2 {public static void main(String[] args) {//new一个Test对象,指定类型为StringTest<String> test = new Test<String>();test.show("ert");test.prin(123);//当往Test类中传非String类型的元素时,编译会报错}
}

但现在的需求时,在不重新实例化一个对象的前提下,使用Test类下的prin方法打印int类型的元素。
这就需要使用到------泛型方法

 package com.rqy.day19;class Test<W >{void show(W w){System.out.println("show:"+w);}//调用该方法的类型不明确,使用泛型public <Q> void  prin(Q q){System.out.println("print:"+q);}
}
/*** 在不new新的Test对象下,输出int类型的元素* 思路:* 在方法上定义泛型*/
public class GenericExample_2 {public static void main(String[] args) {//new一个Test对象,指定类型为StringTest<String> test = new Test<String>();test.show("rqy");//test.prin("boss");//当往Test类中传非String类型的元素时,编译会报错test.prin(6);//}
}


注意:静态方法是无法访问类上定义的泛型的,如果静态方法需要定义泛型,只能定义在方法上。

 //静态方法上定义泛型static <A> void staticShow(A a){System.out.println("static:"+a);}

泛型接口

package com.rqy.day19;import javax.crypto.spec.PSource;//泛型接口
interface Inter<T>{public void show(T t);
}
//实现接口时明确类型
//class  Test1<String> implements Inter<String>{//    @Override
//    public void show(String s) {//    }
//}
//实现接口时不明确类型
class Test1<W> implements Inter<W>{@Overridepublic void show(W w) {}
}
//继承Test1类时明确参数类型
class Son extends Test1<String>{}
public class GenericExample_3 {public static void main(String[] args) {Son son = new Son();son.show("rqyboss");}
}

通配符

package com.rqy.day19;import java.util.*;
/*** 通配符*/
public class GenericExample_4 {public static void main(String[] args) {Set<String> set = new TreeSet<>();set.add("abc");set.add("rqy");set.add("zzz");set.add("uuu");List<String> list = new ArrayList<String>();list.add("rqy");list.add("ttt");list.add("bbb");printCollection(set);System.out.println("------------------");printCollection(list);}//使用迭代器取出,为了提高代码复用性,可以将其封装为方法//为了使得不论存入set或list都可以使用该方法,将参数换为Collection
//    private static void printCollection(Collection<String> set) {//        for (Iterator<String> it = set.iterator(); it.hasNext();){//            String str = it.next();
//            System.out.println(str);
//        }
//    }//但在不明确具体类型的情况下,可以将参数使用通配符?表示private static void printCollection(Collection<?> coll) {for (Iterator<?> it = coll.iterator(); it.hasNext();){Object obj  = it.next();System.out.println(obj);}}
}

限定

泛型的限定

确定了泛型上线
? extend E:接受E类型或E的子类型
package com.rqy.day19;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/*** 泛型的限定* 当同时需要对person1子类women或者man进行操作* 对于迭代器方法的参数选择,无论是选择woman还是man,代码的复用性都不高* 可以使用泛型中的限定* 既然woman和man都是person1的子类,那么参数直接使用? extends Person1即可*/
public class GenericDemo_5 {public static void main(String[] args) {List<Women> list = new ArrayList<Women>();list.add(new Women("lily",23));list.add(new Women("zero",20));list.add(new Women("stacy",29));printCollection(list);}private static void printCollection(Collection<? extends Person1> coll) {for (Iterator<? extends Person1> it = coll.iterator(); it.hasNext();){Person1 obj  = it.next();System.out.println(obj);}}
}

确定了泛型下限
? super E:接受E类型或E的父类型
package com.rqy.day19;import java.util.*;
/*** 泛型的限定 */
public class GenericDemo_5 {public static void main(String[] args) {List<Person1> list = new ArrayList<Person1>();list.add(new Person1("lily",22));list.add(new Person1("mary",20));list.add(new Person1("queen",29));printCollection(list);}private static void printCollection(Collection<? super Women> coll) {for (Iterator<? super Women> it = coll.iterator(); it.hasNext();){Object obj = it.next();System.out.println(obj);}}
}


文章为学习笔记,如有不足之处还请指正

泛型,泛型的表现,泛型类,泛型方法,泛型接口,通配符,限定相关推荐

  1. java泛型程序设计——定义简单泛型类+泛型方法

    [0]README 0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java泛型程序设计 的 定义泛型类+泛型方法的知识: [1]一个泛型类: 就是具有一个或多个 ...

  2. 鸟欲高飞先振翅,人求上进先读书 [泛型 泛型类 泛型方法 泛型接口 泛型通配符详解]

    文章目录 5. 泛型 5.1 泛型概述[理解] 5.2 为什么会引入泛型? 5.3 泛型的好处 5.4 泛型的定义格式 5.5 泛型类[应用] 5.6 泛型方法 5.7 泛型接口[应用] 5.8类型通 ...

  3. C#入门级——泛型、泛型类、泛型接口、泛型方法和泛型委托

    目录 一.泛型(generic) 二.为什么需要泛型类 类型膨胀 成员膨胀 使用object类 三.泛型的定义 定义泛型类 使用泛型类 泛型接口​​​​​​​ 两种泛型接口的实现方法 泛型方法 成员膨 ...

  4. Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用

    文章目录 泛型的概念 集合中使用泛型 自定义泛型结构 泛型在继承上的体现 通配符的使用 泛型的概念 集合容器类在设计阶段/声明阶段不能确定这个容器实际存的是什么类型的对象,所以在JDK1.5之前只能把 ...

  5. Java泛型-泛型作用+泛型在各种数据结构中的使用+自定义泛型

    文章目录 1. 概念 2. 为什么要使用泛型(Generic) 2.1 在ArrayList中使用泛型 2.2 在HashMap中使用泛型 3. 自定义泛型结构 3.1 泛型类与泛型接口 3.2 泛型 ...

  6. 【Java 泛型】泛型简介 ( 泛型类 | 泛型方法 | 静态方法的泛型 | 泛型类与泛型方法完整示例 )

    文章目录 一.泛型简介 二.泛型类 三.泛型方法 四.静态方法的泛型 五.泛型类与泛型方法完整示例 一.泛型简介 泛型 可以 简单理解为 参数化类型 , 主要作用在 类 , 方法 , 接口 上 ; j ...

  7. Java泛型(泛型类,泛型方法,静态方法泛型,泛型类与泛型方法例子)

    泛型 泛型简介 泛型可以理解为参数化类型,主要作用在类,方法和接口上. Java泛型 与 C++ 模板 : Java 中的泛型 , 是仿照 C++ 中的模板开发的 , 目的是让开发者可以写出通用,灵活 ...

  8. Java泛型02:自定义泛型类、泛型方法

    一.自定义泛型类(接口) 文章目录 一.自定义泛型类(接口) 1.基础知识 2.代码举例 二.自定义泛型方法 1.基础知识 2.代码举例 ps:泛型类和泛型接口的区别就是类和接口的区别,这里不做阐述 ...

  9. 【Flutter】Dart 泛型 ( 泛型类 | 泛型方法 | 特定类型约束的泛型 )

    文章目录 一.Dart 泛型类与泛型方法 二.Dart 泛型中的特定类型约束 三.Dart 自带泛型 四.完整代码示例 五. 相关资源 一.Dart 泛型类与泛型方法 泛型作用 : 为 类 , 接口 ...

  10. JAVA基础03-Object类,常用类,基本的数据结构, Collection常用体系,泛型-泛型通配符

    1.object类 1.概述 java.lang.object类是java语言中的根类,即所有类的超类(基类)他描述的所有的方法子类都可以使用,在对象实例化的时候最终找到的类就是object 如果一个 ...

最新文章

  1. Array.prototype.map() 、 Array.prototype.reduce()、Array.prototype.filter()
  2. GDataXML的一些简单示例。
  3. 强力攻城狮的职位要求...
  4. 面试必问!Tomcat 优化篇!
  5. (18)打鸡儿教你Vue.js
  6. 微信中两大典型微服务案例
  7. jQuery的HTML与CSS方法
  8. 文本处理利器Linux Awk这样入门☛常见变量的使用
  9. 数据库-优化-MYSQL数据库设计原则
  10. oracle插入数据语句实例,oracle Insert 用法总结
  11. 彻底删除 mysql 5.7_Ubuntu16.04彻底删除MySQL5.7
  12. Python中的无序集合(set)
  13. 【NLP新闻-2013.06.16】Representative Reviewing
  14. c语言的基本案例猴子,[转载]猴子选大王问题(C语言实现)
  15. WCF中加密数据信息
  16. Linux基础命令---vmstat显示虚拟内存状态
  17. POJ 2686 Traveling by Stagecoach
  18. 手机长度px值_深度讲解VIEWPORT和PX是什么?移动端单位px,em,rem
  19. java jdom_java中JDOM的基本使用方法
  20. Ansys 2022 安装教程(附赠免费的安装包)

热门文章

  1. TM4C123-JTAG
  2. vs2019中出现PyTorch is not linked with support for cuda devices的解决方法
  3. matlab 折射率椭球,一、折射率椭球.ppt
  4. Java基础篇--编程之路,道长且艰,千里之行,始于足下
  5. 如何制作一首歌的歌词 LRC 歌词制作和绑定
  6. [转]互联网系统架构的演进
  7. 代理服务器的速度慢的原因是什么?
  8. 软件设计第一步——分离关注点和单一职责原则
  9. spring和jump区别_JUMP与 SKIP 的区别
  10. 解密excel.xls文件密码