问题背景

Java 集合有个缺点,把一个对象"丢进"集合里之后,集合就会"忘记"这个对象的数据类型,当再次取出该对象时 该对象的编译类型就变Object类型(其运行时类型没变),Java集合之所以被设计成这样,是因为集合的设计者不知道我们会用集合来保存什么类型的对象所以他们把集合设计成能保存任何类型的对象,只要求具有很好的通用性。但是,有可能使用过程中不符合预期,导致运行时报错。
import java.util.ArrayList;
import java.util.List; public class ProblemTest {
public static void main(String[] args) {
List persons = new ArrayList();
persons.add("李一桐");
persons.add("刘亦菲");
persons.add("鞠婧祎");
//不小心加入了一个int类型的数据
persons.add(10);
persons.forEach(person ->
System.out.println(((String) person).length())); //报错int转换不成String报错
}
}

解决:

  • 为要存储的元素/变量 灵活指定数据类型

1、泛型使用:

  • 作用:<泛型>指定集合存储元素的类型
语法:
  • 集合类<元素类型..> = new 集合类<>;
Set<String> persons = new HashSet<>();
Map<String, Integer> persons = new HashMap<>();

2、自定义泛型

语法:

    自定义类名<泛型形参>{ ... }

Iterator对象定义泛型:

Map定义泛型:

我们就是在类名的后面加上类型的替代符,比如上面的T,K,V。我们在使用的时候,就直接把这些T,K,V替换成对应的类型名称就好了。

/**
* @ClassName MyDefineClassInitTypeExample
* @projectName: object1
* @author: Zhangmingda
* @description: 自定义泛型测试
* date: 2021/4/11.
*/
public class MyDefineClassInitTypeExample {
private static class Student<T>{
private T type; public Student(T type) {
this.type = type;
} public T getType() {
return type;
}
}
public static void main(String[] args) {
Student<String> student = new Student<>("高中");
System.out.println(student.getType());//高中
Student<Integer> student1 = new Student<>(202101);
System.out.println(student1.getType());//202101
}
}

3、从泛型类派生子类

语法:

  自定义子类名<子类泛型形参> extends 父类名<泛型形参> {

    子类构造方法(数据类型|子类泛型形参 形参){

           super(形参)

               }

  }

  

当创建了带泛型申明的接口或父类之后,可以为该接口创建实现类或创建该类派生子类。子类必须指定父类的泛型具体类型,或者子类必须实现和父类相同的泛型
比如下面代码是不行的:

    private static class  ElementaryStudent extends Student<T>{
public ElementaryStudent(T type){
super(type);
}
}
但是我们可以指定具体父类泛型派生一个子类:

public class MyDefineClassInitTypeExample {
private static class Student<T>{
private T type; public Student(T type) {
this.type = type;
} public T getType() {
return type;
}
}
private static class ElementaryStudent extends Student<String>{
public ElementaryStudent(String type){
super(type);
}
} public static void main(String[] args) { ElementaryStudent elementaryStudent = new ElementaryStudent("小学");
System.out.println(elementaryStudent.getType()); //小学
}
}

定义一个子类的时候,无法指定父类泛型的具体类型:则

/**
* @ClassName MyDefineClassInitTypeExample
* @projectName: object1
* @author: Zhangmingda
* @description: 自定义泛型测试
* date: 2021/4/11.
*/
public class MyDefineClassInitTypeExample {
private static class Student<T>{
private T type; public Student(T type) {
this.type = type;
} public T getType() {
return type;
}
}
private static class ElementaryStudent<T> extends Student<T>{
public ElementaryStudent(T type){
super(type);
}
} public static void main(String[] args) { ElementaryStudent<Integer> elementaryStudent1 = new ElementaryStudent<>(202107);
System.out.println(elementaryStudent1.getType());
}
}
不存在泛型类:
  • 用一个支持泛型的类,创建不同类型的实例,他们还是同一个类的实现。
        ElementaryStudent<Integer> elementaryStudent1 = new ElementaryStudent<>(202107);
System.out.println(elementaryStudent1.getType());
ElementaryStudent<String> elementaryStudent2 = new ElementaryStudent<>("幼儿园");
System.out.println(elementaryStudent2.getType());
System.out.println(elementaryStudent1.getClass()); //class MyDefineClassInitTypeExample$ElementaryStudent
System.out.println(elementaryStudent2.getClass()); //class MyDefineClassInitTypeExample$ElementaryStudent
System.out.println(elementaryStudent.getClass().equals(elementaryStudent2.getClass()));//true

4、 泛型通配符?

问题:List<Object> 和 List<String> 什么关系,要求传入List<Object> 传入List<String> 行不行?

import java.util.ArrayList;
import java.util.List; public class ProblemTest {
private static void test(List<Object> list) {
for (Object o : list) {
System.out.println(o);
}
}
public static void main(String[] args) {
List<String> persons = new ArrayList<>();
persons.add("李 ");
persons.add("刘 ");
persons.add("祎");
test(persons); //不行,他们是同一类不同的实现,不是子类关系
}
}

解决:用通配符?替代泛型<Object>

import java.util.ArrayList;
import java.util.List; /**
* @ClassName wildcardExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/11.
*/
public class WildcardExample {
private static void test(List<?> list){
list.forEach(o -> System.out.println(o));
}
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("张三");
list.add("李四");
test(list);
/**
* 张三
* 李四
*/
}
}
上面的这个List,其中的?表示的就是一个通配符,表示可以匹配任何类型。在用的时候,通配符里面的元素,都是Object类型。

5、限定通配符适配范围

5.1 在List集合使用中限定示例代码:继承Animal类的子类都匹配

语法:

  <?extends 类名>

本例如果直接指定List<Animal>泛型,Dog和Cat虽然是Animal的子类,但是List<Dog> List<Cat> 和<List Animal>之间并不是子类关系,List<Dog> 或List<Cat>不能匹配<List Animal>。

import java.util.ArrayList;
import java.util.List; /**
* @ClassName wildcardExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/11.
*/
public class WildcardLimitExample {
private static class Animal{
public void say(){
System.out.println("动物叫了..........");
}
}
private static class Dog extends Animal{
@Override
public void say() {
System.out.println("I am Dog : 汪汪汪");
}
}
private static class Cat extends Animal{
@Override
public void say() {
System.out.println("I am Cat : 喵喵喵!!!");
}
}
public static void animalSay(List<? extends Animal> animals){
animals.forEach(animal -> animal.say());
}
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());
animalSay(animals);
/**
* I am Dog : 汪汪汪
* I am Cat : 喵喵喵!!!
*/
System.out.println("==================="); List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
animalSay(dogs);
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
animalSay(cats);
/**
* I am Dog : 汪汪汪
* I am Cat : 喵喵喵!!!
*/
}
}

5.2在类的定义过程中给泛型限定范围

语法:

 修饰符... class<T extends 父类名 [& 接口名] >

  • 形参T代表数据类型 extends 后面为T要继承或实现的接口

 如下类class CustomerNumber<T extends Number & Serializable> 的意义为:

在用该类创建对象时候如果指定泛型,指定传入构造方法的数据类型T必须是 继承了Number类并且实现了Serializable接口的数据类型。

import java.io.Serializable;
import java.text.NumberFormat; /**
* @ClassName WildcardLimitCustomerNumberExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/11.
*/
public class WildcardLimitCustomerNumberExample {
private static class CustomerNumber<T extends Number & Serializable>{
private T info; public CustomerNumber(T info) {
this.info = info;
} public T getInfo() {
return info;
}
} public static void main(String[] args) {
CustomerNumber<Integer> customerNumber = new CustomerNumber<>(1);
System.out.println(customerNumber.getInfo());
}
}

java数据类型:集合存储元素类型限制<泛型> ;自定义类指定泛型<T> 以及限制用法;派生子类泛型<T> super(泛型内参数); 泛型通配符?以及?限制用法的更多相关文章

  1. HashSet集合存储数据的结构和HashSet集合存储元素不重复的原理

    HashSet集合存储数据的结构 HashSet集合存储元素不重复的原理 //创建HashSet集合对象 Hashset<String> set = new HashSet<> ...

  2. JDBC数据类型、Java数据类型、标准sql类型

    本概述是从<JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference>这本书中摘引来的.JavaSoft ...

  3. JAVA数据类型中的char类型

    1.JAVA中,char占2字节,16位.可在存放汉字 2.char赋值 char a='a'; //任意单个字符,加单引号. char a='中';//任意单个中文字,加单引号. char a=11 ...

  4. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_06 Set集合_4_Set集合存储元素不重复的原理

    set集合元素为什么不能重复 集合重写了toString的方法所以打印是里面的内容 往里面存了三次abc 哈希表,初始容量是16个 set集合存储字符串的时候比较特殊 横着是数组,竖着就是链表结构.跟 ...

  5. 向集合中添加自定义类型--建议在自定义类型的时候要重写equals方法

    package com.bjpowernode.t01list; import java.util.ArrayList; /* * 向集合中添加自定义类型 */public class TestLis ...

  6. Java中集合删除元素时候关于ConcurrentModificationException的迷惑点

    下面的示例来至于阿里巴巴Java开发手册的集合处理部分的第7条: 运行如下代码,会发现正确运行. public static void hasNotExcption() { List<Strin ...

  7. Java操作Redis存储对象类型数据

    背景描述      关于JAVA去操作Redis时,如何存储一个对象的数据,大家是非常关心的问题,虽然官方提供了存储String,List,Set等等类型,但并不满足我们现在实际应用.存储一个对象是是 ...

  8. java按照集合中元素的属性进行排序示例代码

    public class Student { private String name; private int age; private int id; public Student() {  sup ...

  9. Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类

    Collection 之 Set 实现类: HashSet TreeSet 特点: 无序. 元素不可重复. (如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false ...

随机推荐

  1. Java培训班4个月有用吗?

    很多想学Java都会经历这样一个选择,是自学还是报班?自学的话需要一步步摸索,从无到有硬啃下来,时间没保证:可如果报班的话,目前市面上五花八门的培训机构又是鱼龙混杂,并且现在越来越多的培训机构宣称&q ...

  2. 【CTSC1999】【带权并查集 】月亮之眼

    Description 吉儿是一家古董店的老板娘,由于她经营有道,小店开得红红火火.昨天,吉儿无意之中得到了散落民间几百年的珍宝-月亮之眼.吉儿深知"月亮之眼"价值连城:它是由许多 ...

  3. HDU 6116 路径计数

    HDU 6116 路径计数 普通生成函数常用于处理组合问题,指数生成函数常用于处理排列问题. 考虑 对于 $ a $ 个 $ A $ 分为很多堆,这么分的方案数是 $ C_{a-1}^{i-1} $ ...

  4. 【R】如何将重复行转化为多列(一对一转化一对多)?

    目录 需求 方法一 方法二 需求 一个数据框一列或多列中有重复行,如何将它的重复行转化为多列?即本来两列一对一的关系,如何转化为一对多的关系?普通的spread函数实现较为麻烦. 示例数据如下: It ...

  5. Bebug与Release版本

    如果调试过程无调试信息,检查编译选项是否切换到了release下 比如Cfree5等编译器 ms为了方便调试才诞生了DEBUG版. 这也导致了MFC有两个功能一至但版本不同的类库,一个为DEBUG版, ...

  6. WINDOWS中使用svn

    官网:https://tortoisesvn.net/index.zh.html  (SVN安装包) 然后下载对应的64位安装包(语言包) 安装完后运行 可以存到D盘,新建一个文件夹存放 右键桌面会多 ...

  7. 【模板】二分图最大匹配(匈牙利算法)/洛谷P3386

    题目链接 https://www.luogu.com.cn/problem/P3386 题目大意 给定一个二分图,其左部点的个数为 \(n\),右部点的个数为 \(m\),边数为 \(e\),求其最大 ...

  8. 巩固javaweb第九天

    巩固内容: HTML <base> 元素 <base> 标签描述了基本的链接地址/链接目标,该标签作为HTML文档中所有的链接标签的默认链接: <head> < ...

  9. 日常Java 2021/9/23

    练习使用Math.random函数,以及JOptionPane.showMessageDialog(null,"字符串","Results",JOptionPa ...

  10. 理解ASP.NET Core - 模型绑定&验证(Model Binding and Validation)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 模型绑定 什么是模型绑定?简单说就是将HTTP请求参数绑定到程序方法入参上,该变量可以是简单类 ...