【Java学习笔记】枚举类与泛型

枚举类型是一种特殊的数据类型,之所以特殊,是因为它既是一种类(Class)类型,却又比类类型多了一些特殊的约束,但正是因为这些约束的存在,也造就了枚举类型的简洁性、安全性、便捷性。

泛型,即“参数化类型”,参数,最熟悉的就是定义方法时有形参,调用此方法时传递实参。那么,如何理解参数化类型呢?顾名思义,参数化类型就是将类型由原来的具体类型参数化,类似于方法中的变量参数。此时类型也定义成参数形式(可以称之为类型形参),在调用/使用时传入具体的类型(类型实参)。

2.1 枚举类型

枚举类型是指其字段由一系列固定的常量组成的数据类型。在生活中常见这种类型的数据,例如,表示方向的值只能是东、西、南、北,表示一周中的天数只能是星期一 ~ 星期日。因为是常量,所以枚举类类型的字段要用大写字母表示。

2.1.1 枚举类型的定义

在Java语言中,使用关键字enum定义一个枚举类型。
例:使用枚举类型来指定一周中的天数

public enum Day{
	星期日,星期一,星期二,星期三,星期四,星期五,星期六
}

在任何时候,如果需要代表一系列固定的常量,就应该使用枚举类型。在两种情况下,尽可能使用枚举类型:一种是自然的枚举类型,例如,表示太阳系中的行星或者员工的性别,这是一组 固定的值,所以在程序中应该使用枚举类型来表示;另一种是程序在编译的时候,已经知道某个数据所有可能的值,也要尽可能的使用枚举类型。
例如,在扑克牌游戏中,花色是固定的。只有四种颜色:方块,梅花,红心和黑桃,所以,在一个扑克牌游戏的程序中,如果要定义表示扑克牌花色的类型,可以使用枚举类型。

public enum Suit{
	DIAMONDS,	//方块
	CLUBS,			//梅花
	HEARTS,		//红心
	SPADES,			//黑桃		
}

【例1】枚举示例类型
``
package enums;

public class EnumDemo {

Day day ; 		//声明Day枚举类型的变量day
public EnumDemo(Day day) {	//构造器,传入一个Day类型的参数
	this.day = day;
}

public void tellFelling() {
	switch(day) {
	case 星期一 :  System.out.println("星期一都令人不喜欢");break;
	case 星期五 :	  System.out.println("星期五所有人都喜欢");break;
	case 星期六 :
	case 星期日 :  System.out.println("周末让人愉快");break;
	default:System.out.println("一周的中间,不好也不坏");break;
	}
}
public static void main(String[] args) {
	EnumDemo firstDay = new EnumDemo(Day.星期一);
	firstDay.tellFelling();
	EnumDemo thirdDay = new EnumDemo(Day.星期二);
	thirdDay.tellFelling();
	
	EnumDemo fifthDay = new EnumDemo(Day.星期五);
	fifthDay.tellFelling();
	
	EnumDemo sixthDay = new EnumDemo(Day.星期六);
	thirdDay.tellFelling();
	
	EnumDemo seventhDay = new EnumDemo(Day.星期日);
	thirdDay.tellFelling();
}
public enum Day{
	星期日,星期一,星期二,星期三,星期四,星期五,星期六
}

}

``
在这里插入图片描述

2.1.2 枚举类型的迭代

在Java语言中,enum声明了一个类(称为“枚举类型”)。枚举类的类体中可能包括方法和其他字段。当编译器创建了一个枚举时,他会自动的添加一些专门的方法。例如,他会添加一个静态的values()方法,该方法会按照声明的顺序返回一个包含枚举类中所有值的数组。
values()方法通常与for-each结构一起使用,以迭代一个枚举类型的值。例如,要迭代一星期中的每一天,使用如下代码:

for(Day day :Day.values() ){
	System.out.println("今天是"+day);
}

所有的枚举类都隐含地继承自java.lang,Enum。因为Java不支持多重继承,所有一个么句类型不能再从其他类继承。
【例2】枚举示例程序

public enum Planet{
        水星(3.303e+23, 2.4397e6),
        金星(4.869e+24, 6.0518e6),
        地球(5.976e+24, 6.37814e6),
        火星(6.421e+23, 3.3972e6),
        木星(1.9e+27,7.1492e7),
        土星(5.688e+26,6.0268e7),
        天王星(8.686e+25, 2.5559e7),
        海王星(1.024e+26,2.4746e7);
        private final double mass;
        private final double radius;

        Planet (double mass, double radius){
            this.mass = mass;
            this.radius =  radius;
        }

     public static final double G = 6.673008-11;
     double surfaceGravity() {
         return G* mass / (radius*radius);
     }
     double surfaceweight (double otherMass){
         return otherMass * surfaceGravity();
     }

     public static void main(String[] args){
         if (args.length<1){    如果没有命令行参数,则返回
             System.out.println("请在命令行中输入参数!");
             return;
         }
         double earthweight = Double.parseDouble (args[0]);//通过命令行参数传递在地球上的休重
         double mass = earthweight/地球.surfaceGravity(); //获取质量大小
         for (Planet p:Planet.values())
             System. out.printf("你在%s%f公斤。%n",p, p.surfaceweight (mass));
     }


 }

在这里插入图片描述

一个枚举类型的构造器必须为包级私有的或私有的(Private),它自动地创建在枚举体一开始定义的常量。不能人为的调用枚举类型的构造器。除属性和构造器外,Planet还定义了一些方法。

2.2 泛型

泛型是java语言中引入的新特性。通过在程序中使用泛型,可以提高程序代码的复用性,减少数据的类型转换,从而提高代码的运行效率,让代码更加健壮。
在任何正式的软件项目中,Bug都会存在,这是无法改变的事实。通过使用泛型,可以协助程序员进行代码检测,增加代码的稳定性。

2.2.1 为什么要使用泛型

程序中出现的Bug一般有两类,一类是编译时的Bug,另一类是运行时的Bug。满足一定的条件才会触发。在Java语言中引入泛型,通过在编译时进行更多的bug检测,从而增强代码的稳定性。

2.2.2 一个简单的Box类

public class Box{
	private Object object;
	public void add(Object object){
		this.object = object;
}
	public Object get(){
	return object;
}
}

因为Box类的方法接收或返回Object,因此可以传入任何类型的参数(原始数据类型除外)。但是,如果这个“盒子“只用来存放和获取一个指定类型的对象,则将其需要包含的类型限定为某些指定的类型(如Interger),那么唯一的选择是在帮助文档中详细的说明这种要求(编译器对此一无所知)

public class BoxDemo1 {
    public static void main(String[] args) {
        //只能将Interger对象放入此箱子中
        Box integerBox = new Box();
        integerBox.add(new Integer(10));
        Integer someInteger = (Integer)integerBox.get();
        System.out.println(someInteger);
    }

}

在这里插入图片描述

我们知道,将类型从Object转换到Interger是正确的,因为Object类型的引用实际上是Interger对象实例。但是编译器对此一无所知,它只信赖正确的转换,所以,如果传入一个错误类型的对象,如String,那么编译器并不知道这是错误的.
在这里插入图片描述
如上图所示,在从Box里获取放入的对象时,会想当然的任务应该是Interger类型的,从而将一个指向String类型的Objec引用变量向Interger类型转换。
这是一个Bug,但能编译通过。直到运行的时候,程序崩溃并抛出ClassCastException(程序转换异常)

2.3 泛型类型

泛型类型实际上是通过给类或接口增加类型参数(Type Parameters)来实现的。类型参数指明,泛型类型可以用在多种数据类型上,在具体使用时可以根据实际指定的类型来确定。

2.3.1 Box类型的泛型版本

声明泛型版本与声明类的一般版本的语法相似。只需要在类名后面加上一个类型参数即可。

将上一节中的Box改为泛型类,首先将声明类的代码"public class Box"改为“public class Box”,以创建一个“泛型类型声明”。
这里引入了一个“类型变量”称为T,可以在该类中的任何地方使用这些类型变量,在一定程度上将他们当做已知的类型。
实际上,“类型变量”T和一般意义上的变量非常相似,只需要把T想象为一个代表指定类别的变量即可,他的“变量值”是传递进来的任何类型:即可以是任何类类型,也可以是任何接口类型,甚至是另一个类型变量。但是它不能是任何的原始数据类型。

//Box 的泛型版本
public class Box<T>{
	private T t ;
	public void add(T t){
		this.t = t;
}
public T get(){
	return t;
}
}

在上面的代码中,将所有出现Object的地方都用T来代替,在程序中应用这个具有泛型特性的Box时,必须执行一个“泛型类型调用”,指名实际的具体类型,即在每个类型变量处分别用一个实际的具体类型替换掉T,例如使用Interger

Box <Interger> intergerBox;

一个泛型类型调用通常被看做“参数化类型”。要实例化这个类,照常使用new关键字,但是要将<Interger>放在类名和圆括号之间。例如:

intergerBox = new Box<Interger>
Box<Interger> intergerBox = new Box<Interger>();

一旦intergerBox被实例化,就可以随便调用它的get()方法,而不再需要使用类型转换。

如下面的实例所示:

public class BoxDemo3 {
	public staticvoid main(String[] args){
		Bod<Integer> integerBox = new Box<Integer>();
		integerBox.add(new Integer(10));
		Integer someInteger = integerBox.get(); //不需要进行类型转换
		System.out.println(someInteger);
	}
}

在这里插入图片描述

2.3.2 参数类型命名惯例

按照惯例,类型参数命名为单个的大写字母。
这样命名的原因是:如果不这样命名,将很难区分一个类型变量和一个普通类或接口名称的不同。

  • E : 元素。
  • K :键
  • N :数字
  • T :类型
  • V :值
  • S U V:第二、三、四个类型。

2.4 泛型方法和泛型构造器

类型参数还可以再方法和构造器签名中声明,用来创建“泛型方法”和“”泛型构造器“。这与声明一个泛型类型相似,但是类型参数的作用域被限制在它被声明的方法或构造器中。
【例】泛型方法和泛型构造器示例
在这里插入图片描述
通过传递进来的不同类型,输出结果页相应的发生改变,
这种特性被称为"类型推断",允许像调用一个普通方法一样调用一个泛型方法,而不必指定一个类型。

2.5 限定的类型参数

有时候程序员想将允许被传递的类型参数的类型限制在一定的范围之内。例如,操作数字的方法可能只想接收Number(数字类)或其子类的实例。这就是“限定类型参数”的目的。

要声明一个限定的类型参数,可以通过列出类型参数的名字,后跟extends关键字。再后跟他的“上限”来实现。
【例】
在这里插入图片描述
对类型参数的限定也可以包括指定额外的必须被实现的接口,使用&字符来实现。如下所示:指定类型变量U可以接受的值为实现了MyInterface接口的Number类或其子类。

< U extends Number & MyInterface >

在限定类型参数时,可以限定上限的类型中最多只能有一个为类,其余必须为接口。接口可以有多个,中间用&字符分隔。

2.6 泛型子类型

可以将一个类型的对象赋给另一个类型的对象,只要两个类型是兼容的。
比如,可以将一个Interger类型的对象赋给一个Object类型的对象。因为Object是Interger的一个父类型
在面向对象的术语中,这被称为“是”的关系。但是,Interger还是一种Number。


对于泛型,也可以这样使用,执行一个泛型调用,传递Number作为它的类型实参,而任何后来对于add()方法的调用,如果参数与Number兼容(是Number类或其子类),则都是可以的。


现在考虑下面的方法:

public void boxTest(Box<Number> n){

}

它接收一个参数,参数的类型是’‘‘Box<Number - >’’’ ,但是Box<Interger - > 和 Box<Double - > 不是 ‘’‘Box<Number - >’‘’ 的子类型。
如果想象一个具体的对象——可以实际的描述事物——如笼子,理解为什么会这样会变得很容易。

在需要动物的地方,可以引用一头狮子,已同意狮子当然可以被放到一只关狮子的笼子里

Cage<Lion> lionCage = ...
lionCage.add(king)

而蝴蝶可以被放到一只关蝴蝶的笼子里。

Cage<Butterfly> lbutterflyCage = ...
lbutterflyCage.add(monarch)

那么,如果是一只“关动物的笼子”呢?或者准确的说,什么是一只“关所有动物的笼子”呢?
在这里,笼子被设计用来存放所有类型的动物,混合在一起。
不存在足够解释的格栅来关狮子,并且必须有足够小的空隙来关蝴蝶,这样一只笼子甚至不可能真正的建造出来。

2.7 使用通配

  • 在泛型中,使用通配符 " ? "可以表示一个未知的类型。例如,要指定一只能关“某些”类型动物的笼子,可以使用下面的代码形式表示
Cage<? extends Animal> someCage = ... ;

将"? extends Animal" 读作“一个未知的类型,他是Animal的子类型,也可能是Animal本身”。

  • 还可以通过使用super取代extends来指定一个下限。所以代码<? super Animal> 可以被读作‘一个未知的类型,它是Anmial的父类型,也可能是Anmial本身’
  • 还可以使用一个“”无限定通配符<?>“来指定一个未知类型。无限定通配符在本质上与<? extends Object >相同
    Cage< Lion > 和 Cage< Butterfly > 不是Cage< Animal > 的子类型。实际上他们是Cage< ? extends Animal >的子类型。

如果someCage 是一只关蝴蝶的笼子,那么它用来关蝴蝶很合适。但是如果用它来关狮子,则狮子会破窗而出。如果someCage是一只关狮子的笼子,那么用它来关狮子很合适,但是如果用来关蝴蝶,蝴蝶会飞走。s
所以,可以将各种动物放到他们单独的笼子里,并先为狮子调用这个方法,再为蝴蝶调用这个方法。
或者选择将所有动物组合放到关所有动物的笼子里。

2.8 类型擦除

当一个泛型被实例化时,编译器通过"类型擦除"的技术来编译这些类型。
“类型擦除”指的是编译器移除一个类或方法中所有与类型参数相关的信息。类型擦除能够使使用泛型的Java应用程序与Java类库在泛型出现之前创建的应用程序保持二进制上的兼容性。

Box< String > 被编译为类型Box。在这里,Box被称为是"原类型(Raw Type )".所谓源类型,指的是不带任何类型参数的泛型类接口或接口的名称。这意味着无法找出一个泛型类在运行时正在使用的是Object的什么类型。

因为存在“类型擦除”,所以新的代码可能继续使用遗留的代码。但不管什么原因,使用一个原类型被认为是一种不好的程序设计实践,应该尽量避免使用。

2.9 拓展训练

2.9.1 训练一:将枚举类型设置到集合中

在这里插入图片描述

2.9.2 训练二:输出枚举类类型

package list;
import list.DaysOfWeekEnum.DaysOfWeeK;
public abstract class TestWeek {
	enum WeeK {
	    MONDAY{
	    	public String getWeek() {
	    		return "星期一";
	    	}
	    	
	    },
	    TUESDAY{
	    	public String getWeek() {
	    		return "星期二";
	    	}
	    } ,
	    WEDNESDAY{
	    	public String getWeek() {
	    		return "星期三";
	    	}
	    },;

		public abstract String getWeek();

	}

	public static void main(String[] args) {
		for (WeeK w : WeeK.values()) {
			System.out.println(w.ordinal() + "____" + w.name()+":" +w.getWeek());
		}

	}

}

在这里插入图片描述

2.10 技术解惑

2.10.1 EnumSet是什么

java.util.EnumSet是使用枚举类型的集合体现。当集合创建时,枚举集合中的所有元素必须来自单个指定的枚举类型,可以是显式的或者是隐式的。EnumSet是不同步的,不允许null值的存在。它也提供了一些有用的方法。如:copyOf(Collection c) \ of(Efirst) \ complementOf(EnumSet s)

2.10.2 使用泛型的好处是什么

泛型的本质是参数化类型。也就是数,所操作的数据类型被指定为一个参数。使用泛型的好处有:
(1)类型安全,提供编译期间的类型检测
(2) 前后兼容
(3)泛化代码,使代码可以被重复利用
(4)性能较高。可以为Java编译器和虚拟机带来更多的类型信息。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SPIE独立出版 | 往届均已完成EI检索】2024云计算、性能计算与深度学习国际学术会议(CCPCDL 2024)

2024云计算、性能计算与深度学习国际学术会议(CCPCDL 2024) 2024 International conference on Cloud Computing, Performance Computing and Deep Learning *CCPCDL往届均已完成EI检索&#xff0c;最快会后4个半月完成&#xff01; 一、重要信息 大会官网&#xff1a;www…

python-开学?

[题目描述] 小执&#xff1a;终于可以开学啦&#xff01;好开心啊&#xff01; 小理&#xff1a;你没看新闻吗&#xff0c;开学日期又延后了。 小执&#xff1a;&#x1d441;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&#x1d442;&am…

Vue01-前端概述

一、前端核心分析 1.1、概述 Soc原则&#xff1a;关注点分离原则 Vue 的核心库只关注视图层&#xff0c;方便与第三方库或既有项目整合。 HTML CSS JS : 视图 &#xff1a; 给用户看&#xff0c;刷新后台给的数据 网络通信 &#xff1a; axios 页面跳转 &#xff1a; v…

Java聚合快递系统对接云洋系统快递小程序APP公众号系统源码

快递小程序的深度解析与未来展望 &#x1f69a; 引言&#xff1a;快递行业的变革与挑战 在数字化浪潮的推动下&#xff0c;快递行业正经历着前所未有的变革。随着电商的蓬勃发展&#xff0c;快递业务量呈爆发式增长&#xff0c;而传统的快递管理方式已难以满足日益增长的需求。…

我用chatgpt写了一款程序

众所周知&#xff0c;Chatgpt能够帮助人们写代码&#xff0c;前几天苏音试着完全用Chatgpt写一款Python程序 有一句话我很赞同&#xff0c;未来能代替人的不是AI&#xff0c;是会使用AI的人。 最终&#xff0c;写下来效果还不错&#xff0c;完全提升了我的办公效率。 开发前…

计算机跨考现状,两极分化现象很严重

其实我觉得跨考计算机对于一些本科学过高数的同学来说有天然的优势 只要高数能学会&#xff0c;那计算机那几本专业课&#xff0c;也能很轻松的拿下&#xff0c;而对于本科是文科类的专业&#xff0c;如果想跨考计算机&#xff0c;难度就不是一般的大了。 现在跨考计算机呈现…

了解Java的LinkedBlockingQueue

了解Java的LinkedBlockingQueue LinkedBlockingQueue是一个基于链接节点的有界阻塞队列。它实现了BlockingQueue接口&#xff0c;可以在多线程环境中安全地进行插入、移除和检查操作。LinkedBlockingQueue的容量可以在创建时指定&#xff0c;如果未指定&#xff0c;则默认容量…

AI绘画stable diffusion 模型介绍及下载、使用方法,超全的新手入门教程建议收藏!

大家好&#xff0c;我是画画的小强 今天我将继续分享AI绘画Stable Diffusion的模型、参数含义等&#xff0c;分享给各位朋友一起学习。 一、模型 Stable difusion 模型就是所谓的大模型&#xff0c;用来控制整个画面的风格走势的。 打开webui页面&#xff0c;可以看到大模型…

安卓实现圆形按钮轮廓以及解决无法更改按钮颜色的问题

1.实现按钮轮廓 在drawable文件新建xml文件 <shape xmlns:android"http://schemas.android.com/apk/res/android"<!--实现圆形-->android:shape"oval"><!--指定内部的填充色--><solid android:color"#FFFFFF"/><!-…

Mongodb介绍及window环境安装

本文主要内容为nosql数据库-MongoDB介绍及window环境安装。 目录 什么是MongoDB&#xff1f; 主要特点 MongoDB 与Mysql对应 安装MongoDB 下载MongoDB 自定义安装 创建目录 配置环境变量 配置MongoDB服务 服务改为手动 启动与关闭 安装MongoDB Shell 下载安装包 …

高考分数限制下,选好专业还是选好学校?

高考分数限制下&#xff0c;选好专业还是选好学校&#xff1f; 高考作为每年一度的盛大考试&#xff0c;不仅关乎学生们的未来&#xff0c;更承载了家庭的期望。2004年高考刚刚结束&#xff0c;许多考生和家长已经开始为填报志愿而焦虑。选好学校和专业&#xff0c;直接关系到…

LogicFlow 学习笔记——8. LogicFlow 基础 事件 Event

事件 Event 当我们使用鼠标或其他方式与画布交互时&#xff0c;会触发对应的事件。通过监听这些事件&#xff0c;可以获取其在触发时所产生的数据&#xff0c;根据这些数据来实现需要的功能。详细可监听事件见事件API。 监听事件 lf实例上提供on方法支持监听事件。 lf.on(&…

【SCAU数据挖掘】数据挖掘期末总复习题库应用题及解析

1. 给定圆的半径为e &#xff0c;令 MinPts3&#xff0c;考虑下面两幅图。 &#xff08;1&#xff09;哪些对象是核心对象? m,p,o,r(因为这些核心对象在半径e的范围内都至少包含MinPts3个对象) &#xff08;2&#xff09;哪些对象是直接密度可达的? 对象q是…

2024年【通信安全员ABC证】最新解析及通信安全员ABC证模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 通信安全员ABC证最新解析是安全生产模拟考试一点通总题库中生成的一套通信安全员ABC证模拟试题&#xff0c;安全生产模拟考试一点通上通信安全员ABC证作业手机同步练习。2024年【通信安全员ABC证】最新解析及通信安全…

vuejs3 pinia持久化存储

pinia地址&#xff1a; 开始 | Pinia 插件地址&#xff1a; 快速开始 | pinia-plugin-persistedstate 先安装pinia npm install pinia 再安装插件 安装pinia后&#xff0c;再安装这个插件 npm i pinia-plugin-persistedstate 全局中引入持久化插件 在src目录下的main…

【ONE·基础算法 || 记忆化搜索】

总言 主要内容&#xff1a;编程题举例&#xff0c;熟悉理解记忆化搜索类题型&#xff08;对比递归、动态规划理解运用&#xff09;。             文章目录 总言1、记忆化搜索1.1、基本介绍1.2、细节理解&#xff08;记忆搜索化、递归、动态规划……&#xff09; 2、斐…

智源联合多所高校推出首个多任务长视频评测基准MLVU

当前&#xff0c;研究社区亟需全面可靠的长视频理解评估基准&#xff0c;以解决现有视频理解评测基准在视频长度不足、类型和任务单一等方面的局限性。因此&#xff0c;智源联合北邮、北大和浙大等多所高校提出首个多任务长视频理解评测基准MLVU&#xff08;A Comprehensive Be…

利用K8S技术栈打造个人私有云

1.三个节点&#xff1a;master&#xff0c;slave&#xff0c;client 在Kubernetes集群中&#xff0c;三个节点的职责分别如下&#xff1a; Master节点&#xff1a; docker&#xff1a;用于运行Docker容器。 etcd&#xff1a;一个分布式键值存储系统&#xff0c;用于保存Kuberne…

AI + 3D:用单个图像和文本提示创建可交互的3D世界

你是否曾经梦想过只需一张照片和一些简单的文字描述,就能立即进入一个生动的3D虚拟世界?今天,我们将介绍一个革命性的技术,它就像是一台神奇的3D场景制造机,能够根据你的想象快速构建出令人惊叹的虚拟空间。 一、技术概览 这项技术不仅仅是一个简单的图像到3D的转换工具…

PCB雕刻切割用德国自动换刀主轴SycoTec 4033 AC-ESD

随着电子行业的蓬勃发展&#xff0c;印刷电路板&#xff08;PCB&#xff09;的应用范围正在迅速扩大&#xff0c;涵盖了通信、计算机、消费电子等诸多领域。伴随着PCB的广泛应用&#xff0c;对PCB板切割加工技术的要求也日益严格。高速电主轴作为分板机的关键零部件之一&#x…