首先看一看java泛型类的使用:

  1. /**
  2. * 一个泛型方法:使程序更加安全
  3. * 并且能被更多的使用
  4. * @author 丁**
  5. *
  6. * @param <T>
  7. */
  8. class Pair<T>{
  9. private T first;
  10. private T second;
  11.  
  12. //实例化类型变量
  13. public static<T> Pair<T> makePair(Class<T> cl){
  14. try {
  15. return new Pair<>(cl.newInstance(), cl.newInstance());
  16. } catch (Exception e) {
  17. return null;
  18. }
  19. }
  20.  
  21. public Pair(){ first = null; second = null; }
  22. public Pair(T first, T second){ this.first = first; this.second = second;}
  23.  
  24. public T getFirst() {
  25. return first;
  26. }
  27. public void setFirst(T first) {
  28. this.first = first;
  29. }
  30. public T getSecond() {
  31. return second;
  32. }
  33. public void setSecond(T second) {
  34. this.second = second;
  35. }
  36.  
  37. }
  1. class Father {
  2. private int age = 40;
  3. public void getName(){
  4. System.out.println(age);
  5. }
  6. }
  7.  
  8. class Son extends Father{
  9. private int age = 12;
  10. public void getName() {
  11. System.out.println(age);
  12. }
  13. }

在普通类中:Father aa = new Son();父类是可以用来指向子类的

但是在泛型类中却不是如此:

  1. Pair<Son> bb = new Pair<>();
  2. Pair<Father> cc = bb;//error

1:虽然Son是Father的子类,但是Pair<T>之间没有继承关系:

  1. List<Object> a1 = new ArrayList<>();
  2. List<String> a2 = new ArrayList<>();
  3. //设a1可以等于a2
  4. //a1 = a2;
  5. //a1.add(1111);因为是对a1进行操作,所以可以添加Object,a1.add(Object ad);
  6. //a2.get(0);报错,因为a1添加Object进入了a2的空间中,但是a2是String类型,所以报错

2:可以将参数化类型转换成一个原始类型:

  1. List<String> a2 = new ArrayList<>();
  2. List a3 = a2;//可以通过编译,但是后面使用方法时可能会产生类型错误!
  3. //这时候a3对象时原始类型,所以add(Object obj);
  4. a3.add(123);//是对a3进行操作,但是最终结果保存到了a2中,将一个Integer装入String中
  5. 显然是错误的;

3:泛型类可以扩展或实现其他的泛型类:

  1. //泛型接口
  2. interface List1<E>{
  3. }
  4.  
  5. //实现了泛型接口的泛型类
  6. class List2<T, E> implements List1<E>{
  7.  
  8. }
  9.  
  10. //泛型类
  11. class List3<T>{
  12.  
  13. }
  14.  
  15. //继承了其他泛型类的泛型类
  16. class List4<T, E> extends List3<E>{
  17.  
  18. }
  1. List1<Father> b1 = new List2<Son, Father>();//因为List2实现了List1
  2. List3<Father> b2 = new List4<Son, Father>();//List4继承了List3,所以List3是父类,可以指向子类对象。

虽然这样也完成了泛型类的继承,实现了和普通类一样的多态,但是使用起来并不是特别好,就这样java引入了通配符概念:

通配符上限:

  1. /*
  2. 通配符的上限:Pair<? extends Father> c2
  3. extends是关键字
  4. Pair<T>代表的是某个唯一(具体的泛型类)的泛型类:比如Pair<Son>,Pair<Father>
  5. 但是Pair<? extends Father>不是具体的泛型类,它所指的是参数类型为Father的子类的所有泛型类(包括Father)
  6. */
  7. Pair<? extends Father> c3;
  8. Pair<Father> c1 = new Pair<>();
  9. Pair<Son> c2 = new Pair<>();
  10. //c2 = c1;error
  11. c3 = c1;
  12. c3 = c2;

需要注意的是:

  1. /*
  2. * 使用通配符的上限的问题:
  3. * ? extends Father getFirst();
  4. * void setFirst(? extends Father);
  5. * 当c2= c1时:
  6. * c2.setFirst(Father father);时,会将Father对象添加到Son对象内存中,这是不好的
  7. * 所以使用extends上限时,不能使用setFirst(? extends Father),add(? extends Father)* 等方法。
  8. * 但可以使用getFirst();方法
  9. */
    c2.setFirst( new Father(); );//error

通配符下限:

  1. /*
  2. * 通配符的下限:
  3. * ? super Son
  4. * 表示的不是某个具体的泛型类,而是表示参数类型为Son的父类的所有可能的泛型类(包括* * Son)
    * 和通配符上限一样,通配符的超类型限定不能使用getFirst()方法,但可以使用setFirst(XX)方法
  5. */
  6. Pair<Son> c1 = new Pair<>();
  7. Pair<? super Son> c3;
  8. c3 = c1;
  9.  
  10. //另一种超类型限定的写法
    Pair<T extends Comparable<? super T>> c4;

 无限定通配符:

  1. //无限定通配符
  2. Pair<Son> c7 = new Pair<>();
  3. Pair<String> c5 = new Pair<>();
  4. //c7 = c5;error,因为他们不是同一种类型
  5. Pair<?> c6 = new Pair<>();
  6. c6 = c5;//Pair<?>是所有的Pair泛型类的父类,Pair<?> c6 = new Pair<xx>();

Pair<?>和Pair的本质不同在于:可以用任意的Object对象调用原始的Pair类的setObject()方法;

通配符的捕获:

  1. //交换First,Second变量值
  2. public static void swap(Pair<?> p){
  3. ? t = p.getFirst();//error,因为通配符(?)不是类型变量,所以不能直接将?写入代码中,利用通配符的捕获来解决这个问题。
  4. p.setFirst(p.getSecond());
  5. p.setSecond(t);
  6. }
  1. //交换First,Second变量值
  2. public static void swap(Pair<?> p){
  3. swapHelper(p);//在调用下面的方法时,类型参数就被捕获了。
  4. }
  5.  
  6. //利用通配符的捕获来解决该问题
  7. public static <T> void swapHelper(Pair<T> p){
  8. T t = p.getFirst();//T是具体的某个类型。
  9. p.setFirst(p.getSecond());
  10. p.setSecond(t);
  11. }

注意:通配符的捕获只有在许多限制的情况下才是合法的,编译器必须能够确信通配符表达的是单个,确定的类型。

java泛型类的继承规则的更多相关文章

  1. JAVA封装、继承

    封装 1.概念: 将类的某些信息隐藏在类的内部,不允许外部程序访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: a.只能通过规定的方法访问数据 b.隐藏类的实例细节,方便修改和实 ...

  2. Java中的继承

    我们在以前的学习中,我们会了C#中的继承,今天我们来了解了解Java中的继承,其实都大同小异啦! 1.语法 修饰符 SubClass extends SuperClass(){ //类定义部分 } e ...

  3. Java面向对象的继承

    继承也是面向对象的又一重要特性,继承是类于类的一种关系,通俗来说狗属于动物类,那么狗这个类就继承了动物类 java中的继承是单继承的,一个类只能继承与一个父类 子类继承父类之后,子类就拥有了父类的所有 ...

  4. JAVA中的继承和覆盖

    java里面的继承是子类继承父类的一些方法和属性(除private属性和方法之外):对于父类的私有属性和方法子类是没有继承的.可是要想子类也能訪问到父类的私有属性,必须给私有属性以外界訪问的方法接口. ...

  5. java类的继承,多态,抽象类与接口

    知识点梳理:     1,怎样定义自己的类. MyStarFrame,MyStarPanel 类中定义: (1)属性(数据),变量. (2)方法(函数),行为. (3)构造方法(特征,作用,何时被调用 ...

  6. java类的继承的一些细节

    类的继承是java面向对象体系的一个重要方面(封装.继承.多态),对于java类的继承,需要注意如下细节. 1.构造函数. 如果一个类没有任何构造函数,系统会默认分配一个无参的构造函数给它,这个构造函 ...

  7. java方法的继承,覆盖与重载

    java中的继承使用extends关键字,在子类继承了父类之后将会获得父类的全部属性与方法(父类的构造器除外).如果在定义java类时没有显示定义她的父类,那么这个类默认将扩展java.lang.Ob ...

  8. Java 类设计----Java类的继承

    Java类的继承 为描述和处理个人信息,定义类Person: public class Person { public String name; public inat age; public Dat ...

  9. Java中的继承、封装、多态的理解

    Java中的继承.封装.多态 继承的理解: 1.继承是面向对象的三大特征之一,也是实现代码复用的重要手段.Java的继承具有单继承的特点,每个子类只有一个直接父类. 2.Java的继承通过extend ...

随机推荐

  1. bat脚本设置系统环境变量即时生效

    关于bat的资料多但零碎,记录一下. 1.设置环境变量即时生效:通过重启explorer来实现即时生效(亲测有效) @echo off set curPath=%cd% wmic ENVIRONMEN ...

  2. 查看三种MySQL字符集的方法

    查看MySQL字符集的命令是我们经常会使用到的,下文就介绍了其中的三种查看MySQL字符集的命令,供您参考学习. 作者:佚名来源:互联网|2010-10-09 11:36 移动端 收藏 分享 CTO训 ...

  3. [SinGuLaRiTy] Nescafe 24杯模拟赛

    [SinGularLaRiTy-1044] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 小水塘(lagoon) 题目描述 忘川沧月的小水塘 ...

  4. [拾 得] zip gzip bzip2 & tar 压缩/打包 四大金刚

    坚持知识分享,该文章由Alopex编著, 转载请注明源地址: http://www.cnblogs.com/alopex/    索引: 介绍压缩和打包 gzip bzip2 zip 的基本使用 gz ...

  5. jquery自定义进度条与h5原生进度条

      介绍一款自定义的进度条 <div class="box-nine"> <div class="progress"> <!--一 ...

  6. C#读取固定文本格式的txt文件

    C#读取固定文本格式的txt文件 一个简单的C#读取txt文档的程序,文档中用固定的格式存放着实例数据. //判断关键字在文档中是否存在 ] == "设备ID:107157061" ...

  7. spring task 定时

    最近工作中需要用到定时任务的功能,虽然Spring3也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之后,决定整合更为专业的Quartz来实现定时任务功能. 首先,当然是添加依 ...

  8. CentOS7.3 ARM虚拟机扩容系统磁盘

    由于扩容磁盘的操作非同小可,一旦哪一步出现问题,就会导致分区损坏,数据丢失等一系列严重的问题,因此建议:在进行虚拟机分区扩容之前,一定要备份重要数据文件,并且先在测试机上验证以下步骤,再应用于您的生产 ...

  9. python_如何定义带参数的装饰器?

    案例: 实现一个装饰器,用它来检查被装饰函数的参数类型. 需求: 装饰器可以通过函数,指明函数参数类型,进行函数调用的时候,传入参数,检测到不匹配时,抛出异常 如何解决这个问题? 先要获取函数的签名, ...

  10. 配置SESSION超时与请求超时

    <!--项目的web.xml中 配置SESSION超时,单位是min.用户在线时间.如果不设置,tomcat下的web.xml的session-timeout为默认.--><sess ...