【JavaSE】泛型通关教程

简介: 文章目录1 泛型引入2 泛型讲解2.1 泛型的介绍2.2 泛型实例2.3 泛型使用细节3 自定义泛型类4 自定义泛型接口5 自定义泛型方法6 泛型的继承与通配写在最后

1 泛型引入

 我们来引入一个需求,在ArrayList集合中添加三个Dog对象,并遍历该集合,输出Dog对象的姓名。这点我们很容易做到,只需要在遍历的时候将Object对象向下转型为Dog就可以正常遍历了。但是,假如程序员在添加Dog对象时不小心添加了一只猫呢? 来看下面的代码:

import java.util.ArrayList;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class Generic0 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        Dog dog1 = new Dog("小黄");
        Dog dog2 = new Dog("小花");
        Cat cat = new Cat("猫猫");
        arrayList.add(dog1);
        arrayList.add(dog2);
        arrayList.add(cat);  // 不小心添加了一只猫
        // 遍历
        for (Object o :
                arrayList) {
            // 向下转型
            Dog dog = (Dog) o;
            System.out.println(dog.name);
        }
    }
}
class Dog{
    public String name;
    public Dog(String name) {
        this.name = name;
    }
}
class Cat{
    public String name;
    public Cat(String name) {
        this.name = name;
    }
}


🐱 传统方法可能遇到的问题:


不能对加入到集合的ArrayList中的数据类型进行约束(不安全);

遍历的时候,需要进行类型转换,在数据量大的情况下,对效率有影响。

而通过使用泛型,则可以很好的解决该类问题。

在创建 ArrayList 的时候,通过下面的语句使用泛型,限制元素的类型:


ArrayList<Dog> arrayList = new ArrayList<>();
1

则编译器就会对类型进行检查,避免了将Cat加入ArrayList的错误情况:


🐰 泛型的好处:


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

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

不再提示编译警告。

2 泛型讲解

2.1 泛型的介绍

🐱 简介:


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

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

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

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

class Person<E>{
    E element;  // E 表示 element 的数据类型,该数据类型在定义 Person 对象的时候指定,即在,编译期间,就确定E的类型
    public Person(E element){  // E 也可以是参数类型
        this.element = element;
    }
    public E method(){  // 返回类型为E
        return element;
    }
}

2.2 泛型实例

1.创建 3 个学生对象;

2.放入HashSet中,元素为Student;

3.通过遍历HashSet,将值放入到 HashMap 中,Key 为 String name(HashSet中的Student), Value 为学生对象;

4.使用两种方式遍历,HashMap。

import java.util.*;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class Generic2 {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<>();
        students.add(new Student("黄小黄", 20));
        students.add(new Student("祢豆子", 7));
        students.add(new Student("春卷儿", 19));
        HashMap<String, Student> hashMap = new HashMap<>();
        // 遍历 HashSet,并将值传入 HashMap
        Iterator<Student> studentIterator = students.iterator();
        while (studentIterator.hasNext()){
            Student s = studentIterator.next();
            hashMap.put(s.name, s);
        }
        // 遍历 HashMap
        System.out.println("=================== 方式一 ==================");
        Set<String> keySet = hashMap.keySet();
        for (String s :
                keySet) {
            System.out.println(s + "--->" + hashMap.get(s));
        }
        System.out.println("=================== 方式二 ==================");
        Set<Map.Entry<String, Student>> entrySet = hashMap.entrySet();
        for (Map.Entry es :
                entrySet) {
            System.out.println(es.getKey() + "--->" + es.getValue());
        }
    }
}
// 学生类
class Student{
    public String name;
    public int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}



2.3 泛型使用细节

给泛型指定数据类型时,必须是引用类型,不能是基本数据类型;



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

泛型的使用形式如下:



如果不使用泛型,默认是使用 Object类型。

3 自定义泛型类

🆔 基本语法:

class 类名<T, R...>{
  ...
}

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

使用泛型的数组,不能初始化, 因为数组在 new 时不能确定泛型的类型,无法确定开辟的空间;

静态方法中不能使用类的泛型, 因为静态是和类相关的,在类加载的时候,对象还没创建,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化;

泛型类的类型,是在创建对象时确定的;

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

4 自定义泛型接口

🆔 基本语法:

interface 接口名<T, R...>{
  ...
}
  1. 接口中,静态成员也不能使用泛型;
  2. 泛型接口的类型,在继承接口或者实现接口的时候确定;
  3. 没有指定类型,依然为Object;
  4. 在 jdk8 中,可以在接口中使用默认方法,该方法可以使用泛型。

5 自定义泛型方法

🆔 基本语法:

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

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


当泛型方法被调用时,类型就会确定;



public void f(E e){},修饰符后面没有 ,则 f 不是泛型方法,而是使用了泛型;


泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型。


6 泛型的继承与通配

泛型不具有继承性;


  1. :支持任意泛型类型;
  2. :支持A类以及A类的子类,规定了泛型的上限;
  3. :支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。

🐰 通配示例如下,具体见注释:

import java.util.List;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class Generic3 {
    // <?> 任意泛型
    public static void printCollection01(List<?> c){
        for (Object object:
             c) {
            System.out.println(object);
        }
    }
    // <? extends A> A表示上限,可以接受A或者A的子类
    public static void printCollection02(List<? extends A> c){
        for (Object object:
                c) {
            System.out.println(object);
        }
    }
    // <? super A> A表示下限,可以接受A以及A的父类
    public static void printCollection03(List<? super A> c){
        for (Object object:
                c) {
            System.out.println(object);
        }
    }
}
class C{}
class A extends C{}
class B extends A{}
相关文章
|
存储 Java
【JavaSE】基础笔记 - 类和对象(上)
【JavaSE】基础笔记 - 类和对象(上)
71 0
|
Java 编译器
【JavaSE】基础笔记 - 类和对象(下)
【JavaSE】基础笔记 - 类和对象(下)
62 0
|
Java 程序员
【JavaSE】Java基础语法(二十):多态
1. 多态的概述 什么是多态 同一个对象,在不同时刻表现出来的不同形态 多态的前提 要有继承或实现关系 要有方法的重写 要有父类引用指向子类对象
【JavaSE】Java基础语法(十五):继承
1. 继承的实现 继承的概念 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新 定义,以及追加属性和方法 实现继承的格式 继承通过extends实现 格式:class 子类 extends 父类 { } 举例:class Dog extends Animal { }
【JavaSE】Java基础语法(十八):接口
1. 接口的概述 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。 Java中接口存在的两个意义 用来定义规范 用来做功能的拓展
|
安全 Java 测试技术
java 泛型 万字详解(通俗易懂)
java 集合篇章——泛型 详解。
30020 2
|
安全 算法 Java
【JavaSE专栏19】谈谈泛型和枚举的那些事
【JavaSE专栏19】谈谈泛型和枚举的那些事
200 0
【JavaSE】Java基础语法(四十三):反射
概述: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(包括私有的);对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的); 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
【JavaSE】Java基础语法(三十一):可变参数
1. 可变参数 可变参数介绍 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了 方法的参数类型已经确定,个数不确定,我们可以使用可变参数
开心档-软件开发入门之Java 抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。