JAVA基础(二):容器

容器框架

在这里插入图片描述

数组

数组是相同类型数据的有序集合:
1、相同类型的若干个数据,按照一定先后次序排列组合而成。
2、 其中,每一个数据称作一个数组元素
3、每个数组元素可以通过一个下标来访问它们.

数组的特点:
1、 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
2、 其元素必须是相同类型,不允许出现混合类型
3、 数组中的元素可以是任何数据类型,包括基本类型和引用类型。

数组的创建

int[] s = new int[10];
//创建并初始化
int[] a = {1,2,3,4,5};

二维数组
二维数组可以看成以数组为元素的数组

二维数组的创建

int[][] buf = new int[10][10];
int[][] buf = new int[10][];
int[][] buf = new int[][10];//非法

//创建并初始化
int intA[][] = {{1,2},{2,3},{3,4,5}}; 

数组的拷贝:
调用java.lang.System的静态方法

//可以用于数组src从第srcPos项元素开始的length个元素拷贝到目标数组从destPos项开始 的length个位置
 public static void arraycopy (Object src,int srcPos,Object dest,  int destPos,int length) 
 

Arrays类

常用操作

	@Test
	void arrTest() {
		//以字符串形式输出
		int[] buf = {1,3,2,5,4};
		System.out.println(Arrays.toString(buf));//[1, 3, 2, 5, 4]
		//排序
		//Jdk1.8中源码是数据量大采用快排,数据少采用插入排序
		//sort适用于20w以下的数据
		//parallelSort适用于大量数据的排序
		Arrays.sort(buf);
		System.out.println(Arrays.toString(buf));//[1, 2, 3, 4, 5]
		
		int[] tmp = new int[5];
		System.arraycopy(buf, 0, tmp, 0, 5);
		System.out.println(Arrays.toString(tmp));//[1, 2, 3, 4, 5]
		System.out.println(tmp.toString());//默认toString输出的是tmp的hash值
		//二分查找
		System.out.println(Arrays.binarySearch(buf, 3));//2
	
	}

关于Arrays还有一些比较少使用的方法可以翻一下文档

JAVA中的数组跟其他语言定义概念基本一样
总结:
数组的特点:
长度固定,连续空间,存储同一种类型数据
for-each循环:简单、主要用于遍历操作
优点:按照索引查询效率高
缺点:添加删除元素效率低;按照内容查询效率低(无序)

集合

当我们需要将一些相同结构的个体整合在一起时,就可以考虑使用集合了
集合和数组相似点:
都可以存储多个对象,对外作为一个整体存在
数组的缺点:
1、长度必须在初始化时指定,且固定不变
2、数组采用连续存储空间,删除和添加效率低下
3、数组无法直接保存映射关系
4、数组缺乏封装,操作繁琐

关于集合的架构:
在这里插入图片描述

List

在这里插入图片描述
特点:有序 不唯一(可重复)
ArrayList 线性表中的顺序表 :
1、 在内存中分配连续的空间,实现了长度可变的数组
2、 优点:遍历元素和随机访问元素的效率比较高
3、 缺点:添加和删除需大量移动元素效率低,按照内容查询效率低
LinkedList 线性表中双向链表 :
1、采用双向链表存储方式。
2、 缺点:遍历和随机访问元素效率低下
3、优点:插入、删除元素效率比较高

ArrayList基本操作

	@Test
	void ListTest() {
		List<Integer> arrlist = new ArrayList<>();
		arrlist.add(1);
		arrlist.add(3);
		//必须是顺序插入
		arrlist.add(2,5);
		if(arrlist.contains(3)) {
			System.out.println("Yes");
		}
		System.out.println(arrlist.get(1));
		System.out.println(arrlist.get(2));
		arrlist.remove(Integer.valueOf(5));
		System.out.println(arrlist.toString());//[1, 3]
		//根据索引更改
		arrlist.set(1, 2);
		System.out.println(arrlist.toString());//[1, 2]
		//链表转换成数组
		Object[] arr =  arrlist.toArray();
		System.out.println(arr[0]);
	}

ArrayList虽然常用,但是关于ArrayList的坑还是不少的
通过Arrays的asList转换成List集合,需要注意的坑(巨坑

	@Test
	void ListTest() {
		String[] arr = {"hello","java"};
		List<String> list =  Arrays.asList(arr);
		list.add("Hello world");
	}

简单地add操作,报了一个奇怪的异常
在这里插入图片描述
就连内部方法中,方法也是返回ArrayList
在这里插入图片描述实际上Arrays中返回的ArrayList跟我们用的ArrayList并不是同一个
这是Arrays下的ArrayList
在这里插入图片描述
实际上,我们要用到的是java.util.ArrayList
在这里插入图片描述
区别:
Arrays.ArrayList和java.util.ArrayList都是继承AbstractList<>,但是Arrays.ArrayList没有重写父类的方法,所以没有add等方法

坑2:

	String[] arr = {"hello","java"};
	List<String> list =  Arrays.asList(arr);
	list.set(1, "hi");
	for (String string : list) {
		System.out.println(string);//hello	hi
	}

在更改list的内部,会对原数组产生影响,主要是因为Array.asList内部还是使用了arr原始数组,所有的操作还是对arr原始数组进行操作,所以无论使更改arr还是更改Array.asList的list内部都是对原始数组操作
在这里插入图片描述结局方法:
1、在外部封装一层真正的ArrList,简称套娃操作

List<String> list2 = new ArrayList<>(Arrays.asList(arr));

2、采用Google的Guava Lists包的方法

List<String> list = List.newArrayList(arrays);

如果之后马代码的时候出现UnSupportedOperationException,大概率是这个问题了

测试代码

@Test
	void ListTest() {
		String[] arr = {"hello","java"};
		List<String> list =  Arrays.asList(arr);
		for (String string : list) {
			System.out.println(string);
		}
		list.add("Hello world");
		list.set(1, "hi");
		for (String string : list) {
			System.out.println(string);
		}
		
		List<String> list2 = new ArrayList<>(Arrays.asList(arr));
		
	}

Vector

内部实现跟ArrayList差不多,但是Vector是线程同步的

LinkedList

采用双向链表存储方式。
基本操作跟 ArrayList 差不多

ArrayList、LinkedList、Vector对比

1、ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
2、Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
3、LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
4、vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。

5、如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。

6、如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用Linkedlist,因为它移动一个指定位置的数据所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。
7、ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动 等内存操作,所以索引数据快插入数据慢, Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

Set

特点:无序 唯一(不重复)

HashSet

采用Hashtable哈希表存储结构
1、优点:添加速度快 查询速度快 删除速度快
2、缺点:无序
内部就是一个HashMap,到HashMap的时候再细讲

LinkedHashSet

1、 采用哈希表存储结构,同时使用链表维护次序
2、 有序(添加顺序)
也属于Hash的存储方式
在这里插入图片描述

TreeSet

1、 采用二叉树(红黑树)的存储结构
2、优点:有序 查询速度比List快(按照内容查询)
3、 缺点:查询速度没有HashSet快
在这里插入图片描述Set无序:
1、无法使用for进行遍历(因为无序,所以没有get(i))
2、HashSet、HashMap或Hashtable中对象唯一性判断 :hashCode唯一
3、具体存储方式可以看我的博客—>数据结构与算法:哈希哈希实现
4、基本操作跟HashMap差不多

public static void main(String[] args) {
		Set<String>  set1 = new HashSet<>();
		
		set1.add("aa");
		set1.add("bb");
		set1.add("aa");
		System.out.println(set1);
		set1.remove("bb");
		System.out.println(set1);
		
	
		Set<String>  set2 = new HashSet<>();
		set2.add("hello");
		set2.addAll(set1);
		System.out.println(set2);
	}
public static void main(String[] args) {
		Set<Integer>  set = new TreeSet<>();
		
		set.add(300);
		set.add(200);
		set.add(600);
		
		//按照元素递增的方式排好序
		for(Integer m:set){
			System.out.println(m);
		}
		
		Set<Emp2>  set2 = new TreeSet<>();
		set2.add(new Emp2(100,"张三",3000));
		set2.add(new Emp2(50,"李四",2000));
		set2.add(new Emp2(150,"王五",8000));
		set2.add(new Emp2(30,"赵六",20000));
		
		for(Emp2 m:set2){
			System.out.println(m);
		}
		
	}
}



class Emp2  implements Comparable<Emp2>  {
	int id;
	String name;
	double salary;
	
	public Emp2(int id, String name, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
	}

	@Override
	public String toString() {
		return  "id:"+id+",name:"+name+",salary:"+salary;
	}
	
	@Override
	public int compareTo(Emp2 o) {		//负数:小于,0:等于,正数:大于
		
		if(this.salary>o.salary){
			return 1;
		}else if(this.salary<o.salary){
			return -1;
		}else{
			if(this.id>o.id){
				return 1;
			}else if(this.id<o.id){
				return -1;
			}else{
				return 0;
			}
		}
		
	}

Map

Map:
key-value映射 ,以Key->value存储

HashMap

Key 无序 唯一 (Set)
Value 无序 不唯一 (Collection)

LinkedHashMap

有序的HashMap 速度快

TreeMap

有序 速度没有hash快

Set和Map有关系吗?
采用了相同的数据结构,只用于map的key存储数据,就是Set

用hashMap模拟数据库的存储

public static void main(String[] args) {
		
		Map<String,Object>  row1 = new HashMap<>();
		row1.put("id", 1001);
		row1.put("姓名", "张三");
		row1.put("薪水", 20000);
		row1.put("入职日期", "2010.5.5");
		
		Map<String,Object>  row2 = new HashMap<>();
		row2.put("id", 1002);
		row2.put("姓名", "李四");
		row2.put("薪水", 30000);
		row2.put("入职日期", "2000.4.4");
		
		Map<String,Object>  row3 = new HashMap<>();
		row3.put("id", 1003);
		row3.put("姓名", "王五");
		row3.put("薪水", 3000);
		row3.put("入职日期", "2018.5.4");
		
		List<Map<String,Object>>   table1 = new ArrayList<>();
		table1.add(row1);
		table1.add(row2);
		table1.add(row3);
		
		for(Map<String,Object> row:table1){
			
			Set<String> keyset = row.keySet();
			//keyset遍历
			for (String key : keyset) {
				System.out.print(key+":"+row.get(key)+"\t");
			}
			System.out.println();
		}
 
		
		
		
	}

用TreeMap模拟

public static void main(String[] args) {
		Map<Integer,String>  treemap1 = new TreeMap<>();
		treemap1.put(20, "aa");
		treemap1.put(3, "bb");
		treemap1.put(6, "cc");
		
		//按照key递增的方式排序
		for(Integer  key:treemap1.keySet()){
			System.out.println(key+"---"+treemap1.get(key)); 
		}
		
		
		Map<Emp,String>  treemap2 = new TreeMap<>();
		treemap2.put(new Emp(100,"张三",50000), "张三业绩不错");
		treemap2.put(new Emp(200,"李四",5000), "李四工作不积极");
		treemap2.put(new Emp(150,"王五",6000), "王五经常迟到");
		treemap2.put(new Emp(50,"赵六",6000), "赵六代码写的好");
		
		//按照key递增的方式排序
		for(Emp  key:treemap2.keySet()){
			System.out.println(key+"---"+treemap2.get(key)); 
		}		
		
	}
}

class Emp  implements Comparable<Emp>  {
	int id;
	String name;
	double salary;
	
	public Emp(int id, String name, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
	}

	@Override
	public String toString() {
		return  "id:"+id+",name:"+name+",salary:"+salary;
	}
	
	@Override
	public int compareTo(Emp o) {		//负数:小于,0:等于,正数:大于
		
		if(this.salary>o.salary){
			return 1;
		}else if(this.salary<o.salary){
			return -1;
		}else{
			if(this.id>o.id){
				return 1;
			}else if(this.id<o.id){
				return -1;
			}else{
				return 0;
			}
		}
		
	}

Map有很多方法,用到的时候看看文档,内部存储和实现可以看数据结构的课程

Iterator

Iterator:所有集合类均未提供相应的遍历方法,而是把把遍历交给迭代器完成。迭代器为集合而生,专门实现集合遍历
Iterator是迭代器设计模式的具体实现,本质是实现了Iterable接口

List<String>  list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");

//使用iterator遍历List
for(Iterator<String> iter=list.iterator();iter.hasNext();){
	String  temp = iter.next();
	System.out.println(temp);
}

Set<String>  set = new HashSet<>();
set.add("aa");
set.add("bb");
set.add("cc");
		
//使用iterator遍历Set
for(Iterator<String> iter=set.iterator();iter.hasNext();){
	String  temp = iter.next();
	System.out.println(temp);
}
Map<Integer,String> map1 = new HashMap<>();
map1.put(100, "aa");
map1.put(200, "bb");
map1.put(300, "cc");
		

//第一种遍历Map的方式
Set<Entry<Integer,String>>  ss =  map1.entrySet();
for(Iterator<Entry<Integer,String>> iter=ss.iterator();iter.hasNext();){
	Entry<Integer,String> temp = iter.next();
	
	System.out.println(temp.getKey()+"--"+temp.getValue());
	
}
System.out.println("++++++++++++++++++++++++");
//第二种遍历Map的方式
Set<Integer>  keySet = map1.keySet();
for(Iterator<Integer> iter=keySet.iterator();iter.hasNext(); ){
	Integer key = iter.next();
	System.out.println(key+"----"+map1.get(key));
}

总结
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值