【技术积累】Java中的泛型【一】
泛型是什么
Java中的泛型是一种能够让用户在编写代码时避免使用明确的类型而进行类型参数化的机制。Java中的泛型可以让编程者在代码编写时不必关心具体类型,只用关心类型之间的关系和相互转换,从而在编写代码的过程中实现类型的复用。这使得代码更加简洁、可读性更高,并且可以提高代码的可维护性和可扩展性。
Java泛型可以在类、方法、接口、以及数组等多个地方使用,并且可以结合约束条件来限制类型参数的类型。例如,在定义一个泛型类时,可以使用<T>定义一个泛型类型参数,T可以代表任何具体类型,例如Integer、String、Map等。在使用泛型时,可以将具体类型传递给类型参数,然后在方法或者类中使用该类型参数,从而实现代码的类型自动化。
Java中的泛型还具有类型检查和类型擦除的特性。类型检查可以检查在编译时期是否使用了正确的类型,避免了在运行时期由于类型转换错误而产生的异常。而类型擦除则是Java泛型在实现时使用的一种技术,它会去掉泛型中的类型参数信息,并将其变为原始类型,在运行时也不会保留泛型的信息,从而实现Java泛型的运行时兼容性。
什么是类型参数?
public class MyClass<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
MyClass<Integer> intObj = new MyClass<>();
MyClass<String> strObj = new MyClass<>();
什么是类型擦除?
public class Pair<T, S> {
private T first;
private S second;
public Pair(T first, S second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public S getSecond() {
return second;
}
}
public class Pair {
private Object first;
private Object second;
public Pair(Object first, Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
}
什么是通配符类型?
Java中的通配符类型是一种泛型类型,用于表示未知类型的泛型参数。 通配符类型由问号(?)表示,其可以用作方法的参数类型、字段类型、局部变量类型等任何地方需要使用泛型类型的地方。
通配符类型有两种形式:无界通配符类型和有界通配符类型。
无界通配符类型是指使用符号 ? 表示未知类型,例如 List<?>。在使用无界通配符类型时,不能添加任何元素到集合中,因为这个集合的元素类型是未知的。但是,可以从集合中获取元素,并将其转换为 Object 类型。
有界通配符类型是指使用符号 ? extends 或 ? super,限制泛型参数的类型范围。例如,List<? extends Number> 表示泛型参数必须是 Number 类型或其子类型。而 List<? super Integer> 表示泛型参数必须是 Integer 类型或其父类型。在使用有界通配符类型时,可以添加元素到集合中,并能获取它们。
注意,通配符类型不能用于泛型类或泛型接口的定义,只能作为方法参数或返回类型的通用形式使用。
什么是泛型方法和泛型类
泛型方法和泛型类是Java中重要的概念,它们的作用是为了提高代码的可重用性和安全性。
泛型方法是在方法的声明中使用泛型类型,使得方法可以接受不同类型的参数,同时还可以指定返回值或方法体中使用的泛型类型。泛型方法通常有以下特点:
- 泛型方法可以在方法中定义自己的类型参数,也可以使用类定义的类型参数。
- 泛型方法可以接受任意类型的参数,即可以接受参数化类型,也可以接受普通类型。
- 泛型方法可以有多个类型参数,也可以没有类型参数。
- 泛型方法可以有泛型类型的返回值。
下面是一个使用泛型方法的例子:
public static <T> void printArray(T[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
在这个例子中,我们定义了一个名为 printArray 的泛型方法,它接受一个泛型数组作为参数,并且使用 for 循环遍历数组的每个元素,最后输出所有元素到控制台。
泛型类是在类的声明中使用泛型类型,使得类可以接受不同类型的参数,同时还可以指定类中使用的泛型类型。泛型类通常有以下特点:
- 泛型类可以在类名后面添加泛型类型参数。
- 泛型类可以在类中定义泛型类型的实例变量。
- 泛型类可以有泛型类型的构造方法。
- 泛型类可以有泛型类型的方法。
下面是一个使用泛型类的例子:
public class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public static void main(String[] args) {
Box<Integer> box = new Box<>(10);
System.out.println(box.getValue());
}
}
在这个例子中,我们定义了一个名为 Box 的泛型类,它有一个泛型类型参数 T,同时定义了一个名为 value 的实例变量,以及相应的 get 和 set 方法。在 main 方法中,我们创建了一个 Box 对象,并且使用泛型类型为 Integer 的参数,然后输出了这个对象的值到控制台。
总的来说,泛型方法和泛型类是Java中非常重要的概念,它们可以为我们提供更加灵活和安全的编程方式,同时也是提高代码可读性和可维护性的有效手段。
泛型类中是否可以继承泛型类
Java中泛型类可以继承泛型类,这一特性被称为泛型的继承或泛型的子类化。
在泛型类继承中,子类继承的父类可以是泛型类也可以是非泛型类。当子类继承的父类是泛型类时,子类可以继承父类的泛型类型;也可以在继承时指定自己的泛型类型。
下面是一个范例来展示Java中泛型类继承泛型类的用法:
public class Parent<T> {
// 泛型类型 T
private T data;
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
public class Child<T> extends Parent<T> {
// 继承泛型类 Parent<T>
}
public class Test {
public static void main(String[] args) {
Child<String> child = new Child<String>(); // 子类指定了泛型类型为 String
child.setData("Hello World");
System.out.println(child.getData()); // 输出结果为 "Hello World"
}
}
在上面的例子中,Child类继承了Parent类,由于Parent类是一个泛型类,所以Child类又继承了Parent类的泛型类型T。而在定义Child类时,也可以在继承Parent类时指定T的具体类型,如Child<String>,从而使Child类也成为具有泛型特性的类。
总结一下,Java中允许泛型类继承泛型类,子类也可以使用父类的泛型类型或为自己指定泛型类型。这个特性可以帮助开发者更好地管理和组织泛型类,能够提升代码的可重用性和可读性。
泛型方法中是否可以声明泛型类
Java中泛型方法可以声明泛型类,这样可以在方法中使用泛型类型参数,从而在方法中实现通用的操作。
除了声明泛型类,泛型方法还可以声明泛型方法参数、返回类型,以及利用泛型通配符进行类型转换等常用操作。
以下是一个简单的示例,展示了在泛型方法中声明泛型类的用法:
public class MyClass<T> {
public <E> void printElements(E[] elements) {
for (E element : elements) {
System.out.println(element.toString());
}
T obj = new T(); // 泛型类类型参数T在泛型方法中使用
}
}
public class Test {
public static void main(String[] args) {
Integer[] integers = {1, 2, 3, 4, 5};
String[] strings = {"Hello", "World"};
MyClass<Integer> myClass = new MyClass<>();
myClass.printElements(integers);
MyClass<String> myClass1 = new MyClass<>();
myClass1.printElements(strings);
}
}
在上述代码中,我们定义了一个泛型类 MyClass<T>,其中,又定义了一个名为 printElements 的泛型方法,该方法中使用了泛型类型参数 E[],并在方法中对数组元素进行遍历输出;同时,方法中也使用了泛型类型参数 T,在方法中初始化一个泛型类类型参数T的对象。
在Test类中,我们实例化了两个 MyClass 类,分别强制指定泛型类型参数为 Integer 类型和 String 类型,并通过执行各自的 printElements 方法来打印数组元素。
通过这种方式,Java中的泛型方法不仅支持泛型类型参数,也支持对泛型类(包括实例化泛型类对象)的操作,从而让我们可以实现更加通用的方法封装,提升代码的可读性和复用性。
为什么类型参数不能是原始类型
- 泛型的类型擦除机制
Java中的泛型是通过类型擦除机制实现的。泛型类和方法会在编译时通过擦除类型信息来去除泛型的影响,转换成原始类型。例如,List<String>和List<Integer>在编译后都会变成List<Object>。
原始类型与泛型类无法一起使用,这样会破坏Java 的类型安全。如果类型参数允许原始类型,那么在擦除类型信息之后,无法在运行时获得类型信息,这就导致了无法编写通用的泛型代码。
- 原始类型的限制
原始类型不能继承任何类,也无法实现任何接口。如果类型参数可以是原始类型,那么泛型类就无法利用Java强大的面向对象特性来实现更加复杂、灵活的结构。
- 自动类型转换问题
Java中自动类型转换和类型擦除机制可能会导致类型参数变为原始类型。例如,我们在泛型方法中将一个原始类型转换为一个泛型类型参数,当运行时擦除类型时,这个泛型类型变成了Object类型,而不是我们想要的类型参数。
综上所述,Java中为什么类型参数不能是原始类型,是因为这种做法会破坏Java的类型安全和面向对象特性,无法实现通用的泛型代码。
什么是限定通配符和无限定通配符?
限定通配符是Java中泛型的一个重要特性,用于指定泛型参数的上界或下界。
在Java中,泛型参数不仅可以指定具体的类型,还可以指定一个范围,即可以定义类型的上界或下界。限定通配符就是用来指定这个范围的符号。
限定通配符分为extends和super两种类型:
- extends限定通配符:用于指定泛型参数的上界。表示类型必须是指定类型或其子类。
示例:List<? extends Number> 表示泛型参数必须是Number或其子类,如Integer、Double等。
- super限定通配符:用于指定泛型参数的下界。表示类型必须是指定类型或其父类。
示例:List<? super Integer> 表示泛型参数必须是Integer或其父类,如Number、Object等。
限定通配符的作用是确保泛型参数的类型符合特定的条件,同时增加代码的可用性和可读性。
Java中的无限定通配符(Unbounded Wildcard)是指泛型参数没有任何限制,使用符号"?"来表示。
示例:List<?> 表示List中可以存放任何类型的对象,相当于是List<Object>的简化写法。
无限定通配符可以用于以下情况:
当泛型参数类型并不重要时,比如在方法中只需要对泛型参数进行处理而不需要知道具体类型。
当泛型类型的上界或下界无法确定时,比如在方法中需要接受不同类型的List对象,但是这些List对象的元素类型并不确定。
无限定通配符并不能直接调用参数的方法或者添加新的元素,因为其具体的类型是未知的,需要通过强制类型转换才能进行操作。
什么是类型边界
Java泛型中的类型边界(Type Bound)是指限制泛型类型参数的范围,使得参数只能是特定类或其子类,或者实现了特定接口的类或其实现类。
类型边界有两种形式:extends和super。extends用于限制类型参数的上界(Upper Bound),即指定参数只能是某一类或其子类的类型;super用于限制类型参数的下界(Lower Bound),即指定参数只能是某一类或其父类的类型。
//类型边界为Number及其子类
public class GenericClass<T extends Number> {
private T number;
public GenericClass(T number) {
this.number = number;
}
public T getNumber() {
return number;
}
}
GenericClass<Integer> intClass = new GenericClass<>(10);
GenericClass<Double> doubleClass = new GenericClass<>(3.14);
//类型边界为String及其父类
public class GenericClass<T super String> {
private T str;
public GenericClass(T str) {
this.str = str;
}
public T getString() {
return str;
}
}
GenericClass<Object> objClass = new GenericClass<>("Hello World");
GenericClass<CharSequence> charSeqClass = new GenericClass<>("Hello World");
什么是协变
Java泛型中的协变(Covariant)是指泛型类型参数的子类型关系能够被继承到泛型类的实例化类型中。也就是说,子类型的泛型类实例可以替代父类型的泛型类实例。
在Java中,协变类型只有在泛型参数是用作方法返回值类型时才可以生效。在这种情况下,如果泛型实例可以返回子类型对象,则该类型为协变类型。
public class Animal {}
public class Dog extends Animal {}
//泛型协变
public class GenericClass<T> {
public T getAnimal() {
return null;
}
}
GenericClass<Dog> dogClass = new GenericClass<>();
GenericClass<? extends Animal> animalClass = dogClass;
Animal animal = animalClass.getAnimal(); //协变成Animal类型
Dog dog = dogClass.getAnimal(); //无需转换,返回类型为Dog
什么是类型变量的继承
Java泛型中,类型变量的继承是指当一个泛型类型参数被声明在一个类中,并被另一个类继承时,继承后的子类可以直接使用该泛型类型参数。
具体来说,当一个类声明了泛型类型参数T,在另一个类中继承该类时,可以通过在子类中指定T的具体类型来使用其父类中声明的泛型类型。子类可以继承和使用其父类中的泛型类型,或者在实现接口时使用泛型类型。
public class ParentClass<T> {
T t;
public T getT() {
return t;
}
}
public class ChildClass<T> extends ParentClass<T> {
}
ChildClass<String> child = new ChildClass<>();
child.setT("Hello"); //继承父类中的泛型类型T
String s = child.getT(); //继承父类中的泛型类型T
//类实现接口时使用泛型类型
public interface MyInterface<T> {
public T getT();
}
public class MyClass<T> implements MyInterface<T> {
}
MyClass<String> myClass = new MyClass<>();
String s = myClass.getT(); //使用泛型类型T
【技术积累】Java中的泛型【一】的更多相关文章
- Java 中的泛型详解-Java编程思想
Java中的泛型参考了C++的模板,Java的界限是Java泛型的局限. 2.简单泛型 促成泛型出现最引人注目的一个原因就是为了创造容器类. 首先看一个只能持有单个对象的类,这个类可以明确指定其持有的 ...
- 夯实Java基础系列13:深入理解Java中的泛型
目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...
- Java中的泛型 (上) - 基本概念和原理
本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...
- [JavaCore]JAVA中的泛型
JAVA中的泛型 [更新总结] 泛型就是定义在类里面的一个类型,这个类型在编写类的时候是不确定的,而在初始化对象时,必须确定该类型:这个类型可以在一个在里定义多个:在一旦使用某种类型,在类方法中,那么 ...
- 【Java入门提高篇】Day14 Java中的泛型初探
泛型是一个很有意思也很重要的概念,本篇将简单介绍Java中的泛型特性,主要从以下角度讲解: 1.什么是泛型. 2.如何使用泛型. 3.泛型的好处. 1.什么是泛型? 泛型,字面意思便是参数化类型,平时 ...
- Java开发知识之Java中的泛型
Java开发知识之Java中的泛型 一丶简介什么是泛型. 泛型就是指泛指任何数据类型. 就是把数据类型用泛型替代了. 这样是可以的. 二丶Java中的泛型 Java中,所有类的父类都是Object类. ...
- Java中的泛型 --- Java 编程思想
前言 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...
- Java 中的泛型
泛型的一般意义: 泛型,又叫 参数多态或者类型参数多态.在强类型的编程语言中普遍作用是:加强编译时的类型安全(类型检查),以及减少类型转换的次数. Java 中的 泛型: 编译时进行 类型擦除 生成与 ...
- 第九节:详细讲解Java中的泛型,多线程,网络编程
前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...
- Java基础之Java中的泛型
1.为什么要使用泛型 这里我们俩看一段代码; List list = new ArrayList(); list.add("CSDN_SEU_Cavin"); list.add(1 ...
随机推荐
- Cisco模拟器配置DNS服务器遇到的问题
1.使用工具: Cisco-Packet-Tracer(7.0或8.0版本及以上) 2.问题: 原因:安装思科模拟器后进行中文汉化: 过程:配置DNS服务时无法进行域名操作: 解决: 更改为原来的语言 ...
- 手机号码归属地的自动查询.py(亲测有效)
import requests url = "http://m.ip138.com/sj.asp?mobile=" kv = {'user-agent':'Mozilla/5.0' ...
- Auto Photoshop StableDiffusion - 这是一款可以在 Photoshop 中使用 AI 智能 Automatic1111 进行插画、海报等设计的插件
简介 Auto Photoshop StableDiffusion - 这是一款可以在 Photoshop 中使用 AI 智能 Automatic1111 进行插画.海报等设计的插件,此插件可以是你在 ...
- $\mathcal{Friends\,\,Of\,--Mathic}$
- offsetX与offsetLeft
offsetX:鼠标指针距离当前绑定元素左侧距离,他并不是相对于带有定位的父盒子的x,y坐标, 记住了,很多博客都解释错了 offsetLeft,offsetTop 相对于最近的祖先定位元素.
- 快速使用ChatGpt Web Server
快速使用ChatGpt Web Server ChatGpt Web Server是使用Blazor Server模式部署的一个服务,所有的逻辑和代码执行都会在服务器执行,然后通过SignalR传输到 ...
- python入门教程之十五获取对象属性的几种方法
当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type()判断: >>> ...
- PHP利用 JSON 将XML转换为数组
在很多开发项目中,我们都会遇到将XML文件转换为数组使用,因此在本篇 PHP教程 中,UncleToo和大家一起学习 如何转换XML为数组 . 现在有一个uncletoo.xml的配置文件,格式如下: ...
- Linux操作系统网络模块
Linux操作系统的网络模块是负责网络通信的核心部分.它通过实现各种协议和算法,使得计算机能够在网络中进行数据交换和通信.网络模块主要包括以下几个方面的功能: (1)IP协议栈:负责处理网络层的数据包 ...
- If选择语句的用法
今天我们学习下If判断语句. 首先了解下它有几种用法: If单选择语句 If双选择语句 If多选择语句 我们一个一个用,每一个用法都给一个运用的过程演练一下. If单选择语句:我们很多需要判断一个东西 ...