`

Java学习系列(七)Java面向对象之集合框架详解(上)

 
阅读更多

Java集合

有时也将集合称为容器类,它的作用就是用来“装对象”的。这里要注意的是集合也可以是对象。下面先看一张图:

HashSet:底层用一个数组存元素 --而且这个数组的长度永远是2的N次方。

HashSet底层就是HashMap实现的。
HashSet的构造器:HashSet(int initialCapacity, float loadFactor)
--initialCapacity:控制底层数组的长度。
如果传入数组长度不是2的N次方,HashSet会自动扩展到2的N次方。
--loadFactory:当HashSet感觉到底层数组快满时,它会再次创建一个长度是原来数组长度2倍的数组。原有的数组就变成垃圾,并且要把原有数组中的元素复制到新数组中,这个过程也叫“重hash”。loadFactory越小,越耗内存;loadFactory越大,性能越低。

举例说明1:

 

public class Test {
	public static void main(String[] args) {
		//没有泛型限制的集合
		Collection c1 = new HashSet();	
		c1.add(1);//本来1不是对象,无法装入集合,但由于jdk提供的自动装箱功能,它会将1包装成对象
		c1.add(new Date());
		//加入泛型限制的集合,意味着该集合只能装“指定类型”的对象。
		//jdk1.7可使用"菱形语法"将new HashSet<String>换成new HashSet<>
		Collection<String> c2 = new HashSet<String>();
		//c2.add(1);错误:只能装String类型的对象
		c2.add("张三");
		c2.add("李四");
		c2.add("王五");
		//判断集合是否包含指定元素
		System.out.println(c2.contains("张三"));
		System.out.println(c2.contains("赵六"));
		//遍历Set集合,有两种方式:1)foreach循环,2)迭代器
		System.out.print("使用foreach循环遍历:");
		for(String e : c2){
			System.out.print(e+" ");
		}
		Iterator<String> it = c2.iterator();
		System.out.print("\n使用迭代器遍历:");
		while(it.hasNext()){
			System.out.print(it.next()+"  ");
		}
		System.out.println();
		Collection<String> c3 = new HashSet<String>();
		c3.add("张三");
		c3.add("王五");
		c3.add("赵六");
		//求差集c2-c3
//		c2.removeAll(c3);
//		System.out.println("c2与c3差集:"+c2);
		//求并集
//		c2.addAll(c3);
//		System.out.println("c2与c3并集"+c2);
		//求交集
		c2.retainAll(c3);
		System.out.println("c2与c3交集:"+c2);
	}
}

 

举例说明2:

 

public class TestHashSet {
	public static void main(String[] args) {
		HashSet<String> hs = new HashSet<String>(3);//底层数组容量会自动会展到4(注意:2的N次方)
		hs.add("1");
		hs.add("2");
		hs.add("3");
		hs.add("4");
		hs.add("5");
		//当HashSet感觉到底层数组快满时,它会再次创建一个长度是原来数组长度2倍的数组,此时新的数组长度为8
		System.out.println(hs);
	}
}

 

HashSet存入机制:

1)当有元素加进来时,HashSet会调用该对象的hashCode()方法,得到一个int值;

2)根据hashCode()返回的int值,计算出它在HashSet的存储位置(数组中的索引);

3)如果要加入的位置是空的,直接方法即可。如果要加入的位置已经有元素,此处就会形成“链表”,数组越满,就越有可能出现链表。

HashSet取元素机制:

1)当有元素加进来时,HashSet会调用该对象的hashCode()方法,得到一个int值;

2)根据hashCode()返回的int值,计算出它在HashSet的存储位置(数组中的索引);

3)如果该位置恰好是要找的元素,直接取出即可。如果该位置有“链表”,HashSet要“挨个”地搜索链表里的元素。

HashSet怎么才会认为两个对象是相等的?(要求自定义类的hashCode()和equals()方法是一致的,即方法中所用到的关键属性要一致)

1、两个对象的hashCode()返回值相等;

2、两个对象通过equals比较返回true。

LinkedHashSet(HashSet的一个子类):它与HashSet的存储机制相似,但LinkedHashSet额外地有一个链表,这个链表可以保证LinkedHashSet能记住元素的添加顺序。

TreeSet(sortedset接口的实现类):它保证Set里添加的元素后是“大小排序”的。底层用一个“红黑树”存放元素。

举例说明(使用TreeSet要求集合元素必须是可以比较大小的):

 

public class TestTreeSet1 {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<Integer>();
ts.add(3);
ts.add(1);
ts.add(2);
ts.add(5);
ts.add(4);
System.out.println(ts);
}
}
public class TestTreeSet2 {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>();
		ts.add("t");
		ts.add("r");
		ts.add("e");
		ts.add("e");
		System.out.println(ts);//字符串的大小
	}
}

TreeSet元素存入、检索的性能也比较好。
Java的比较大小有两种方式:
A. --自然排序。所有集合元素要实现Comparable接口。
B. --定制排序。要求创建TreeSet时,提供一个Comparator对象(负责比较元素大小)。
举例说明:

 

 

class Apple implements Comparable<Apple> {
	private double weight;// 规定:苹果重量大的苹果越大

	public Apple(double weight) {
		this.weight = weight;
	}

	@Override   //自然排序
	public int compareTo(Apple obj) {
		return this.weight > obj.weight ? 1 : this.weight < obj.weight ? -1 : 0;
	}
     
	@Override
	public String toString() {
		return "Apple[weight=" + this.weight + "]";
	}
}

public class TreeSetTest {

	public static void main(String[] args) {
		TreeSet<Apple> set = new TreeSet<Apple>();
		set.add(new Apple(2.3));
		set.add(new Apple(1.2));
		set.add(new Apple(3.5));
		for (Apple ele : set) {
			System.out.println(ele);
		}
	}
}
class Bird {
	private String name;

	public String getName() {
		return name;
	}

	public Bird(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Bird[name=" + name + "]";
	}
}

public class TreeSetTest2 {

	public static void main(String[] args) {
		// 如果集合元素本身没有实现Comparable接口
		// 那就要求创建TreeSet时传入一个Comparator对象
		TreeSet<Bird> set = new TreeSet<Bird>(new Comparator<Bird>() {
			@Override
			public int compare(Bird o1, Bird o2) {
				if (o1.getName().compareTo(o2.getName()) > 0) {
					return -1;
				} else if (o1.getName().compareTo(o2.getName()) < 0) {
					return 1;
				} else {
					return 0;
				}
			}
		});
		set.add(new Bird("aabc"));
		set.add(new Bird("abc"));
		set.add(new Bird("Z"));
		set.add(new Bird("dx"));
		System.out.println(set); 
	}
}

ArrayList(JDK1.2)与Vector(JDK1.0,已经过时)都是基于数组实现的,它们的区别如下:
ArrayList(可根据索引来存取元素)是线程不安全的,Vector是线程安全的。
--ArrayList的性能比Vector要好,即使在多线程环境下,可以使用Collections集合工具类的synchronizedXxx方法把ArrayList包装成线程安全的。

 

而LinkedList底层是基于链表实现的,通常认为它的性能比不上ArrayList,它们的区别如下:

ArrayList:由于可以根据底层数组的索引存取元素,所以性能非常快,但当插入元素、删除元素时性能低。

LinkedList:由于底层采用了链表来存储元素,因此根据索引存取元素性能较慢,但当插入、删除元素时性能非常快。
举例说明:

 

public class Test {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("2");
		list.add("1");
		list.add("5");
		list.add("3");
		System.out.println(list);
		list.add(2,"在索引2处插入元素");
		System.out.println(list);
		list.set(2,"在索引2处替换的元素");
		System.out.println(list);
		list.remove(2);
		System.out.println(list);
		//遍历list(类似数组)
		for(int i =0;i<list.size();i++){
			System.out.print(list.get(i)+"   ");
		}
	}
}

Deque集合:功能被限制的线性表。

 

 

//把Deque当成栈用
public class Test {
	public static void main(String[] args) {
		//把Deque当成栈用
		Deque<String> dq = new ArrayDeque<String>();
		//进栈(压栈):后进先出
		dq.push("a");
		dq.push("b");
		dq.push("c");
		dq.push("d");
		//打印首先出栈的元素
		System.out.println(dq.pop());
		//打印访问栈顶的元素
		System.out.println(dq.peek());
	}
}
//把Deque当成队列用:先进先出
public class Test2 {
	public static void main(String[] args) {
		//把Deque当成队列用:先进先出
		Deque<String> dq = new ArrayDeque<String>();
		//从队列尾部入队
		dq.offer("a");
		dq.offer("b");
		dq.offer("c");
		dq.offer("d");
		//从队列头部出队
		System.out.println(dq.poll());
		//打印访问队头元素
		System.out.println(dq.peek());
	}
}

Collections集合工具类:

public class TestCollections {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		System.out.println(list);
		//对集合进行反转
		Collections.reverse(list);
		System.out.println(list);
		//把b, c位置进行交换
		Collections.swap(list, 1, 2);
		System.out.println(list);
		//将list集合元素进行随机排列
		Collections.shuffle(list);
		System.out.println(list);
		
	}
}

 

 

结束语

今天内容比较多,而且有些和数据结构相关,所以理解起来可能会有些困难。编程我觉得还是要多练,只要你肯多练,就不会那么难了。今天就讲到这,明天开始讲Map。

分享到:
评论

相关推荐

    Java基础知识点总结.docx

    七、 接口(面向对象特征之一)★★★★ 28 八、 多态(面向对象特征之一)★★★★ 30 九、 java.lang.Object 31 十、 异常★★★★ 34 十一、 包(package) 37 十二、 多线程★★★★ 39 为什么要使用多线程 39 ...

    免费超全面的Java基础类型,容器,并发,IO流,面向对象,Web编程等代码总结

    Java基础类型,容器,并发,IO流,面向对象,Web编程等代码总结。 2、分类文档 JVM虚拟机 JVM特点,结构与执行周期 JVM类加载机制 JVM运行时区数据 JVM执行引擎和垃圾回收 基础语法 理解Java中对象基础Object类 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    Java编程老鸟潜心写作,奉献高效率的Java学习心得 完全站在没有编程经验读者的角度,手把手教会读者学习Java 配16小时多媒体教学视频,高效、直观 一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    Java编程老鸟潜心写作,奉献高效率的Java学习心得 完全站在没有编程经验读者的角度,手把手教会读者学习Java 配16小时多媒体教学视频,高效、直观 一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让...

    java基础案例与开发详解案例源码全

    11.1 Java集合框架概述264 11.2 Collection接口264 11.2 Set接口实现类266 11.2.1 实现类HashSet267 11.2.2 实现类LinkHashSet270 11.2.3 实现类TreeSet272 11.3 List接口实现类277 11.3.1 实现类ArrayList277 ...

    Java 基础核心总结 +经典算法大全.rar

    continue 语句面向对象 类也是-种对象对象的创建 属性和方法 构造方法 方法重载 方法的重写 初始化 类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限...

    46道java基础知识面试题详解含答案(值得珍藏)

    例如,对于面向对象编程的概念、异常处理机制、集合框架的使用等方面的知识,如果求职者能够清晰地解释并给出相应的示例代码,就能够让面试官了解到其扎实的技术基础和良好的编程习惯。 其次,熟练掌握Java基础知识...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    本书为中南大学精品教材立项项目,分为上下两篇共21章,涵盖了面向对象技术中Java开发环境配置、程序设计基础、面向对象原理以及UML的知识。本书使用的开发环境是JDK 1.6+Eclipse 3.3+Rational Rose 2003,逐步引领...

    Java基础最全笔记文档

    7. 面向对象基础 8. 常用API 9. 综合项目实战 Java加强篇包括: 1. static、单例设计、继承 2. 权限修饰符、常量、枚举、抽象类 3. 多态、内部类、常用API 4. 日期与时间、日期类、包装类、正则表达式、Arrays 类、...

    Java基础详解(入门级)

    第七章:集合框架(容器)+其他类对象使用 139-199 第八章:IO 流 199-280 第九章:GUI 编程 280-284 第十章:网络编程 284-309 第十一章:反射机制 310-315 第十二章:正则表达式 315-322 第十三章:HTML ...

    Week02学习源码(配合博文笔记使用)

    面向对象,继承多态,接口....api文档使用,集合 1.static关键字、继承 2.封装以及抽象类 3.内部类(了解) 4.常用类库 5.常用类库(Date Calender SimpleDateFormat) 6.集合框架 7.自写工具类:Date &lt;-&gt; ...

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    Java开发技术大全 电子版

    第2篇Java面向对象编程 第3章对象和类98 3.1面向对象的基本概念98 3.1.1对象98 3.1.2类99 3.1.3消息101 3.1.4面向对象的4个基本特征101 3.2类与对象104 3.2.1类的基本结构104 3.2.2类的声明104 3.2.3创建...

    asp.net知识库

    与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable 与DotNet数据对象结合的自定义数据对象设计 (一) 数据对象与DataRow ASP.NET中大结果集的分页[翻译] .net 2.0 访问Oracle --与Sql Server的...

    低清版 大型门户网站是这样炼成的.pdf

    1.4 ssh 2组合框架—门户网站开发之首选 28 1.4.1 mvc混血宠儿struts 2 28 1.4.2 幕后的财政部长spring 2.5 30 1.4.3 orm中间件香馍馍hibernate 3.2 31 1.5 小结 32 第2章 mvc混血宠儿struts 2 33 2.1 初识mvc...

    《电动力学(第二版)》(郭硕鸿) 习题答案doc

    Visual C++面向对象与可视化程序设计.ppt 本周上传用户排名 108个mirage1982 100个wkkys 87个gouyue 86个samsho2 61个ynsky 55个zhong_jianyu 49个lei_zhimin 45个lukarl592 43个fosoyo 39个MobilityFans 28个...

    Scala程序设计(第2版)

    8.8 调用父类构造器(与良好的面向对象设计) 226 8.9 嵌套类型 230 8.10 本章回顾与下一章提要 232 第9章 特征 233 9.1 Java 8中的接口 233 9.2 混入trait 234 9.3 可堆叠的特征 238 9.4 ...

    深入浅出ES6 简体中文

    整个系列的翻译历时150余天,坚持专栏翻译的日子艰苦也快乐,编辑徐川细心地帮我审校每一篇文章,编辑丁晓昀赠予钱歌川先生详解翻译之著作让我大开眼界,与李松峰老师的交流也让我深刻理解了“阅读、转换、表达”的...

Global site tag (gtag.js) - Google Analytics