泛型

Generics:泛型,愿意指“无商标的”。

泛型,可以理解为“宽泛的数据类型”,就是将类型由原来的具体的类型泛化。

泛型在建立对象时不指定类中属性的具体类型,而是在声明及实例化对象时由外部指定。泛型可以提高数据安全性。

List中应用了泛型,在编译期对数据类型进行严格 检查,如果类型不匹配,编译无法通过。

示例 :

public interface List<E> extends Collection<E>

E:Element

T:Type


泛型的本质是为了参数化类型,即在不创建新类型的情况下,通过泛型指定的不同类型(类型形参),调用时传入具体的类型(类型实参)。

在使用泛型过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

泛型类

public class 泛型_类 {
public static void main(String[] args) {
车<Girl> v = new 车<Girl>();
v.add(new Girl());
// 不让上车
// v.add(new Boy());
}
}
abstract class Person {
}
class Boy extends Person {
}
class Girl extends Person {
}
class 车<T> {
public T add(T arg) {
System.out.println(arg.getClass());
return arg;
}
}

泛型接口

泛型接口与泛型类的定义及使用基本相同。

public interface Generator<T> {
public T getS();
}

泛型接口的两种使用方法(以ArrayList和Scanner为例):

import java.util.*;
interface IGenerics<E> {
void m(E e);
}
// 仿照ArrayList<E>,implements List<E>
// 实现类还是泛型
class MyList<E> implements IGenerics<E> {
@Override
public void m(E e) {
List<E> lst = new ArrayList<>();
}
}
// 仿Scanner类, implements Iterator<String>
// 直接指定泛型为String
class MyScanner implements IGenerics<String> {
@Override
public void m(String e) {
Scanner sc = new Scanner(System.in);
}
}
public class 泛型接口 {
public static void main(String[] args) {
// 定义时未指定类型,实例化需要指定类型
MyList<Integer> my1 = new MyList<>();
my1.m(1);
// 定义时已经指定类型,实例化不用指定
MyScanner my2 = new MyScanner();
my2.m("A");
}
}

泛型方法

泛型定义在修饰符和返回类型之间,在参数列表中使用泛型。

泛型方法主要针对参数有泛型(如集合)的场景,如果把下例的参数List改为数组则和Object没有太大区别

import java.util.*;
public class 泛型方法 {
public static <T> int find(List<T> lst, T a) {
int indexOf = -1;
if (lst != null) {
indexOf = lst.indexOf(a);
}
return indexOf;
}
public static void main(String[] args) {
int find = find(new ArrayList<String>(), "A");
System.out.println(find);
// 编译不通过:find(new ArrayList<Integer>(), "A");
}
}

说明:

泛型的参数类型只能是类类型,不能是简单类型。比如,<int>是不可使用的。
可以声明多个泛型参数类型,比如<T,P,Q…>,同时还可以嵌套泛型,例如:<List<String>>。
泛型的参数类型可以使用extends语句,例如<T extends superclass>。
使用extends语句将限制泛型参数的适用范围,只能是指定类型的子类。
|-例如:<T extends Collection> ,则表示该泛型参数的使用范围是所有实现了Collection接口的calss。如果传入<String>则程序编译出错。

示例【T extends Collection】:

import java.util.*;
public class 泛型extends {
public static <A extends Collection> void find(A arg1, int arg2) {
}
public static void main(String[] args) {
find(new ArrayList(), 5);
// 不是Collection的子类,编译不通过:
// find(new String(), 5);
}
}

<?>通配符

用于承接不同类型的泛型对象。

不知道使用什么类型接收数据时,使用?通配符。

此时只能接收数据,不能往该集合中存储数据。

import java.util.*;
public class 泛型_通配符 {
public static void main(String[] args) {
List<String> lst1 = new ArrayList<String>();
lst1.add("A");
List<Integer> lst2 = new ArrayList<Integer>();
lst2.add(1);
printList_T(lst1);
printList_T(lst2);
System.out.println("----------");
printList(lst1);
printList(lst2);
}
// 用常规泛型写,比较麻烦
private static <T> void printList_T(List<T> list) {
list.add(list.get(0));
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
}
// 用泛型通配符写简单
private static void printList(List<?> list) {
// ?不能写入,此处编译错误:list.add(list.get(0));
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
}
}

通配符界限

<? extends T>:是 “上界通配符(Upper Bounds Wildcards)”,泛型只能是T的子类/本身
<? super T>:是 “下界通配符(Lower Bounds Wildcards)”,泛型只能是T的父类/本身
参见:泛型通配符界限问题: https://www.cnblogs.com/tigerlion/p/10659515.html

定义三个类,Fruit->Apple->RedApple,声明ArrayList,有如下现象:

import java.util.*;
public class 泛型_通配符边界2 {
public static void main(String[] args) {
ArrayList<Apple> p1 = new ArrayList<Apple>();
// 【震惊!装得了苹果,装不了红苹果】
// ↓Type mismatch:
// cannot convert from ArrayList<RedApple> to ArrayList<Apple>
// ArrayList<Apple> p2 = new ArrayList<RedApple>();
}
}
class Fruit {
}
class Apple extends Fruit {
}
class RedApple extends Apple {
}

解决方案就是

【1.<? extends Fruit>,定类型继承关系的上界】
【2.<? super Apple>,确定类型继承关系的下界】

解决方案如下,照着注释看便是

package ah;
import java.util.*;
// 先定义三个类:水果、苹果、红苹果
class Fruit {
}
class Apple extends Fruit {
}
class RedApple extends Apple {
}
public class 泛型_通配符边界 {
public static void main(String[] args) {
ArrayList<Apple> p1 = new ArrayList<Apple>();
// 【震惊!装得了苹果,装不了红苹果】
// ↓Type mismatch:
// cannot convert from ArrayList<RedApple> to ArrayList<Apple>
// ArrayList<Apple> p2 = new ArrayList<RedApple>();
// 【1.<? extends Fruit>,定类型继承关系的上界:】
// 能装Apple以及一切Apple的派生类
ArrayList<? extends Apple> p3 = new ArrayList<Apple>();
p3 = new ArrayList<RedApple>();
// ↓上层的类不接受
// Type mismatch:
// cannot convert from ArrayList<Fruit> to ArrayList<? extends Apple>
// p3 = new ArrayList<Fruit>();
// 【然而,extends是只读的,不能写入】
// p3.add(new Apple());
if (p3.size() != 0) {
Apple apple = p3.get(0);
}
// 【2.<? super Apple>,确定类型继承关系的下界】
// 能装苹果以及一切苹果的基类
ArrayList<? super Apple> p4 = new ArrayList<Apple>();
p4 = new ArrayList<Fruit>();
p4 = new ArrayList<Apple>();
// Type mismatch:
// cannot convert from ArrayList<RedApple> to ArrayList<? super Apple>
// p4 = new ArrayList<RedApple>();
// 【可读可写,读出来的是Object类型】
p4.add(new RedApple());// 子类对象但是可以写进入,因为默认向上转型
Object object = p4.get(0);
System.out.println(object);
// 最后,其实JDK 7之后,后面的<>里什么都不用写
List<Apple> p2 = new ArrayList<>();
}
}

Java基础教程——泛型的更多相关文章

  1. Java基础教程:泛型基础

    Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...

  2. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  3. Java基础教程:面向对象编程[3]

    Java基础教程:面向对象编程[3] 内容大纲 基础编程 获取用户输入 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入.我们可以查看Ja ...

  4. 黑马程序员:Java基础总结----泛型(高级)

    黑马程序员:Java基础总结 泛型(高级)   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...

  5. Java基础教程(18)--继承

    一.继承的概念   继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...

  6. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  7. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

  8. Java基础教程(5)--变量

    一.变量 1.变量的定义   正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...

  9. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

随机推荐

  1. D. Maximum Distributed Tree 解析(思維、DFS、組合、貪心、DP)

    Codeforce 1401 D. Maximum Distributed Tree 解析(思維.DFS.組合.貪心.DP) 今天我們來看看CF1401D 題目連結 題目 直接看原題比較清楚,略. 前 ...

  2. Kerberos与票据的爱情故事

    0x01.Kerberos认证原理 Kerberos是一种认证机制.目的是通过密钥系统为客户端/服务器应用程序提供强大的可信任的第三方认证服务: 保护服务器防止错误的用户使用,同时保护它的用户使用正确 ...

  3. CentOS 7 搭建 Ceph 集群(nautilus 版本)

    搭建 Ceph 分布式集群( nautilus 版本 ) 一.服务器环境说明 主机名 角色 IP地址 ceph-admin ceph-deploy 192.168.92.21 ceph-node1 m ...

  4. GPRS DTU的工作原理和应用场景有哪些

    GPRS DTU是属于物联网无线数据终端设备的中一种,它主要是利用公用运营商的GPRS网络(又称G网)来为用户提供无线长距离数据传输的功能.一般都是采用的高性能工业级8/16/32位通信处理器和工业级 ...

  5. 【Luogu】P6232 [eJOI2019]挂架 题解

    这道题跟CSP/S 2019 D1T1有点像. 我们先来模拟一下 \(n=4\) 的情况, 不难得出,最后的衣架挂钩顺序: 下标: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 ...

  6. hdu3974 Assign the task线段树 dfs序

    题意: 无序的给编号为1-n的员工安排上下级, 操作一:给一个员工任务C,则该员工以及他的下级任务都更换为任务C 操作二:询问一个员工,返回他的任务   题解: 给一个员工任务,则他所在组都要改变,联 ...

  7. learning to Estimate 3D Hand Pose from Single RGB Images论文理解

    持续更新...... 概括:以往很多论文借助深度信息将2D上升到3D,这篇论文则是想要用网络训练代替深度数据(设备成本比较高),提高他的泛性,诠释了只要合成数据集足够大和网络足够强,我就可以不用深度信 ...

  8. 【JVM第五篇--运行时数据区】方法区

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.栈.堆.方法区的关系 虚拟机运行时的数据区如下所示: 即方法区是属于线程共享的内 ...

  9. C# 中大端序与小端序

    C# 中大端序与小端序 static void Main(string[] args) { uint value = 0x12345678; Console.WriteLine("原始字节序 ...

  10. exec系列函数详解

    execve替换进程映像(加载程序):execve系统调用,意味着代码段.数据段.堆栈段和PCB全部被替换.在UNIX中采用一种独特的方法,它将进程创建与加载一个新进程映像分离.这样的好处是有更多的余 ...