首页 > 编程语言 >java泛型机制(基础知识总结篇)

java泛型机制(基础知识总结篇)

时间:2022-11-28 20:46:10浏览次数:40  
标签:Massages java void 基础知识 content 泛型 public Massage

  • 泛型概述

  • 泛型使用的必要性

  • 泛型类

  • 泛型接口

  • 泛型对象引用传递的解决方案

  • 泛型方法

  • 泛型的简单应用
    ---本文中将介绍泛型的基础知识以及简单应用,后面还计划学泛型的擦除机制以及在集合和反射机制中的应用

泛型的概述

泛型,字面上理解就是广泛的数据类型。其实就是将数据类型进行参数化,可以达到进一步的代码复用和使得程序更安全的目的

  • 泛型的基本定义
    泛型的特点:在声明一个变量或者属性的时候不设置其数据类型,而是在指定结构使用的时候进行动态的配置。使用泛型解决了强制类型转化的设计缺陷

泛型的必要性

在生活中信息的发送是并不可少的,但信息表达的方式也是不尽相同的。怎样实现代码复用得接收不同类型的消息显得很重要

不使用泛型的设计

//用于接收不同类型的消息
class Massage{
	private Object content;//用Object接收所以类型的消息
	public Massage(Object content){
		setContent(content);
	}
	public Object getContent(){
		return content;
	}
	public void setContent(Object content){
		this.content=content;
	}
	public void sentMassage(){
		System.out.println(content);
	}
}


public class MassageTest{
	public static void main(String[]args){
		Massage ma=new Massage("你今天有什么计划吗?");
		Massage me=new Massage(98.3);
		ma.sentMassage();
		me.sentMassage();
		//String str=(String)me.getContent();//此处ClassCastException(失误操作)
		//str.split();
		
		
	}
}
output:
你今天有什么计划吗?
98.3
//Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
        at MassageTest.main(MassageTest.java:25)

该程序用Object类作为所以类的父类进行接收所以的类型的数据,可以实现相应的功能,没有一点问题

但一般我们得到相应的数据之后,一般会做相应的一些处理,如程序中的注释部分,其中一般会涉及向下转型(用于调用子类特有的方法)向下转型如果我们操作失误,将可能会发生ClassCastException异常更重要的是这种异常为运行时异常,在编译期间不会暴露,而在我们的运行期间才会暴露,这给我们的程序带来了极大的安全隐患

而泛型的使用可以从根源上解决这个问题

为了解决这个问题,我们可以将这个Massage类设计成泛型类 由此我们引入泛型类

泛型类

泛型类在进行对象的实例化的时候,指定该泛型类所携带的泛型的具体类型
格式:
类名称<具体类> 对象名称= new 类名称<具体类>();
在jdk1.7时对该格式进行了简化:
类名称<具体类> 对象名称= new 类名称<>();(好像也称为钻石表达式)

泛型类实现后面同样的代码

//用于接收不同类型的消息
class Massage<T>{//标识为一个泛型类,T该泛型的类型
	private T content;//此处类型由外部指定
	public Massage(T content){//由外部指定
		setContent(content);
	}
	public T getContent(){//由外部指定
		return content;
	}
	public void setContent(T content){//由外部指定
		this.content=content;
	}
	public void sentMassage(){
		System.out.println(content);
	}
}


public class MassageTest{
	public static void main(String[]args){
		Massage<String>ma=new Massage<String>("你今天有什么计划吗?");
		Massage<Double>me=new Massage<Double>(98.3);
		ma.sentMassage();
		me.sentMassage();
	    String str=me.getContent();//此处失误
		str.split("");
		
		
	}
}
编译后:
MassageTest.java:25: 错误: 不兼容的类型: Double无法转换为String
            String str=me.getContent();//此处失误
                                    ^

相信聪明的你已经发现不同了,用泛型类进行实现相同的功能,和普通类实现相比更安全,都是相同的错误,但泛型实现在编译期间就可以泛型,而普通类进行实现需要在运行期间才能够发现(如果开发要求比较严格,这种有警告信息的代码一般不允许发布)

注意:

  • 泛型的类型只能用类,基本数据类型需要使用对应的包装类,有自动拆箱和装箱的加持,也并不复杂
  • 当泛型指定的类型和传入的类型不一致时,程序将会在编译期间报错
  • 当在实例化对象的时候没有指定泛型的类型 即Massage ma=new Massage()时,为了保证程序不出错,java将会把泛型类型默认为Object,但在编译期间将会出现安全警告,但不影响运行
//用于接收不同类型的消息
class Massage<T>{//标识为一个泛型类,T该泛型的类型
	private T content;//此处类型由外部指定
	public Massage(T content){//由外部指定
		setContent(content);
	}
	public T getContent(){//由外部指定
		return content;
	}
	public void setContent(T content){//由外部指定
		this.content=content;
	}
	public void sentMassage(){
		System.out.println(content);
	}
}


public class MassageTest{
	public static void main(String[]args){
		Massage ma=new Massage("你今天有什么计划吗?");//没有指定泛型类型
		Massage me=new Massage (98.3);//没有指定泛型类型
		ma.sentMassage();
		me.sentMassage();
	    
		
		
	}
}
编译时:
C:\Users\SWT\Desktop\java语言疑问测试代码>javac MassageTest.java
注: MassageTest.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。

output:
你今天有什么计划吗?
98.3

多元泛型

上面的程序我们都只运用了一个泛型类型,其实我们可以设置多元泛型
举例说明:

//验证多元泛型的使用
class Tools<K,V>{
	
	private K key;
	private V value;
	public Tools(K key,V value){
		setKey(key);
		setValue(value);
	}
	public K getKey(){
		return this.key;
	}
	
	public void setKey(K key){
		this.key=key;
	}
	public V getValue(){
		return this.value;
	}
	public void setValue(V value){
		this.value=value;
	}
}

public class ToolsTest{
	public static void main(String[]args){
		Tools<String,Double>to=new Tools<String,Double>("汤姆猫",34.5);
        System.out.println("名称:"+to.getKey());
        System.out.println("价值:"+to.getValue());		
	}
}
output:
名称:汤姆猫
价值:34.5

泛型接口

必知:实现的接口的泛型类型需要和其子类的泛型类型相同

我们不仅可以定义泛型类,还可以定义泛型接口,泛型接口有2种实现方法

  • 方式一:接口的泛型类型和泛型类一起在实例化时指定
//泛型接口的实现
interface Info<T>{//该步和泛型类意义相同
public T getVar();
	
}

class Infolmpl<T> implements Info<T>{
	private T var;
	public Infolmpl(T var){
		this.setVar(var);
	}
	public void setVar(T var){
		this.var=var;
		
	}
	public T getVar(){
		return this.var;
	}
}


public class FInterfaceTest{
	public static void main(String[]args){
		Info<String> in=new Infolmpl<String>("天才在左,疯子在右");//用子类实例化接口
		System.out.println(in.getVar());
		
		
	}
}
output:
天才在左,疯子在右
  • 方式二:在接口中指定具体的泛型类型(这种方式可能会更常用)
//泛型接口的实现
interface Info<T>{//该步和泛型类意义相同
public T getVar();
	
}

class Infolmpl<T> implements Info<String>{//该处直接指定泛型类型
//指定泛型类型后,后面的定义就用String直接表示就好了
	private String var;
	public Infolmpl(String var){
		this.setVar(var);
	}
	public void setVar(String var){
		this.var=var;
		
	}
	public String getVar(){
		return this.var;
	}
}


public class FInterfaceTest{
	public static void main(String[]args){
		Info<String> in=new Infolmpl<String>("天才在左,疯子在右");//用子类实例化接口
		System.out.println(in.getVar());
		
		
	}
}
output:
天才在左,疯子在右

泛型对象引用传递的解决方案

//验证泛型对象的引用传递
class Massages<T>{
	private T content;
	public Massages(T content){
		this.setContent(content);
	}
	public T getContent(){
		return this.content;
	}
	public void setContent(T content){
		this.content=content;
	}
	public void sentMassages(){
		System.out.println(this.content);
	}
	
}
public class MassagesTest{
	public static void info(Massages<String> ma){//进行引用传递
		ma.sentMassages();
	}
	public static void main(String[]ages){
		Massages<String> me=new Massages<>("同学你又在摸鱼吗?");
		info(me);
	}
}
output:
同学你又在摸鱼吗?

此时可以发现可以成功传递了

但如果我们换成下面一句代码,发现传不过来了

Massages<Integer> me=new Massages<>(12);

MassagesTest.java:24: 错误: 不兼容的类型: Massages无法转换为Massages

可以得出一个我自以为是的推论:

编译器将同一个类的不同泛型的对象的数据类型看成了不同的数据类型
就是Massages和Massages它将会认为了不同的数据类型

下面是验证与推导的过程
**-------------------------------------------------------------------------------------------------------------

为了解决此时泛型对象的引用传递我们想到了以下的3种解决方案

1.我们根据传入泛型的类型,设计多种传参函数进行重载,完成对该类的不同泛型对象的引用传递
2.我们知道Object类是所有类的父类,如果我们将传参函数的泛型设置成Object,就可以接收不同的对象了
3.Massage和Massages编译器认为其类型不同,但本质上将都同属于Massage类,所以可以直接用Massages类进行接收,不进行泛型标识
方案一:

//验证泛型对象的引用传递
class Massages<T>{
	private T content;
	public Massages(T content){
		this.setContent(content);
	}
	public T getContent(){
		return this.content;
	}
	public void setContent(T content){
		this.content=content;
	}
	public void sentMassages(){
		System.out.println(this.content);
	}
	
}
public class MassagesTest{
	//将传参函数进行重载
	public static void info(Massages<String> ma){
		ma.sentMassages();
	}
	public static void info(Massage<Integer>ma){
		ma.sentMassages();
	}
	public static void main(String[]ages){
		Massages<Integer> me=new Massages<>(12);
		Massages<String> ma=new Massages<>("条条大路通罗马");
		info(me);
		info(ma);
	}
}
MassagesTest.java:29: 错误: 对于info(Massages<Integer>), 找不到合适的 方法
                info(me);
                ^
    方法 MassagesTest.info(Massages<String>)不适用
      (参数不匹配; Massages<Integer>无法转换为Massages<String>)
    方法 MassagesTest.info(Massage<Integer>)不适用
      (参数不匹配; Massages<Integer>无法转换为Massage<Integer>)
2 个错误

但好像失败了,编译器不认为这样的2个函数是重载

  • 方案二
//验证泛型对象的引用传递
class Massages<T>{
	private T content;
	public Massages(T content){
		this.setContent(content);
	}
	public T getContent(){
		return this.content;
	}
	public void setContent(T content){
		this.content=content;
	}
	public void sentMassages(){
		System.out.println(this.content);
	}
	
}
public class MassagesTest{
	//将传参函数进行重载
	public static void info(Massages<Object> ma){
	
		ma.sentMassages();
	}
	
	public static void main(String[]ages){
		Massages<Integer> me=new Massages<>(12);
		Massages<String> ma=new Massages<>("条条大路通罗马");
		
		info(me);
		info(ma);
		
	}
}
C:\Users\SWT\Desktop\java语言疑问测试代码>javac MassagesTest.java
MassagesTest.java:29: 错误: 不兼容的类型: Massages<Integer>无法转换为Massages<Object>
                info(me);
                     ^
MassagesTest.java:30: 错误: 不兼容的类型: Massages<String>无法转换为Massages<Object>
                info(ma);

不出所料,Massages

标签:Massages,java,void,基础知识,content,泛型,public,Massage
From: https://www.cnblogs.com/swtaa/p/16931820.html

相关文章

  • 从 Java 到 Kotlin - 介绍 Kotlin
    B站视频:​​https://www.bilibili.com/video/BV1Ti4y197u9/?share_source=copy_web&vd_source=74448386fecd6b0affd408eabb573749​​语法层面可空对象(和C#的<Nullable>......
  • Java8 Function 用法简介
    publicclassFunctionTest{publicstaticvoidmain(String[]args){Function<Numbers,Integer>test1=i->i.getN1()-i.getN2();Funct......
  • Java.11.28
    一.递归1.递归就是:A方法调用A方法!就是自己调用自己2.递归的能力在于用有限的语句来定义对象的无限集合3.递归结构包含两个部分:3.1.递归头:什么时候......
  • 【Java并发入门】01 并发编程Bug的源头
    一、根本原因「CPU、内存、磁盘之间的速度差异」为了能同时执行多个任务,CPU发展出时间片轮转、多核等CPU要从内存中读数据太慢了,所以给自己设置了缓存CPU读磁盘更......
  • Java:Hutool工具箱之hutool-jsonJSON数据读取转换处理
    文档https://hutool.cn/docs/#/json/概述依赖<dependency><groupId>cn.hutool</groupId><artifactId>hutool-json</artifactId><version>5.8.10</versi......
  • java8 成绩分数排名
    第一种是分数一样的排名不相同,排名不重复。分数为空的考生不参与排名,排在后面。第二种是分数一样排名相同,排名重复,但是会把位置占掉。(eg:1,2,2,2,2,6,7这种排名相同的情况......
  • Java 任意文件下载漏洞
    我们在开发Web应用时,经常会提供文件下载功能。对外暴露类似如下的URLhttp://demo.com/download?fileName=foo.txt这样的确很方便,但是,大家有没有想过,这样的功能可能会......
  • java 验证邮箱格式正确性、验证字符串是否为数字
    java验证邮箱格式正确性 importjava.util.regex.Matcher;importjava.util.regex.Pattern;publicclassRegisterCheck{   /**    *验证输入的邮箱格式是......
  • Java生成二维码,基于QRCode
    packagetest;importjava.io.*;importjava.util.Date;importjava.awt.*;importjava.awt.image.*;importjavax.imageio.*;importcom.swetake.util.Qrcode;publicclass......
  • 一个GUI的简单练习-------- Java记事本 简单实现 陆续完善中……
    packagejavanotpad;publicclassMainFrame{/***@paramargs*authorjavaAlpha*时间:2009年5月8日20:00:50*java记事本*/publicstaticvoidmain(Strin......