黑马程序员————学习日记【10】 【泛型、Map和Collections】

本文深入讲解Java集合框架的核心概念,包括Set、Map等接口的不同实现类及其应用场景,探讨泛型的作用与使用方法,并介绍集合与数组之间的转换技巧。

------- android培训java培训、期待与您交流! ----------

 

 

Set:无序,不可以重复
 |--HashSet:数据结构是哈希表,线程是非同步的
    保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true。

 |--TreeSet:可以对Set集合中的元素进行排序
    底层数据结构是二叉树
    保证元素唯一性的依据:compareTo方法return 0.
    
    只有HashSet才关联哈希值,TreeSet走的是二叉树。TreeSet是通过compareTo方法来确定元素是否相同。
    如果想TreeSet集合删除元素或者判断元素是否包含,走的都是CompareTo方法return 0.但凡返回0,认为元素是相同的。

    TreeSet排序的第一种方式:让元素自身具备比较性。
    元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。

    TreeSet的第二种排序方式
    当元素自身不具备比较性,或者具备的比较性不是所需要的,此时就需要让集合自身具备比较性。
    在集合一初始化时,就有了比较方式。

 

 

当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数

当两种排序都存在时,以比较器为主。

 

/*
练习:按照字符串长度排序

字符串本身具备比较性,但是它的比较方式不是所需要的

这时就只能使用比较器
*/

import java.util.*;
class TreeSetTest
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet(new StrLenComparator());

		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("aaa");
		ts.add("z");
		ts.add("hahahaha");

		Iterator it = ts.iterator();

		while(it.hasNext())
		{
			System.out.println(it.next());
		}
	}
}

class StrLenComparator implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		String s1 = (String)o1;
		String s2 = (String)o2;

		/*
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()==s2.length())
			return 0;
			*/

		int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));

		if(num==0)
			return s1.compareTo(s2);
		return num;
	}
}


 

泛型:JDK1.5以后出现新特性,用于解决安全问题,是一个类型安全机制。

好处:
1、将运行时期出现的问题ClassCastException,转移到了编译时期方便于程序员解决问题,让运行时期问题减少,安全。

2、避免了强制转换的麻烦

泛型格式:通过<>来定义要操作的引用数据类型

在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,只要见到<>就要定义泛型,其实<>就是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可

class GenericDemo 
{
	public static void main(String[] args) 
	{
		
		ArrayList<String> a1 = new ArrayList<String>();

		a1.add("abc01");
		a1.add("abc0991");
		a1.add("abc014");

		//a1.add(4);//a1.add(new Integer(4));

		Iterator<String> it = a1.iterator();
		while(it.hasNext())
		{
			String s = it.next();
			System.out.println(s+":"+s.length());
		}
	}
}


 

泛型类定义的泛型,在整个类中有效。如果被方法使用。
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上


特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上

注意:泛型定义在方法上,需要放到返回值类型的前面,修饰符的后面。

 

 

?通配符,也可以理解为占位符。

泛型的限定:【泛型的高级应用,泛型的复合应用】

? extends E:可以接收E类型或者E的子类型,上限。
? super E:可以接收E类型或者E的父类型,下限。

 

 

 

Map集合:该集合存储键值对,一对一对往里存,而且要保证键的唯一性
 1,添加
  put(K key,V value)
  putAll(Map<? extends K,? extends V> m)

 2,删除
  clear()
  remove(Object key)

 3,判断
  containsValue(Object value)
  containsKey(Object key)
  isEmpty()

 4,获取
  get(Object key)
  size()
  values()

  entrySet()
  keySet()

Map
 |--Hashtable:底层是哈希表数据结构,不可以存入null键null值。
     该集合是线程同步的。【JDK1.0】效率低

 |--HashMap:底层是哈希表数据结构,允许使用null键和null值。
       该集合是不同步的。【JDK1.2】效率高

 |--TreeMap:底层是二叉树数据结构,线程不同步。可以用于给
    Map集合中的键进行排序。

和Set很像
其实,Set底层就是使用了Map集合。

import java.util.*;

class MapDemo 
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

		//添加元素,当添加时出现相同的键,那么添加后的值会覆盖原有键
		//对应的值,并put方法会返回被覆盖的值。
		System.out.println("put:"+map.put("01","zhangsan1"));
		System.out.println("put:"+map.put("01","wangwu"));
		map.put("02","zhangsan2");
		map.put("03","zhangsan3");

		System.out.println("containsKey:"+map.containsKey("022"));
		//System.out.println("remove:"+map.remove("02"));

		System.out.println("get:"+map.get("023"));
		
		map.put("04",null);
		System.out.println("get:"+map.get("04"));
		//可以通过get方法的返回值来判断一个键是否存在。
		//通过返回null来判断。

		//获取map集合中所有的值
		Collection<String> coll = map.values();

		System.out.println(coll);
		System.out.println(map);
	}
}

map集合的两种取出方式
1、Set<k keySet>:将map中所有的键存入到Set集合。因为set具备迭代器。
 所以可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。

 Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。

2、Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了 set集合中,而这个关系的数据类型就是:Map.Entry

 

 

练习:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数,
希望打印结果:a(1)c(2)......

通过结构发现,每一个字母都有对应的次数,说明字母和次数之间都有映射关系

注意,当发现有映射关系时,可以选择map集合,因为map集合中存放的就是映射关系

什么时候使用map集合呢?
当数据之间存在映射关系时,就要先想map集合。

思路:
1,将字符串转换成字符数组,因为要对每一个字母进行操作

2,定义一个map集合,因为打印结果的字母有顺序,所以用treemap集合

3,遍历字符数组
 将每一个字母作为键去查map集合
 如果返回null,将该字母和1存入到map集合中
 如返回不是null,说明该字母 在map集合中已经存在并有对应此时
 那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到
 map集合中,覆盖调用原理键所对应的值。

4,将map集合中的数据变成指定的字符串形式返回。

import java.util.*;
class MapTest3 
{
	public static void main(String[] args) 
	{
		String s = charCount("aakb+fc-dabcd1ke,fa");
		System.out.println(s);
	}

	public static String charCount(String str)
	{
		char[] chs = str.toCharArray();

		TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();

		int count = 0;

		for(int x=0; x<chs.length; x++)
		{
			if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))	
				continue;
			Integer value = tm.get(chs[x]);
			if(value!=null)
				count = value;
			count++;
			tm.put(chs[x],count);

			count  = 0;
			
			/*
			if(value==null)
			{
				tm.put(chs[x],1);
			}
			else
			{
				value = value + 1;
				tm.put(chs[x],value);
			}
			*/
		}
		//System.out.println(tm);
		
		StringBuilder sb = new StringBuilder();

		Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
		Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();

		while(it.hasNext())
		{
			Map.Entry<Character,Integer> me = it.next();
			Character ch = me.getKey();
			Integer value = me.getValue();
			sb.append(ch+"("+value+")");
		}

		return sb.toString();
	}
}


集合框架的工具类
Collections

比较对象大小要么compare要么compareTo

 

/*
Arrays:用于操作数组的工具类
里面都是静态方法

asList:将数组变成list集合
*/

import java.util.*;
class ArraysDemo 
{
	public static void main(String[] args) 
	{
		//int[] arr = {2,4,5};

		//System.out.println(Arrays.toString(arr));

		String[] arr = {"abc","cc","kkkk"};
		
		/*
		问:把数组变成list集合有什么好处? 
		答:可以使用集合的思想和方法来操作数组中的元素

		注意:将数组变成集合,不可以使用集合的增删方法。
		因为数组的长度是固定的。
		contains
		get
		indexOf()
		subList()
		如果增删,那么会发生UnsupportedOperationException
		*/
		List<String> list = Arrays.asList(arr);
		//sop("contains:"+list.contains("cc"));
		//list.add("qq");//UnsupportedOperationException

		//sop(list);
		//int[] nums = {2,4,5};
		 
		Integer[] nums = {2,4,5};
		List<Integer>li = Arrays.asList(nums);

		/*
		如果数组中的元素都是对象,那么变成集合时,数组中的元素就
		直接转成集合中的元素。如果数组中的元素都是基本数据类型,
		那么会将该数组作为集合中的元素存在。
		*/
		sop(li);
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}


 

/*
集合变数组
Collection接口中的toArray方法
*/


import java.util.*;
class CollectionToArray
{
	public static void main(String[] args) 
	{
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");

		/*
		1、指定类型的数组到底要定义多长呢?

		(1)当指定类型的数组长度小于了集合的size,那么该方法内部会
		创建一个新的数组,长度为集合的size;

		(2)当指定类型的数组长度大于了集合的size,就不会新创建数组,
		而是使用传递进来的数组,所以创建一个刚刚好的数组最优。

		2、为什么要将集合变数组?
		为了限定对元素的操作。不需要进行增删了。

		*/

		String[] arr = al.toArray(new String[al.size()]);
		sop(Arrays.toString(arr));
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}


 

高级for循环

格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{

}
对集合进行遍历
只能获取集合中的元素,但是不能对集合进行操作。

迭代器除了遍历,还可以进行remove集合中元素的动作
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作

 

传统for和高级for有什么区别呢?

高级for有一个局限性,必须有被遍历的目标。
建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角标。

 

/*
JDK1.5版本出现的新特性

方法的可变参数
在使用时注意:可变参数一定要定义在参数列表最后面
*/

class ParamMethodDemo 
{
	public static void main(String[] args) 
	{
		/*
		int[] arr = {3,4};
		show(arr);

		int[] arr1 = {2,3,4,5};
		show(arr1);
		*/
		//虽然少定义了方法
		//但是每次都要定义一个数组,作为实际参数。
		show(2,4,5,6);
		/*
		可变参数,
		其实就是上一种数组参数的简写形式
		不用每一次都手动的建立数组对象
		只要将要操作的元素作为参数传递即可
		隐饰将这些参数封装成了数组
		*/
	}

	public static void show(int... arr)
	{	
		System.out.println(arr.length);
	}
}


 

/*
StaticImport 静态导入

当类名重名时,需要指定具体的包名
当方法重名时,指定具备所属的对象或者类
*/
import java.util.*;
import static  java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员

import static java.lang.System.*;//导入了System类中所有静态成员

class StaticImport extends Object
{
	public static void main(String[] args) 
	{
		out.println("haha");
		int[] arr = {3,1,5};

		sort(arr);
		int index = binarySearch(arr,1);
		System.out.println(Arrays.toString(arr));
		System.out.println("Index="+index);
	}
}


 

代码下载地址: https://pan.quark.cn/s/a4b39357ea24 在计算机视觉技术中,数据集扮演着训练评估模的核心角色。Labelme作为一个广受欢迎的开源工具,能够支持用户以交互方式对图像进行标注,而COCO(Common Objects in Context)则是一种被广采纳的数据集标准格式,适用于包括物体检测、图像分割在内的多种任务。本文将详细阐述如何将Labelme生成的标注数据转换为COCO数据集的标准格式。 Labelme标注的图像在输出为JSON格式时,会包含以下核心内容: 1. `version`: 指明JSON文件的版本信息。 2. `flags`: 目前未定义或保持为空,预留用于未来的功能扩展。 3. `shapes`: 列表形式存储对象的形状信息,每个形状项包含`label`(对象类别名称),`points`(构成对象边缘的多边形顶点),以及`shape_type`(通常为“polygon”)。 4. `imagePath``imageData`: 提供原始图像的存储路径二进制数据,便于后续图像的还原。 5. `imageHeight``imageWidth`: 明确标注图像的垂直水平尺寸。 COCO数据集的标准格式中定义了三种主要的标注类: 1. Object instances(目标实例):主要用于执行物体检测任务。 2. Object keypoints(目标上的关键点):适用于人体姿态估计相关应用。 3. Image captions(看图说话):用于生成图像的文本描述。 COCO的JSON结构中包含以下基本组成部分: 1. `images`:记录图像的基本属性,包括`height`(高度)、`...
内容概要:本文围绕基于Basisformer模的时间序列锂离子电池SOC(State of Charge,荷电状态)预测展开研究,利用PyTorch深度学习框架构建并训练模,旨在提升锂电池SOC估计的准确性与鲁棒性。该方法融合Transformer架构的核心机制,通过引入基函数(Basis)分解策略,有效捕捉电池充放电过程中长时序、非线性动态特征,增强模对复杂工况的适应能力。研究不仅详细阐述了Basisformer的网络结构设计、注意力机制优化与训练流程,还提供了完整的Python代码实现方案,涵盖数据预处理、模搭建、损失函数定义、训练验证及结果可视化等环节,便于科研人员快速复现、调优并拓展至其他电池状态预测任务。; 适合人群:具备一定深度学习与Python编程基础,熟悉PyTorch框架,从事电池管理系统(BMS)、新能源汽车、储能系统、智能传感等领域的高校研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于动力电池与储能系统的实时SOC估算模块,提升系统安全性与能量利用效率;②作为学术研究的基础模,用于复现、改进基于Transformer的时间序列预测方法在电化学系统中的应用;③为数据驱动的电池健康状态(SOH)、剩余使用寿命(RUL)联合估计提供可扩展的技术框架。; 阅读建议:建议读者结合所提供的代码与公开电池数据集(如NASA、CALCE等)进行动手实践,深入理解模的输入输出结构与时序建模逻辑,同时可尝试引入温度、老化周期等多维特征,或融合物理模构建混合预测架构,以进一步提升预测精度与化能力。
内容概要:本文系统阐述了基于动态规划算法优化插电式混合动力电动汽车(PHEV)能源管理的技术方案,结合Matlab与Simulink工具实现完整的仿真建模与代码开发。通过动态规划这一全局优化方法,在已知驾驶循环条件下,精确求解发动机、电机及电池之间的最优能量分配策略,以实现燃油消耗与排放的最小化目标,解决PHEV多能源路径规划中的复杂决策问题。文中提供了详尽的仿真模构建流程与算法实现步骤,涵盖车辆动力学建模、能量管理架构设计、状态空间定义、代价函数构造、最优控制律求解及结果可视化分析等关键环节,全面揭示PHEV能量管理系统的内在机制与优化逻辑。; 适合人群:具备一定Matlab/Simulink编程基础,从事新能源汽车、智能控制、电力电子、自动化或交通运输工程等相关领域的研究生、科研人员及工程技术人员,尤其适合专注于车辆能量管理策略、节能控制算法研究的专业人士。; 使用场景及目标:①深入掌握动态规划在混合动力汽车能量管理中的理论基础与工程实现方法;②学习如何在Matlab/Simulink环境中搭建PHEV整车仿真平台并实施多目标优化仿真;③为学术研究、学位论文撰写或实际工程项目提供可复用的算法框架、模模板与技术支持,支撑后续对等效燃油消耗最小化策略(ECMS)、模预测控制(MPC)、实时优化算法等的对比研究与性能评估。; 阅读建议:建议读者结合所提供的完整代码与Simulink模文件,逐模块调试运行,重点理解状态变量离散化处理、前后向递推求解过程、惩罚项设置以及边界条件处理等核心技术细节,同时可进一步拓展应用于不同工况场景、不同车结构或与其他优化算法(如庞特里亚金极小值原理PMP)的对比验证,从而深化对PHEV能量管理实时性与全局性平衡问题的理解。
内容概要:本文围绕基于多虚拟同步发电机(VSG)的独立微网系统,开展多目标二次控制策略的MATLAB/Simulink建模与仿真研究。通过构建包含多个VSG单元的独立微网系统,设计并实现了能够同时实现频率与电压的无静差恢复、有功/无功功率精确分配以及环流有效抑制的综合控制目标的二次控制方法。研究重点在于控制策略的整体架构设计、关键控制模块的数学建模及其在Simulink环境中的精细化实现,通过大量仿真实验验证了所提控制策略在不同工况下的有效性、动态响应性能及系统鲁棒性。; 适合人群:具备电力系统分析、自动控制理论及现代电力电子技术等专业知识背景,熟悉MATLAB/Simulink仿真工具,从事新能源发电、微电网运行与控制、分布式能源系统集成等相关领域的科研人员、工程技术人员及高校研究生。; 使用场景及目标:① 深入掌握多VSG独立微网系统的建模方法与稳定性分析要点;② 理解并复现兼顾静态精度与动态品质的多目标二次协同控制算法;③ 为新微网控制保护装置的研发及先进控制策略的工程化应用提供可靠的仿真验证平台技术储备。; 阅读建议:学习者应在巩固电力系统基础理论的前提下,重点关注控制算法的设计逻辑、各控制环节间的耦合关系以及Simulink模块的搭建技巧,建议通过调整系统参数、设置不同的负载投切与故障扰动工况进行反复仿真,以深刻理解控制策略的内在机理与适应能力。
【通用视觉框架】基于Qt+Halcon开发的仿Visionmaster的通用视觉框架软件,全套源码,开箱即用 1.1 背景 ​ 本项目软件开发意图为实现对Halcon、Opencv算子及其它视觉软件的便捷使用,由于HalconOpencv使用相比VisionPro较为麻烦,故此本软件仿照海康VisionMaster的流程图式操作,实现对Halcon、Opencv及其它视觉软件的二次开发。 2.1 软件概述 本软件使用Qt框架进行开发,实现对视觉流程的自由搭配,市场上对标海康威视的VisionMaster; 本软件使用插件化开发框架,可使用提供的二次开发库自行添加新功能算子新模块(将生成的插件放置到对应目录下即可); 2.2 功能概述: 视觉流程图式编程:实现对视觉/数据处理算子的自由编程,从而实现各类复杂的视觉需求 项目读取保存:将编程的视觉项目进行保存或者读取 图像显示:主界面中可以显示及监控视觉算子的图像处理情况 日志消息显示:显示软件运行过程中出现的日志消息 多语言:可进行多种语言切换 2.3 开发平台 主开发语言:Qt(C++) C++语言标椎:C++17 开发环境:Window/Linux 编程平台:Qt Creator 编译器: |版本 | MSVC | Qt 6.4.0 MSVC2019 64bit | | Mingw | Qt 6.4.0 MinGW 64-bit | 视觉工具:Halcon19.11 Progress X64 资源介绍请查阅:https://blog.csdn.net/m0_37302966/article/details/146980317 更多视觉框架资源:https://blog.csdn.net/m0_37302966/article/details/146583453
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值