文章目录
目录
零、概念
一、泛型的优点
1.1优点
1.2为什么要使用泛型
二、泛型使用与不使用的区别
1、泛型的没有使用会造成什么后果呢?
2.添加泛型的使用会发生什么效果呢?
【一、二】 知识点小结
关于包装类的延伸知识点
包装类
三、自定义泛型结构
3.1泛型类举个栗子
3.1.1 OrderTest类
3.2自定义泛型类的子类怎么处理?
3.3、在继承情况中使用泛型
3.4自定义泛型方法
3.4.1泛型⽅法说明: ⽅法也可以被泛型化,不管此时定义在其中的类是不是泛型类。 在泛型⽅法中可以定义泛型参数,此时,参数的类型就是传⼊数据的类型。 泛型⽅法在调⽤时候确定类型。
3.4.2泛型⽅法的格式
3.4.3、子类重写泛型方法
3.5、泛型类和泛型方法的使用情景
四、通配符的使用
4.1概念
4.2使用场景
4.3具体使用说明
总结:
泛型:
他是 JDK5 中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数
# 常见的泛型的类型表示
上面的 T 仅仅类似一个形参的作用,名字实际上是可以任意起的,但是我们写代码总该是要讲究可读性的。常见的参数通常有 :
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(表示Java 类,包括基本的类和我们自定义的类)
K - Key(表示键,比如Map中的key)
V - Value(表示值)
? - (表示不确定的java类型)
但是泛型的参数只能是类类型,不能是基本的数据类型,他的类型一定是自Object的
————————————————
原文链接:https://blog.csdn.net/bjweimengshu/article/details/117793971
1.提交了java的类型安全
泛型在很大程度上来提高了java的程序安全。例如在没有泛型的情况下,很容易将字符串 123 转成 Integer 类型的 123 亦或者 Integer 转成 String,而这样的错误是在编译期无法检测。而使用泛型,则能很好的避免这样的情况发生。
2.不需要烦人的强制类型转换
泛型之所以能够消除强制类型转换,那是因为程序员在开发的时候就已经明确了自己使用的具体类型,这不但提高了代码的可读性,同样增加了代码的健壮性。
3. 提高了代码的重用性
泛型的程序设计,意味着编写的代码可以被很多不同类型的对象所重用
1、解决元素存储的安全性问题,好⽐商品、药品标签,不会弄错。
2.解决获取数据元素时,需要类型强制转换的问题,好⽐不⽤每回拿商品、药品都要辨别。
2、Java泛型可以保证如果程序在编译时没有发出警告,运⾏时就不会产⽣ClassCastException异常。同时,代码更加简洁、健壮。
import org.junit.Test;
import java.util.ArrayList;
/**
* 泛型的使⽤
* 1.jdk5.0新增的特征
*/
public class GenericTest {
//在集合中使⽤泛型之前的情况:
@Test
public void test(){
ArrayList list = new ArrayList();
//需求:存放学⽣的成绩
list.add(78);
list.add(49);
list.add(72);
list.add(81);
list.add(89);
//问题⼀:类型不安全
// list.add("Tom");
for(Object score : list){
//问题⼆:强转时可能出现类型转化异常
int stuScore = (Integer)score;
System.out.println(stuScore);
}
}
}
那我们发现,没有添加泛型的时候呢,我们可以向list集合添加各种各样类型的数据,那么就会导致在数据类型转换的时候发生异常,那么我们添加泛型的好处也是很明显的了。
public class GenericTest {
//!在集合中使⽤泛型的情况:以ArrayList为例
@Test
public void test2(){
//注意点:泛型的类型必须是类,不能是基本数据类型。需要⽤到基本数据类型的位置,拿包装类替换
//看图例这⾥规定泛型是Integer,使⽤add⽅法的时候也是Integer
ArrayList list = new ArrayList();
list.add(78);
list.add(49);
list.add(72);
list.add(81);
list.add(89)
//编译时,就会进⾏类型检查,保证数据的安全
// list.add("Tom");
//⽅式⼀:
// for(Integer score :list){
// //避免了强转的操作
// int stuScore = score;
//
// System.out.println(stuScore);
// }
//⽅式⼆:
Iterator iterator = list.iterator();
while(iterator.hasNext()){
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
//在集合中使⽤泛型的情况:以HashMap为例
@Test
public void test3(){
// Map map = new HashMap();
//jdk7新特性:类型推断, 实例化的时候就可以不⽤写泛型,空即可
Map map = new HashMap<>();
map.put("Tom",87);
map.put("Tone",81);
map.put("Jack",64);
// map.put(123,"ABC");
//泛型的嵌套
Set> entry = map.entrySet();
Iterator> iterator = entry.iterator();
while(iterator.hasNext()){
Map.Entry e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + "----" + value);
}
}
}
使用了泛型,就可以达到很多方便开发的效果,可以实现泛型的嵌套,也不用担心数据转换异常问题,有错误编译期间就会报错。
经过知识总结归纳,到目前的泛型学习,有几个知识点需要注意:
① 泛型是在JDK1.5版本之后出现的,改写了集合框架中所有的接口和类,为他们提供泛型的支持,从⽽可以在声明集合变量、创建集合对象时传⼊类型实参。
②泛型的出现使集合类型安全
③需要注意的是,泛型的类型必须是类,不能是基本数据类型。需要⽤到基本数据类型的位置,拿包装类替换。
如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
每个基本数据类型都提供了一个包装类,使用对应的包装类对象,对对应类型的数据进行了封装,又提供相应的方法对其封装的数据可以进行一些操作。
包装类(基本概念和一些使用方法)_Vicali的博客-CSDN博客_什么是包装类
有三种结构:泛型类、泛型接口,泛型方法
注意:↓
1.泛型类可以有多个参数,
2.泛型不同的引⽤不能相互赋值。尽管在编译时ArrayList和ArrayList是两种类型,但是,在运⾏时只有⼀个ArrayList被加载到JVM中。
@Test public void test3(){ ArrayList
list1 = null; ArrayList list2 = new ArrayList (); //泛型不同的引⽤不能相互赋值。 //list1 = list2; Person p1 = null; Person p2 = null; p1 = p2; } 3.泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object(继承⽅⾯的区别)。经验:泛型要使⽤⼀路都⽤。要不⽤,⼀路都不要⽤。
4.jdk1.7,泛型的简化操作类型推断:ArrayList flist = new ArrayList<>();
5.泛型的指定中不能使⽤基本数据类型,可以使⽤包装类替换。
6.静态⽅法中不能使⽤类的泛型。因为泛型是创建对象的时候指定的,静态结构早于对象创建。
public static void show(T orderT){ // System.out.println(orderT); // }
但是泛型方法可以是静态方法!
1. 前提:订单名称和订单编号是确定的类型
2. 问题:以后再出现的属性,类型不能确定
3. 解决:使⽤泛型解决,在类名字后⾯添加, 这些字⺟常⽤的可以使⽤4. 使⽤的时候 在变量名字使⽤T
5. 继续为泛型类型添加setter和getter⽅法
6. 写好泛型⽅法进⾏测试
public class OrderTest {
String orderName;
int orderId;
//类的内部结构就可以使⽤类的泛型
T orderT;
public OrderTest(){
};
public OrderTest(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
//如下的三个⽅法都不是泛型⽅法
public T getOrderT(){
return orderT;
}
public void setOrderT(T orderT){
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
}
@Test
public void test(){
/**
* 如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
* 要求:如果⼤家定义了类是带泛型的,建议在实例化时要指明类的泛型。
*/
OrderTest order = new OrderTest();
order.setOrderT(123);
order.setOrderT("ABC");
//建议:实例化时指明类的泛型
OrderTest order1 = new OrderTest
("orderAA",1001,"order:AA");
order1.setOrderT("AA:hello");
}
使用类的泛型就可以在需要一些新增的属性的时候匹配到它。
那么就会有几种情况
第一种:SubOrder不是泛型类
public class SubOrder extends OrderTest
{ //SubOrder:不是泛型类 }
第二种:SubOrder1是泛型类
public class SubOrder1
extends OrderTest {//SubOrder1 :仍然是泛型类 }
⽗类有泛型,⼦类可以选择保留泛型也可以选择指定泛型类型:两种情况,了解⼀下
1. ⼦类不保留⽗类的泛型:按需实现
1. 没有类型擦除
2. 具体类型
2. ⼦类保留⽗类的泛型:泛型⼦类1. 全部保留
2. 部分保留
简单情况↓↓
//1.⼦类不保留⽗类的泛型
class Father {}
// 1)没有类型 擦除
class Son1 extends Father {// 等价于class Son extends Father
复杂情况↓↓
①不保留
父类没有类型,子类保留自己提供的
父类有类型,子类保留自己提供的
父类有,子类保留自己提供的和父类全部的一起保留
父类有类型,子类保留自己提供的和部分父类的
//1.⼦类不保留⽗类的泛型
class Father {}
// 1)没有类型 擦除
//⾃⼰提供两个
class Son extends Father {// 等价于class Son extends Father
结论:⼦类必须是“富⼆代”,⼦类除了指定或保留⽗类的泛型,还可以增加⾃⼰的泛型。
>=比第一代更多更强的思路。
3.4.1泛型⽅法说明:
⽅法也可以被泛型化,不管此时定义在其中的类是不是泛型类。
在泛型⽅法中可以定义泛型参数,此时,参数的类型就是传⼊数据的类型。
泛型⽅法在调⽤时候确定类型。
[访问权限] <泛型> 返回类型 ⽅法名([泛型标识参数名称]) 抛出的异常
例如:
public List ⽅法名(E[] arr) throws Exception{
//。。。。
}
所以,需要在返回值类型前⾯加泛型,编译器才理解这个E不是类,是泛型。↓↓
public class OrderTest {
/**
* 泛型⽅法:在⽅法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
* 换句话说,泛型⽅法所属的类是不是泛型类都没有关系。
*/
public List copyFromArrayToList(E[] arr){
ArrayList list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
}
那么,静态方法可以是泛型方法吗?
答:可以
原因:泛型参数是在调⽤⽅法时确定的。并⾮在实例化类时确定。
public static
List copyFromArrayToList(E[] arr){ //... }
测试类↓↓
public class GenericTest1 {
//测试泛型⽅法
@Test
public void test4(){
OrderTest order = new OrderTest<>();
Integer[] arr = new Integer[]{1,2,3,4};
//泛型⽅法在调⽤时,指明泛型参数的类型。
List list = order.copyFromArrayToList(arr);
System.out.println(list);
}
}
import java.util.ArrayList;
import java.util.List;
public class SubOrder extends OrderTest{ //SubOrder:不是泛型类
public static List copyFromArrayToList(E[] arr){//静态的泛型⽅法
ArrayList list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
}
* 1编写Dao类,实现增删改查方法
*2 编写Customer类,其实就是数据库中的Customer表
*3 编写Student类,其实就是数据库中的Student表
* 4编写StudentDao和CustomerDao类来操作各自对应的表(使用泛型实现操作对应的表)
* 5编写测试类
1↓
import java.util.List;
public class DAO { //表的共性操作的DAO
//添加⼀条记录
public void add(T t){
}
//删除⼀条记录
public boolean remove(int index){
return false;
}
//修改⼀条记录
public void update(int index,T t){
}
//查询⼀条记录
public T getIndex(int index){
return null;
}
//查询多条记录
public List getForList(int index){
return null;
}
2↓
public class Customer {
}
3↓
public class Student {
}
4.
public class CustomerDAO extends DAO{
}
public class StudentDAO extends DAO {//只能操作某⼀个表的DAO
}
5↓
import org.junit.Test;
import java.util.List;
public class DAOTest {
@Test
public void test(){
CustomerDAO dao1 = new CustomerDAO();
dao1.add(new Customer());
List list = dao1.getForList(10);
StudentDAO dao2 = new StudentDAO();
Student student = dao2.getIndex(1);
}
}
4.1概念
为了解决类型被限制死了不能动态根据实例来确定的缺点,引⼊了“通配符泛型”
例如使⽤通配泛型格式为 extends Collection>,“?”代表未知类型,这个类型是实现Collection接⼝。
比如这两个方法都是用来遍历List集合,只是泛型不同,使用通配符就可以合二为一。
public void show2(List list){
}
public void show(List
使⽤类型: 通配符:? ⼀个问号
* 通配符?后只允许出现⼀个边界。
* 泛型只存在于编译期中
* 通配符参考:Java之通配符_橘泽的博客-CSDN博客
只允许出现在引⽤中(普通变量引⽤、形参),⼀般是⽤作 extends 具体类型>或者
super 具体类型>。
允许在泛型类或泛型⽅法的{ }⾥还有泛型⽅法的形参上,配合占位符,甚⾄可以使⽤
? extends T或者? super T这种形式来⽤作引⽤。经常⽤于边界
-------------------------------------------------------------------------------------------------------------------------
不允许出现在泛型定义中(泛型类、泛型接⼝、泛型⽅法的< >⾥)
不允许(类上):class one extends Integer> { }
不允许出现在类定义时继承泛型类时的< >⾥。
不允许在泛型⽅法的显式类型说明使⽤通配符。
不允许在new泛型类的时候使⽤通配符,⽐如new ArrayList>()。↓↓↓
通配符这篇比较全面的解释Java通配符-详细篇--一通百通_万千青柳的博客-CSDN博客_通配符java
Collection> c = new ArrayList(); c.add(new Object()); // ❌ 编译时错误因为我们不知道c的元素类型,我们不能向其中添加对象。add⽅法 有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是⼀个未知类型的⼦类。 因为我们不知道那是什么类型,所以我们⽆法传任何东⻄进去。
1.使用泛型的好处集合类型安全,代码更健壮;
2.泛型标记符要认识,T->java类 E->集合元素 K->键 V->值 ?->不确定的java类型
3.泛型分为泛型类,泛型方法,泛型接口;这里面再细分就是
自定义泛型类->类定义了泛型的话,那么类的内部结构就可以使用类的泛型;
继承泛型类时的子类泛型 继承方式、使用方式等等...
泛型方法的格式,静态方法也可以是泛型方法,但是静态方法不能定义泛型
4.通配符? 上限通配符只能读,下限通配符只能写,又读又写不用通配符。
泛型的类型必须是类,不能是基本数据类型。需要⽤到基本数据类型的位置,拿包装类替换。