1. 设计泛型的初衷:

1) 主要是为了解决Java容器无法记忆元素类型的问题:

i. 由于Java设计之初并不知道会往容器中存放什么类型的元素,因此元素类型都设定为Object,这样就什么东西都能放了!

ii. 但是这样设计有明显的缺点:

a. 取出元素的时候必须进行强制类型转换(尽管集合在运行时里面元素的“运行时类型”不变,即元素的getClass返回的还是最初自己的类型而不是Object);

b. 如果不小心往集合里加了不相同类型的元素可能会导致类型异常(进行equals、compare比较的时候尤为明显);

c. 由于没有类型就需要在很多地方进行强制类型转换,但是这样做增加了编程的复杂度,并且代码也不美观(臃肿),维护起来也更加困难;

2) 泛型的概念定义:

i. 从Java 5开始,引入了参数化类型(Parameterized Type)的概念,改造了所有的Java集合,使之都实现泛型,允许程序在创建集合时就可以指定集合元素的类型,比如List就表名这是一个只能存放String类型的List;

ii. 泛型(Generic):就是指参数化类型,上面的List就是参数化类型,因此就是泛型,而String就是该List泛型的类型参数;

3) 泛型的好处:

i. 使集合可以记住元素类型,即取出元素的时候无需进行强制类型转化了,可以直接用原类型的引用接收;

ii. 一旦指定了性参数那么集合中元素的类型就确定了,不能添加其他类型的元素,否则会直接编译保存,这就可以避免了“不小心放入其他类型元素”的可能;

iii. 上述保证了如果在编译时没有发出警告,则在运行时就一定不会产生类型转化异常(ClassCastException);

iv. 显然,泛型使编程更加通用,并且代码也更加简洁,代码更加容易维护;

2. 创建泛型对象——自动类型推断的菱形语法:

1) 首先,定义泛型引用一定要使用尖括号指定类型参数,例如:List list、Map等,其中的String、Integer之类的就是类型参数;

2) 其次,使用构造器构造泛型对象的时候可以指定类型参数也可以不指定,例如:

i. List list = new List(); // 这当然是对的

ii. List list = new List<>(); // 这样对,因为List的类型参数可以从引用推断出!!!但是引用的类型参数是一定要加的,否则无法推断;

3) 由于<>很像菱形,因此上面的语法也叫做菱形语法;

4) 错误提示:引用无类型参数但构造器有类型参数的写法是不对的!例如,List list = new List();!!至于为什么不对,这会在泛型原理的章节中详细介绍,这里先记住这样写不对就行了!!反正就是一个原则,泛型引用是一定要指定类型参数的!!

5) 示例:

3. 定义泛型类、接口:

1) 不仅Java的集合都定义成了泛型,用户自己也可以定义任意泛型的类、接口,只要在定义它们时用<>来指定类型参数即可;

2) 例如:public class Fruit { ... },其中指定了该泛型的类型参数,这个T是一个类型参数名,用户可以任意命名(就像方法参数的形参名一样),只有在定义该泛型的对象时将T替换成指定的具体类型从而产生一个实例化的泛型对象,例如:Fruit fruit = new Fruit<>(...);

3) 类型形参可以在整个接口、类体内当成普通类型使用,集合所有可使用普通类型的地方都可以使用类型形参,例如:

可以看到,在接口内/类体内甚至还可以使用该类型形参运用泛型!例如上面makeSet方法返回一个泛型Set;

4) 定义泛型构造器:泛型的构造器还是类名本身,不用使用菱形语法,例如:

定义构造器无需MyGeneric(...) { ... }了,只有在new的时候需要用到菱形语法;

4. 实现/继承泛型接口/泛型类:

1) 定义泛型和使用泛型的概念:主要区别就是定义和使用

i. 那Java的方法做类比,Java的方法在定义的时候使用的都是形参(虚拟参数),但是在调用方法(使用方法)的时候必须传入实参;

ii. 同样泛型也有这个特点,泛型的类型参数和方法的参数一样,也是一种参数,只不过是一种特殊的参数,用来表示未知的类型罢了;

iii. 因此,泛型也是在定义的时候必须使用形参(虚拟参数,用户自己随意命名),但是在使用泛型的时候(比如定义泛型引用、继承泛型)就必须使用实参,而泛型的实参就是具体的类型,像String、Integer等具体的类型(当然也可以是自定义类型);

2) 泛型定义的时候使用形参,例如:public class MyGeneric { ... } // T就是一个自己随意命名的类型形参

3) 使用泛型的时候必须传入实参:

i. 定义引用(对象)的时候毫无疑问,肯定需要传实参:ArrayList list = ...; // 必须用具体的类型,像这里就是String来代替形参,即实参

ii. 实现/继承一个泛型接口/类的时候:

你在实现/继承一个接口/类的时候实际上是在使用该接口/类,比如:public class Son extends Father { ... }中Father这个类就是正在被使用,毫无疑问,必定是在使用;

因此泛型其实无法继承/实现,因为在实现/继承的时候必须为泛型传入类型实参,给定实参后它就是一个具体的类型了,就不再是泛型了

示例:public class MyType extends MyGeneric { ... } // implements、extends的时候必须传入类型实参,因为实在使用泛型。原则上,任何编程语言都不允许泛型模板层层继承!!

4) 继承之后,父类/接口中的所有方法中的类型参数都将变成具体的类型,你在子类中覆盖这些方法的时候一定要用具体的类型,不能继续使用泛型的类型形参了,例如:

这一定能保证,这三个方法都是从父类中继承来的,只不过类型形参T被实例化成了String;

5. 泛型参数继承:

1) 上面派生出来的类不是泛型,是一个实体类型,因为其继承的泛型是具有类型实参的,而Java还支持一种特殊的语法,可以让你从泛型继续派生出泛型,而泛型的类型参数可以继续传承下去;

2) 语法如下:

即子泛型可以传承父泛型的泛型参数,那么在子类中泛型参数T就和父类的完全相同,还是照常使用(和父类一样正常使用);

3) 注意:

i. 这里extends Father了,因此父类泛型Father就是被使用了,而按照之前讲的规则,使用给一个泛型是必须要指定类型实参的!因此这里的这个语法是一种特殊语法,Java专门为这种语法开了后门,这种语法只有在类型参数传承的时候才会用到(即上面这种应用);

ii. 一旦使用了这种语法,就表示要进行类型参数的传承了(即父类的T传递给子类继续使用,因此子类也是一个跟父类一样的泛型);

iii. 并且一旦使用了这种语法,那么子类定义中的Son和extends Father中的类型参数必须和定义父类时的类型参数名完全一样!!

a. 以下三种情况全部错误(全部发生编译报错):

必须全部使用和父类定义相同的类型参数名(T)!才行,这是Java语法的特殊规定;

4) 其实Java容器中很多类/接口都是通过类型参数传承来定义的:

i. 最典型的例子就是:public interface List extends Collection { ... }

ii. 虽然"如果A是B的父类,但Generic不是Generic"的父类,但"如果A是B的父类,那A一定是B的父类"!这是一定的;

iii. 因为类型参数传承的定义方式本身就是:Son extends Father,那Father一定是Son的父类咯!

6. 在使用泛型的时候可以不使用菱形语法指定实参,直接裸用类型名:

1) 例如:

i. 定义引用(对象)时裸用类名:ArrayList list = new ArrayList(); // 当然也可以写成ArrayList list = new ArrayList<>();

ii. 实现/继承:public class MyType extends MyGeneric { ... }

上面使用的类型或者接口在定义的时候都是泛型!!但是使用它们的时候忽略类型参数(都不用加菱形);

2) Java规定,一个泛型无论如何、在任何地方、不管如何使用,它永远都是泛型,因此这里既是你忽略类型实参它底层也是一个泛型,那么它的类型实参会是什么呢?既然我们没有显式指定,那么Java肯定会隐式为其指定一个类型实参吧?

3) 答案是肯定的,如果使用泛型的时候不指定类型实参,那么Java就会用该泛型的“原生类型“来作为类型实参传入,那么“原生类型“是什么呢?这里先不介绍,会在下一章的”泛型原理“里详细分解;但是我们这里可以先透露一下,Java集合的原生类型基本都是Object,因此像上面的ArrayList list = new ArrayList();写法其实传入的是Object类型实参,即ArrayList!

java参数传入的是一个类名_Java编程细节——泛型的定义(类、接口、对象)、使用、继承...相关推荐

  1. java 策略模式和工厂模式区别_Java编程细节——什么是策略模式

    策略模式应该是Java设计模式中最简单的一种模式, 它的核心思想是,一个类的行为可以在运行时动态改变,有不同的实现逻辑. 其实具体的说,它也是基于面向接口编程的思想,通过定义不同的实现类逻辑来做到的. ...

  2. python 参数类型的多态_【Python】面向对象:类与对象\封装\继承\多态

    六.Python面向对象--类与对象\封装\继承\多态 1.什么是面向对象编程 1.1 程序设计的范式:程序可控,易于理解 1.2 抽象并建立对象模型 1.3 程序是不同对象相互调用的逻辑.每个对象在 ...

  3. java参数传入泛型类型_Java 5.0 泛型之 使用泛型统一传入的参数类型

    Java 5.0 泛型之 使用泛型统一传入的参数类型 package Demo; // 使用泛型统一传入的参数类型 class Info28 { private T var; // 此类型由外部决定 ...

  4. java参数传入泛型类型_java泛型方法参数传递

    Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言). 如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这 ...

  5. java 参数传值的练习题及答案_java方法参数传递面试题三则

    传值还是传引用是Java中很基础的一个问题,也是笔试的时候经常被考察的一个问题,总结一下. 题目1: 写出以下程序的输出内容. public class Test { public static vo ...

  6. java 8流在另一个流_Java 8流– Java流

    java 8流在另一个流 Welcome to Java 8 Stream API tutorial. In the last few java 8 posts, we looked into Jav ...

  7. java 8流在另一个流_Java 8流图

    java 8流在另一个流 Java 8 Stream map function can be used to perform some operation on all of it's element ...

  8. java怎么给类中的私有变量赋值_Java核心技术笔记分享------第二章 类与对象

    对象与类 一.面向对象思想的概述 1>面向对象与面向过程: 二者都是一种思想,面向对象是相对于面向过程而言的.面向过程强调的是功能行为.面向对象,将功能封装进对象,强调具备了功能的对象. 面向对 ...

  9. java oop概念_JAVA OOP(一)——OOP概念,类与对象

    OOP概念,类与对象 OOP--面向对象编程 类与对象 类 对象 OOP--面向对象编程 首先,我们来举一个例子: 现在我要用用代码实现下列要求,定义一只猫,它的名字叫"小芳",年 ...

最新文章

  1. android 拼图课程设计,Flash拼图游戏制作课程设计报告
  2. Node.js 部署免费/自动续订 HTTPS
  3. adf开发_在EL表达式中引用ADF Faces组件
  4. PHP的rm指令,git rm 命令
  5. 教师节PSD分层海报设计模板 | 最好的海报,送给最好的老师们
  6. HDU 2065 红色病毒 指数型母函数+泰勒公式
  7. mysql联合索引测试
  8. 【收藏级教程】专业Finereport教程,帆软报表教程
  9. android黑科技系列——手机端破解神器MT的内购VIP功能破解教程
  10. u盘盘符不显示 win10_win10系统u盘不显示盘符的解决方法
  11. react后台管理项目
  12. oblog后台管理问题
  13. uc缓存分段视频合并
  14. QT教程:QT的基本了解
  15. errno ETIMEDOUT npm ERR! network request to https://registry.npmjs.
  16. Unity 年度总结:一款游戏的从0到1
  17. unity3D多点测量、多边形面积测量
  18. CIKM2020 | 最新9篇推荐系统相关论文
  19. win7一直安装并更新计算机,win7系统更新时一直正在等待安装重启不更新的恢复方案...
  20. 上汽集团进军网约车市场  滴滴的市场地位会被传统车企们挑战成功吗?

热门文章

  1. Web优化 --利用css sprites降低图片请求
  2. mysql创建定时器(event),查看定时器,打开定时器,设置定时器时间
  3. 闭包/Block当成函数参数实现回调
  4. JavaWeb重要知识点总结
  5. Android背景色渐变效果(shape,gradient) (转)
  6. 主流平台应用与游戏的编程语言/工具(图)
  7. win与linux渊源,微软与Linux从对立走向合作,WSL是如何诞生的
  8. leetcode374. 猜数字大小(二分法)
  9. leetcode1405. 最长快乐字符串(贪心算法)
  10. 单元测试 python_Python单元测试简介