经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
java基础——泛型
来源:cnblogs  作者:蜀道,难  时间:2023/7/31 9:11:11  对本文有异议

泛型的引入

看下面这段代码:

  1. private static int add(int a, int b) {
  2. System.out.println(a + "+" + b + "=" + (a + b));
  3. return a + b;
  4. }
  5. private static float add(float a, float b) {
  6. System.out.println(a + "+" + b + "=" + (a + b));
  7. return a + b;
  8. }
  9. private static double add(double a, double b) {
  10. System.out.println(a + "+" + b + "=" + (a + b));
  11. return a + b;
  12. }

如果没有泛型,要实现不同类型的加法,每种类型都需要重载一个add方法;通过泛型,我们可以复用为一个方法:

  1. private static <T extends Number> double add(T a, T b) {
  2. System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
  3. return a.doubleValue() + b.doubleValue();
  4. }

泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型

下面这段代码:

  1. List list = new ArrayList();
  2. list.add("xxString");
  3. list.add(100d);
  4. list.add(new Person());

我们在使用上述list中,list中的元素都是Object类型(无法约束其中的类型),所以在取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出java.lang.ClassCastException`异常。

引入泛型,它将提供类型的约束,提供编译前的检查:

  1. List<String> list = new ArrayList<String>();
  2. // list中只能放String, 不能放其它类型的元素

泛型的好处

1、编译时,检查添加元素的类型,提高了安全性

2、减少了类型转换的次数,提高效率

3、不再提示编译警告

介绍

1.泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题

2.在类声明或实例化时只要指定好需要的具体的类型即可。

3.Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException.异常。同时,代码更加简洁、健壮

4.泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。

代码举例:

  1. public class Generic03 {
  2. public static void main(String[] args) {
  3. //注意,特别强调:E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  4. Person<String> person = new Person<>("dfdfs");
  5. person.show();//String
  6. /**
  7. * Person类相当于下面这样子
  8. * class Person{
  9. * String s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  10. *
  11. * public Person(String s) {//E也可以是参数类型
  12. * this.s = s;
  13. * }
  14. *
  15. * public String f(){//返回类型使用E
  16. * return s;
  17. * }
  18. * public void show(){
  19. * System.out.println(s.getClass());//显示s的运行类型
  20. * }
  21. * }
  22. */
  23. Person<Integer> person2 = new Person<>(100);
  24. person2.show();
  25. /**
  26. * Person类相当于下面这样子
  27. * class Person{
  28. * Integer s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  29. *
  30. * public Person(Integer s) {//E也可以是参数类型
  31. * this.s = s;
  32. * }
  33. *
  34. * public Integer f(){//返回类型使用E
  35. * return s;
  36. * }
  37. * public void show(){
  38. * System.out.println(s.getClass());//显示s的运行类型
  39. * }
  40. * }
  41. */
  42. }
  43. }
  44. //泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
  45. class Person<E>{
  46. E s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  47. public Person(E s) {//E也可以是参数类型
  48. this.s = s;
  49. }
  50. public E f(){//返回类型使用E
  51. return s;
  52. }
  53. public void show(){
  54. System.out.println(s.getClass());//显示s的运行类型
  55. }
  56. }

语法

泛型的声明

interface 接口名{}和class 类名<K,V>{}

说明:

1)其中,T,K,V不代表值,而是表示类型

2)任意字母都可以。常用T表示,是Type的缩写

泛型的实例化

要在类名后面指定类型参数的值(类型)。如:

  1. List<String> strList = new ArrayList<String>();
  2. Iterator<Customer> iterator = customers.iterator();

泛型使用举例

需求:

? 1.创建3个学生对象

? 2.放入到HashSet中学生对象,使用.

? 3.放入到HashMap中,要求Key 是String name,Value就是学生对象

? 4.使用两种方式遍历

  1. public class GenericExercise {
  2. public static void main(String[] args) {
  3. //使用泛型方式给HashSet放入3个学生对象
  4. HashSet<Student> students = new HashSet<>();
  5. students.add(new Student("jack",18));
  6. students.add(new Student("tom",18));
  7. students.add(new Student("ml",18));
  8. //第一种遍历方式,增强for循环
  9. for (Student student:students){
  10. System.out.println(student);
  11. }
  12. //使用泛型方式给HashMap放入3个学生对象
  13. HashMap<String, Student> hm = new HashMap<>();
  14. hm.put("milan",new Student("milan",34));
  15. hm.put("jack",new Student("jack",31));
  16. hm.put("tom",new Student("tom",30));
  17. //2.迭代器
  18. Set<Map.Entry<String, Student>> entries = hm.entrySet();
  19. Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
  20. System.out.println("==========================");
  21. while (iterator.hasNext()){
  22. Map.Entry<String, Student> next = iterator.next();
  23. System.out.println(next.getKey()+"-"+next.getValue());
  24. }
  25. }
  26. }
  27. class Student{
  28. private String name;
  29. private int age;
  30. public Student(String name, int age) {
  31. this.name = name;
  32. this.age = age;
  33. }
  34. public String getName() {
  35. return name;
  36. }
  37. public void setName(String name) {
  38. this.name = name;
  39. }
  40. public int getAge() {
  41. return age;
  42. }
  43. public void setAge(int age) {
  44. this.age = age;
  45. }
  46. @Override
  47. public String toString() {
  48. return "Student{" +
  49. "name='" + name + '\'' +
  50. ", age=" + age +
  51. '}';
  52. }
  53. }

泛型使用注意事项

1.interface 接口名{}和class 类名<K,V>中T,K,V只能是引用类型。如下面:

  1. List<Integer> list = new ArrayList<Integer>();//这样写正确
  2. List<int> list = new ArrayList<int>();//这样写错误

2.在给泛型指定具体类型后,可以传入该类型或者其子类类型

3.泛型使用形式

  1. //1.第一种方式
  2. List<Integer> list1 = new ArrayList<Integer>();
  3. //2.第二种方式
  4. List<Integer> Iist2 = new ArrayList<>();

3.如果我们这样写List list3=new ArrayList();默认给它的泛型是 E就是Object.,等价于ArrayList arrayList = new ArrayList();

自定义泛型

自定义泛型类

语法:

  1. class 类名<T,R....>{//......表示可以有多个泛型
  2. 成员
  3. }

注意事项:

1.普通成员可以使用泛型(属性、方法)

2.使用泛型的数组,不能初始化

3.静态方法中不能使用类的泛型

4.泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)

5.如果在创建对象时,没有指定类型,默认为Object

  1. class Tiger<T,R,M>{
  2. String name;
  3. R r;//属性使用到泛型
  4. M m;
  5. T t;
  6. T[] ts;//因为数组在new时不能确定T的类型,就无法在内存开空间
  7. public Tiger(String name) {
  8. this.name = name;
  9. }
  10. public Tiger(R r, M m, T t) {
  11. this.r = r;
  12. this.m = m;
  13. this.t = t;
  14. }
  15. public Tiger(String name, R r, M m, T t) {//构造器使用泛型
  16. this.name = name;
  17. this.r = r;
  18. this.m = m;
  19. this.t = t;
  20. }
  21. //因为静态是和类相关的,在类加载时,对象还没有创建
  22. //所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化
  23. //static R r2;
  24. // public static void m1(M m){
  25. //
  26. // }
  27. public R getR() {//返回类型可以使用泛型
  28. return r;
  29. }
  30. public void setR(R r) {//方法使用到泛型
  31. this.r = r;
  32. }
  33. }

自定义泛型接口

语法:

  1. interface 接口名<T,R....>{
  2. }

注意事项:

1.接口中,静态成员也不能使用泛型(这个和泛型类规定一样)

2.泛型接口的类型,在继承接口或者实现接口时确定

3.没有指定类型,默认为Object

  1. /**
  2. * 泛型接口使用的说明
  3. * 1.接口中,静态成员也不能使用泛型
  4. * 2.泛型接口的类型,在继承接口或者实现接口时确定
  5. * 3.没有指定类型,默认为Object
  6. */
  7. //在继承接口指定泛型接口的类型
  8. interface IA extends IUsb<String,Double>{
  9. }
  10. //当我们去实现IA接口时,因为IA在继承IUsub接口时,指定了U为String, R为Double,在实现IUsub接口的方法时,使用String替换U,是Double替换R
  11. class AA implements IA{
  12. @Override
  13. public Double get(String s) {
  14. return null;
  15. }
  16. @Override
  17. public void hi(Double aDouble) {
  18. }
  19. @Override
  20. public void run(Double r1, Double r2, String u1, String u2) {
  21. }
  22. }
  23. //实现接口时,直接指定泛型接口的类型
  24. //给U指定Integer给R指定了Float
  25. //所以,当我们实现IUsb方法时,会使用Integer替换U,使用Float替换R
  26. class BB implements IUsb<Integer,Float>{
  27. @Override
  28. public Float get(Integer integer) {
  29. return null;
  30. }
  31. @Override
  32. public void hi(Float aFloat) {
  33. }
  34. @Override
  35. public void run(Float r1, Float r2, Integer u1, Integer u2) {
  36. }
  37. }
  38. //没有指定类型,默认为Object
  39. //建议直接写成IUsb<Object,Object>
  40. class CC implements IUsb{//等价class CC implements IUsb<Object,,Object>
  41. @Override
  42. public Object get(Object o) {
  43. return null;
  44. }
  45. @Override
  46. public void hi(Object o) {
  47. }
  48. @Override
  49. public void run(Object r1, Object r2, Object u1, Object u2) {
  50. }
  51. }
  52. interface IUsb<U,R>{
  53. //普通方法中,可以使用接口泛型
  54. R get(U u);
  55. void hi(R r);
  56. void run(R r1,R r2,U u1,U u2);
  57. //在jdk8中,可以在接口中,使用默认方法,也是可以使用泛型
  58. default R method(U u){
  59. return null;
  60. }
  61. }

自定义泛型方法

语法

  1. 修饰符 <T,R...>返回类型 方法名(参数列表){
  2. }

注意事项:

1.泛型方法,可以定义在普通类中,也可以定义在泛型类中

2.当泛型方法被调用时,类型会确定

3.public void eat(E e){},修饰符后设有<T,R.>eat方法不是泛型方法,而是使用了泛型

  1. public class CustomMethodGeneric {
  2. public static void main(String[] args) {
  3. Car car = new Car();
  4. car.fly("宝马",100);//当调用方法时,传入参数,编译器,就会确定类型
  5. System.out.println("==================");
  6. Fish<String, ArrayList> fish = new Fish<>();
  7. fish.hello(new ArrayList(),11.3f);
  8. }
  9. }
  10. //泛型方法,可以定义在普通类中,也可以定义在泛型类中
  11. class Car{//普通类
  12. public void run(){//普通方法
  13. }
  14. //泛型方法
  15. //1.<T,R>就是泛型
  16. //2.是提供给 fly使用的
  17. public <T,R> void fly(T t,R r){//泛型方法
  18. System.out.println(t.getClass());
  19. System.out.println(r.getClass());
  20. }
  21. }
  22. class Fish<T,R>{//泛型类
  23. public <U,M> void eat(U u,M m){//泛型方法
  24. }
  25. //下面的这个hi方法不是泛型方法,是hi方法使用了类声明的泛型
  26. public void hi(T t){
  27. }
  28. //泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
  29. public <K> void hello(R r,K k){
  30. System.out.println(r.getClass());
  31. System.out.println(k.getClass());
  32. }
  33. }

泛型的继承和通配符

说明:

1.泛型不具备继承性

2.<?>:支持任意泛型类型

3.<? extends A>:支持A类以及A类的子类,规定了泛型的上限

4.<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

  1. public class GenericExtends {
  2. public static void main(String[] args) {
  3. //泛型没有继承性
  4. //List<Object> list = new ArrayList<String>();
  5. List<Object> list1 = new ArrayList<>();
  6. List<String> list2 = new ArrayList<>();
  7. List<AA> list3 = new ArrayList<>();
  8. List<BB> list4 = new ArrayList<>();
  9. List<CC> list5 = new ArrayList<>();
  10. //如果是List<?>c,可以接受任意的泛型类型
  11. printCollection1(list1);
  12. printCollection1(list2);
  13. printCollection1(list3);
  14. printCollection1(list4);
  15. printCollection1(list5);
  16. //List<? extends AA>c:表示上限,可以接受AA或者AA子类
  17. //printCollection2(list1); error
  18. //printCollection2(list2); error
  19. printCollection2(list3);
  20. printCollection2(list4);
  21. printCollection2(list5);
  22. //List<?super AA>c:支持AA类以及AA类的父类,不限于直接父类
  23. printCollection3(list1);
  24. //printCollection3(list2); error
  25. printCollection3(list3);
  26. //printCollection3(list4); error
  27. //printCollection3(list5); error
  28. }
  29. //说明:List<?>表示任意的泛型类型都可以接受
  30. public static void printCollection1(List<?> c){
  31. for (Object object :c){
  32. System.out.println(object);
  33. }
  34. }
  35. //?extends AA表示上限,可以接受AA或者AA子类
  36. public static void printCollection2(List<? extends AA> c){
  37. for (Object object:c){
  38. System.out.println(object);
  39. }
  40. }
  41. //?super 子类类名AA:支持AA类以及AA类的父类,不限于直接父类,规定了泛型的下限
  42. public static void printCollection3(List<? super AA> c){
  43. for (Object object:c){
  44. System.out.println(object);
  45. }
  46. }
  47. }
  48. class AA{
  49. }
  50. class BB extends AA {
  51. }
  52. class CC extends BB {
  53. }

原文链接:https://www.cnblogs.com/malinyan/p/17592372.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号