Java泛型的介绍和基本使用

什么是泛型

​ 泛型就是将类型参数化,比如定义了一个栈,你必须在定义之前声明这个栈中存放的数据的类型,是int也好是double或者其他的引用数据类型也好,定义好了之后这个栈就无法用来存放其他类型的数据。如果这时候我们想要使用这个栈来存放String(字符串类型)的数据就需要重写一遍代码,并且把数据类型改成String,可以说是代码重复性极高。

​ 类型参数化就可以很好的解决这个问题,我们在定义栈的时候,只需要给一个形参,在使用的时候将类型作为参数传递进去就可以使用这个栈来存放不同类型的数据了。

​ 泛型可以使用在接口,方法,和类里面,分别被称为泛型接口,泛型方法

java中的泛型标识符

下表是规范,用来增强代码的可读性,并非必须使用例如在下面的代码中使用了abc照样可以编译运行,不过可读性差,而且不规范。

下面的例子具体不用弄懂,下面会讲解,只需要知道abc和**?**在这里是通配符就好

public static <abc> void printList(List<? extends abc> list) {for (abc element : list) {System.out.println(element);}
}
标记符含义
EElement (在集合中使用,因为集合中存放的是元素)
TType(Java 类)
KKey(键)
VValue(值)
NNumber(数值类型)
可以表示任意类型(或者用来表示未知类型)

有限制的通配符

上限通配符-extends

这些所谓的上和下其实是描述在一个继承关系中的上下关系,对于一个类来说,它的父类的方向就是上,而子类的方向就是下。

所以这里的"上限"通配符的“上限”指的是,一个确定的父类,或者一个确定的接口来进行限制,该通配符表示的类型都是该父类的子类(确定的接口的实现类),或者子类的子类(继承关系在这个确定的父类以下的子类或者接口的实现类)

举个栗子
public class Add<T extends Number>{private T num;Add(T num){this.num = num;}
}

怎么使用呢?

正确调用
Add<Double> a = new Add<>(1.1);//正确
Add<Integer> i = new Add<>(3);//正确
错误调用
Add<String> s = new Add<>("1.1");//错误

通过这个例子我们应该就比较好理解了,Double和Integer都是Number类的子类,所以可以代替“T extends Number”中的T,而String不在Number的继承链中所以编译会报错。

在这里插入图片描述

虚线下面的类,确定的接口确定的父类就是上限通配符可以表示的类。

下限通配符-super

​ 下限通配符也是一种对泛型类型的限制,这里的“下限”指的是继承关系中的类型的下界。

再来一个栗子

这是一个泛型方法

    // 泛型方法接受 Number 及其父类的参数static void Generic(List<? super Number> list) {// 方法体}

方法调用

先看一个错误的示例

    List<Integer> list = new ArrayList<>();Generic(list);

下面都是正确的示例

List<Number> list = new ArrayList<>();
Generic(list);
List<Object> list = new ArrayList<>();
Generic(list);

​ OK从这个例子我们应该很明白啦,List<? super Number> list的尖括号中的数据类型必须是Number及其父类。

多重限定

用来限定类型,表示指定的类型参数必须是多个指定类或指定接口的子类。

public class GenericClass<T extends ClassA & InterfaceB & InterfaceC> {/***方法和属性*/
}
//表示T必须是ClassA的子类或者子类的子类并且实现了InterfaceB和InterfaceC接口,或者实现了接口的类的继承类

通过类型参数的限定,可以在泛型类或方法中对类型进行更精确的控制和约束,以提高代码的类型安全性和灵活性。。

好现在我们已经知道了泛型的常用的标识符了,现在我们来了解下泛型的三种应用

泛型类

单元泛型类

class Singl<T>{         // 这里的标识符可以随意命名,T是type的简称  private T var ;     public T getVar(){ return var ;  }  public void setVar(T var){  this.var = var ;  }  
}  
public class Generics{  public static void main(String args[]){  Singl<String> p = new Singl<String>() ;     // 里面的var类型为String类型  p.setVar("it is love") ;                            // 设置字符串  System.out.println(p.getVar().length()) ;   // 取得字符串的长度  }  
}

多元泛型类

class Multal<K,V>{       // 这里指定了两个泛型类型 K和V private K key ;    		//K表示Key,V表示Valueprivate V value ;  public K getKey(){  return this.key ;  }  public V getValue(){  return this.value ;  }  public void setKey(K key){  this.key = key ;  }  public void setValue(V value){  this.value = value ;  }  
} 
public class GenericsClass{  public static void main(String args[]){  Multal<String,Integer> t  ;        // 定义两个泛型类型的对象  t = new Multal<String,Integer>() ;       // 里面的key为String,value为Integer  t.setKey("我爱罗") ;        // 设置第一个内容  t.setValue(20) ;            // 设置第二个内容  System.out.print("姓名;" + t.getKey()) ;      // 取得信息  System.out.print(",年龄;" + t.getValue()) ;       // 取得信息  }  
}

语法:定义泛型类

class:类名<泛型标识1,泛型标识2,泛型标识3.....>{	private 泛型标识1 变量名;private 泛型标识2 变量名;
}

从泛型类派生子类

派生子类有两种情况:

  • 子类(如果子类也是泛型类)与父类的类型保持一致(泛型标识保持一致),如果父类没有指明泛型类型,则按Object进行处理
  • 子类不是泛型类时,父类的泛型类型必须指明 例如,如果父类没有指明,则按照Object操作

子类也是泛型类

示例一:单一类型参数的泛型类

如果子类也是泛型类,子类的泛型标识必须和父类保持一致

// 定义一个泛型类
class GenericClass<T> {private T value;public GenericClass(T value) {this.value = value;}public T getValue() {return value;}
}// 从泛型类派生子类,子类也是泛型类
class SubGenericClass<U> extends GenericClass<U> {public SubGenericClass(U value) {super(value);}public void displayValue() {System.out.println("Value: " + getValue());}
}// 使用示例
public class Main {public static void main(String[] args) {SubGenericClass<String> stringInstance = new SubGenericClass<>("Hello, Generics!");stringInstance.displayValue(); // 输出: Value: Hello, Generics!SubGenericClass<Integer> integerInstance = new SubGenericClass<>(123);integerInstance.displayValue(); // 输出: Value: 123}
}
示例 2:多个类型参数的泛型类
// 定义一个带有多个类型参数的泛型类
class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() {return key;}public V getValue() {return value;}
}// 从泛型类派生子类,子类也是泛型类
class ExtendedPair<K, V> extends Pair<K, V> {public ExtendedPair(K key, V value) {super(key, value);}public void display() {System.out.println("Key: " + getKey() + ", Value: " + getValue());}
}// 使用示例
public class Main {public static void main(String[] args) {ExtendedPair<String, Integer> pair = new ExtendedPair<>("Age", 30);pair.display(); // 输出: Key: Age, Value: 30ExtendedPair<Double, String> anotherPair = new ExtendedPair<>(3.14, "Pi");anotherPair.display(); // 输出: Key: 3.14, Value: Pi}
}

子类不是泛型类

定义一个泛型类

子类不是泛型类时,父类的泛型类型必须指明

// 定义一个泛型类
class GenericClass<T> {private T value;public GenericClass(T value) {this.value = value;}public T getValue() {return value;}
}
从泛型类派生的子类
// 从泛型类派生子类
class StringGenericClass extends GenericClass<String> {public StringGenericClass(String value) {super(value);}public void printValue() {System.out.println("Value: " + getValue());}
}
调用子类方法
public class Main {public static void main(String[] args) {StringGenericClass stringInstance = new StringGenericClass("Hello, Generics!");stringInstance.printValue(); // 输出: Value: Hello, Generics!}
}
带多个类型参数的泛型类
// 定义一个带有多个类型参数的泛型类
class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() {return key;}public V getValue() {return value;}
}// 从泛型类派生子类
class StringIntegerPair extends Pair<String, Integer> {public StringIntegerPair(String key, Integer value) {super(key, value);}public void display() {System.out.println("Key: " + getKey() + ", Value: " + getValue());}
}// 使用示例
public class Main {public static void main(String[] args) {StringIntegerPair pair = new StringIntegerPair("Age", 30);pair.display(); // 输出: Key: Age, Value: 30}
}

泛型接口

泛型接口语法

interface 接口名 <泛型标识1...>{泛型标识1 方法名(泛型标识1 变量名)}

泛型接口的使用情况(2种)

  • 实现类不是泛型

    • 接口类型必须明确,如果接口类型不明确,值实现类按Object处理
  • 实现类是泛型

实现类为泛型类

GenericInterface 是一个泛型接口,GenericClass 是一个泛型类,继承了这个接口。GenericClass 可以接受不同类型的参数。

// 定义一个泛型接口
interface GenericInterface<T> {void display(T value);
}// 实现泛型接口的泛型类
class GenericClass<U> implements GenericInterface<U> {@Overridepublic void display(U value) {System.out.println("Value: " + value);}
}// 使用示例
public class Main {public static void main(String[] args) {GenericClass<String> stringInstance = new GenericClass<>();stringInstance.display("Hello, Generics!"); // 输出: Value: Hello, Generics!GenericClass<Integer> integerInstance = new GenericClass<>();integerInstance.display(123); // 输出: Value: 123}
}

实现类为普通类

ConcreteClass 是一个普通类,它实现了泛型接口 GenericInterface,并将类型参数指定为 String。

// 定义一个泛型接口
interface GenericInterface<T> {void display(T value);
}// 实现泛型接口的普通类
class ConcreteClass implements GenericInterface<String> {@Overridepublic void display(String value) {System.out.println("Value: " + value);}
}// 使用示例
public class Main {public static void main(String[] args) {ConcreteClass concreteInstance = new ConcreteClass();concreteInstance.display("Hello, Generics!"); // 输出: Value: Hello, Generics!}
}

泛型方法

简单的泛型方法

public class GenericMethodExample {// 定义一个泛型方法public <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 使用泛型方法打印字符串数组String[] stringArray = {"Hello", "Generics", "!"};example.printArray(stringArray); // 输出: Hello, Generics, !// 使用泛型方法打印整数数组Integer[] intArray = {1, 2, 3, 4, 5};example.printArray(intArray); // 输出: 1, 2, 3, 4, 5}
}

带有多个类型参数的泛型方法

public class PairUtil {// 定义一个带有多个类型参数的泛型方法public static <K, V> void printPair(K key, V value) {System.out.println("Key: " + key + ", Value: " + value);}public static void main(String[] args) {// 使用泛型方法打印键值对printPair("Name", "Alice"); // 输出: Key: Name, Value: AliceprintPair(1, 100);           // 输出: Key: 1, Value: 100}
}

泛型方法,是在调用方法的时候指明泛型的具体类型。重点看下泛型的方法(图参考自:https://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html)

  • 定义泛型方法语法格式

在这里插入图片描述

  • 调用泛型方法语法格式

在这里插入图片描述

说明一下,定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。

Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。

Class 的基本概念

这里着重讲一下“Class” 的含义

  • Class 是一个表示某个类的对象,T 是这个类的类型参数。
  • 每个类在 Java 中都有一个对应的 Class 对象,这个对象包含了该类的结构信息,如字段、方法、构造函数等。

如何获取 Class 对象

  • 使用 ClassName.class
Class<String> stringClass = String.class;
  • 使用 getClass() 方法
String str = "Hello";
Class<?> stringClass = str.getClass();
  • 使用 Class.forName()
try {Class<?> stringClass = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {e.printStackTrace();
}

以下示例展示了如何使用 Class 来获取类的信息:

public class ClassExample {public static void main(String[] args) {// 获取 String 类的 Class 对象Class<String> stringClass = String.class;// 打印类的信息System.out.println("Class Name: " + stringClass.getName());System.out.println("Simple Name: " + stringClass.getSimpleName());System.out.println("Is Array: " + stringClass.isArray());System.out.println("Is Interface: " + stringClass.isInterface());System.out.println("Is Primitive: " + stringClass.isPrimitive());// 获取父类信息Class<?> superClass = stringClass.getSuperclass();System.out.println("Superclass: " + superClass.getName());// 获取实现的接口Class<?>[] interfaces = stringClass.getInterfaces();System.out.println("Interfaces:");for (Class<?> iface : interfaces) {System.out.println(" - " + iface.getName());}}
}

注意事项

Class 是 Java 反射机制中的一个重要组成部分,能够让程序在运行时与类进行交互,获取类的结构信息,极大地增强了 Java 的灵活性和动态性。通过理解 Class,开发者可以更有效地利用反射和泛型编程。

使用泛型来实现栈

泛型栈的定义

public class Stack<E> {private E[] arr = (E[]) new Object[10];//E[] arr = new E[10];是不允许的private int flag = 0;public void add(E x) {if(flag == arr.length ) {E[] arrnew = (E[]) new Object[arr.length * 2];for(int i = 0;i < arr.length;i++) {arrnew[i] = arr[i];}arr = arrnew;}arr[flag] = x;flag++;}public E get() {if(flag==0) {return null;}else {E x = arr[flag--];return x;}}
}

泛型栈的调用

public class Demo1 {public int x;public Demo1(int x) {this.x = x;}@Overridepublic String toString() {return "Demo1 [x=" + x + "]";}
}
public class Test {public static void main(String[] args) {Stack<Demo1> xx = new Stack<>();for(int i = 0;i < 24;i++) {xx.add(new Demo1(i));}for(int i = 0;i < 24;i++) {System.out.println(xx.get());}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3268402.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Codeforces 903 div3 A-F

A 题目分析 数据范围很小&#xff0c;暴力枚举即可&#xff0c;然后给字符串x的长度设置一个上限&#xff0c;我设了50&#xff0c;因为n*m<25&#xff0c;多一倍够用了 C代码 #include<iostream> using namespace std; void solve(){int n,m;string x,s;cin>>…

基于RS485的Modbus协议

RS485&#xff1a;用来传输数据&#xff0c;RS485是一种差分传输的串行通信标准&#xff0c;以其强大的抗干扰能力、长距离传输和多点通信能力&#xff0c;在工业控制领域得到广泛应用。RS485使用一对差分信号线&#xff08;A和B&#xff09;来传输数据&#xff0c;差分信号能有…

eclipse ui bug

eclipse ui bug界面缺陷&#xff0c;可能项目过多&#xff0c;特别maven项目过多&#xff0c;下载&#xff0c;自动编译&#xff0c;加载更新界面异常 所有窗口死活Restore不回去了 1&#xff09;尝试创建项目&#xff0c;还原界面&#xff0c;失败 2&#xff09;关闭所有窗口&…

Django学习(二)

get请求 练习&#xff1a; views.py def test_method(request):if request.method GET:print(request.GET)# 如果链接中没有参数a会报错print(request.GET[a])# 使用这个方法&#xff0c;当查询不到参数时&#xff0c;不会报错而是返回你设置的值print(request.GET.get(c,n…

winrar安装好后,鼠标右键没有弹出解压的选项

本来安装挺好的&#xff0c;可以正常使用&#xff0c;有天我把winrar相关的文件挪了个位置&#xff0c;就不能正常使用了。 然后我去应用里面找&#xff0c;找到应用标识了&#xff0c;但是找不到对应的文件夹&#xff08;因为我挪到另外一个文件夹里了&#xff09;。 于是我找…

语言转文字

因为工作原因需要将语音转化为文字&#xff0c;经常搜索终于找到一个免费的好用工具&#xff0c;记录下使用方法 安装Whisper 搜索Colaboratory 右上方链接服务 执行 !pip install githttps://github.com/openai/whisper.git !sudo apt update && sudo apt install f…

Android 软键盘挡住输入框

Android原生输入法软键盘挡住输入框,网上各种解法,但不起效。 输入框都是被挡住了,第二张图的小点,实际就是输入法的光标。 解法: packages\inputmethods\LatinIME\java\res\values-land config.xml <!-- <fraction name="config_min_keyboard_height"&g…

pikachu靶场之目录遍历、敏感信息泄露

一、目录遍历 漏洞概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量&#xff0c;从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时&#xff0c;便会将请求的这个文件的值(比如文件名称)传递到后台&#xff0c;后台再执行其对应的文件。 在这个过…

如何评价估计量的好坏

目录 三大方法 概念 无偏性 如何计算估计量的无偏性&#xff1f; 步骤 有效性 有效性在不同类型的数据分析中如何评估&#xff1f; 步骤 一致性 一致性原则在实际应用中的挑战有哪些&#xff1f; 挑战 在大样本情况下&#xff0c;如何准确测量估计量的一致性&#xf…

AcWing-差分矩阵

insert函数影响范围&#xff0c;在b差分数组这样操作影响到是a里面的&#xff0c;所以下图的矩阵表示的是a数组 b[x1][y1]c;会导致a里面仅绿色范围的a[i][j]c b[x1][y21]-c;会导致a里面仅黄色范围的a[i][j]-c b[x21][y1]-c;会导致a里面仅蓝色范围的a[i][j]-c b[x21][y21]c;会导…

SQL Server 设置端口号:详细步骤与注意事项

目录 一、了解SQL Server端口号的基础知识 1.1 默认端口号 1.2 静态端口与动态端口 二、使用SQL Server配置管理器设置端口号 2.1 打开SQL Server配置管理器 2.2 定位到SQL Server网络配置 2.3 修改TCP/IP属性 2.4 重启SQL Server服务 三、注意事项 3.1 防火墙设置 3…

数据结构与算法-归并排序

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、归并排…

MySQL笔记3——高级数据查询语句DQL

多表联查 多表联查可以通过连接运算实现&#xff0c;即将多张表通过主外键关系关联在一起进行查询。下图提供了多表联查 时用到的数据库表之间的关系。 等值查询和非等值查询 非等值查询&#xff1a;SELECT * FROM 表1&#xff0c;表2 等值查询&#xff1a;SELECT * FROM 表…

Oracle对比两表数据的不一致

MINUS 基本语法如下 [SQL 语句 1] MINUS [SQL 语句 2];举个例子&#xff1a; select 1 from dual minus select 2 from dual--运行结果 1-------------------------------- select 2 from dual minus select 1 from dual--运行结果 2所以&#xff0c;如果想找所有不一致的&a…

Codeforces Round 962 (Div. 3)

链接 C题&#xff1a; 思路&#xff1a; 直接暴力求每个字母的前缀和&#xff0c;对于区间l&#xff0c;r的最小操作就是区间不同数的一半&#xff0c;因为可以把一个数变成另一个不一样的数&#xff0c;一下抵消两个。 #include<bits/stdc.h> using namespace std; //…

苹果CMS V10萌芽采集插件Pro v10.7.3

苹果CMS V10萌芽采集插件Pro v10.7.3 插件下载:萌芽采集插件Pro v10.7.3.zip 使用说明: 将addons文件和static文件放到你苹果cms程序的根目录并覆盖&#xff0c; 在登录后台在应用-应用市场启用。http://你的域名/admin.php/admin/mycj/union.html

等保测评练习卷19

等级保护初级测评师试题19 姓名&#xff1a; 成绩&#xff1a; 判断题&#xff08;10110分&#xff09; 1.为了有效处理等级保护对象运行过程中可能发生的重大安全事件&#xff0c;需要在统一的框架下制定针对不同安全事件的应急预…

FPGA开发——呼吸灯的设计

一、原理 呼吸灯的原理主要基于‌PWM&#xff08;脉冲宽度调制&#xff09;技术&#xff0c;通过控制LED灯的占空比来实现亮度的逐渐变化。这种技术通过调整PWM信号的占空比&#xff0c;即高电平在一个周期内所占的比例&#xff0c;来控制LED灯的亮度。当占空比从0%逐渐变化到1…

java计算机毕设课设—记账管理系统(附源码和安装视频)

这是什么系统&#xff1f; java计算机毕设课设—记账管理系统&#xff08;附源码和安装视频&#xff09; 记账管理系统主要用于财务人员可以从账务中判断公司的发展方向。对个人和家庭而言&#xff0c;通过记账可以制定日后的 消费计划&#xff0c;这样才能为理财划出清晰合理…

C++初学者指南-6.函数对象--lambdas(基础)

C初学者指南-6.函数对象–lambdas(基础) 文章目录 C初学者指南-6.函数对象--lambdas(基础)提醒:函数类和对象Lambdas变量捕获保存闭包通用Lambdas (C14)广义捕获 (C14)相关内容 幻灯片 提醒:函数类和对象 类至少提供一个operator () (…) {…} 函数能像一个函数一样被调用可以…