1:集合
(1)概念理解:
java是一种面向对象语言,因此我们如果要针对多个对象进行操作,就必须创建多个对象并对其进行存储,对多个
对象进行存储,前面学习过数组,不过数组只能存储固定长度的数据,这样数组就不满足要求了,因此,java
提供了集合供我们使用。
集合是存储多个元素的容器
(2)集合的特点
A:长度可以发生改变
B:只能存储引用类型
C:可以存储多种类型的对象
(3)集合和数组的区别
A:长度的区别
数组长度固定
集合长度可变
B:存储元素的区别
数组存储的元素可以是基本类型,也可以是引用类型。
集合存储的元素只能是引用类型。
C:是否同一类型
数组元素类型一致。
集合元素类型可以不一致。
(4)集合体系的由来
(1)集合是存储多个元素的容器,但是,由于数据结构不同,java就提供了多种集合类。而这多种集合类有共性的功能
所以,通过不断的向上抽取,最终形成了集合体系结构。
注意:数据结构就是指数据的存储方式。
(2) 集合体系
|---collection(单列)
|---list(有序,可重复)
|---ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|---Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
|---LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
|---set(无序,唯一)
|---HashSet
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|---TreeSet
底层数据结构是二叉树,
线程不安全,效率高。
怎么保证唯一性的呢?是根据返回值是否是0。
怎么保证排序的呢?两种方式
自然排序(元素具备比较性)
实现Comparable接口
比较器排序(集合具备比较性)
实现Comparator接口
|---Map(双列 底层结构是针对键有效,跟值无关)
|---HashMap
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|---Hashtable
底层数据结构是哈希表,
线程安全,效率低。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|---TreeMap
底层数据结构是二叉树。
线程不安全,效率高。
怎么保证唯一性的呢?是根据返回是否是0。
怎么保证排序的呢?两种方式
自然排序(元素具备比较性)
实现Comparable接口
比较器排序(集合具备比较性)
实现Comparator接口
(3)集合的常见使用步骤:
A:创建集合对象
B:创建元素对象
C:把元素添加到集合中
D:遍历集合
a:通过集合对象获取迭代器对象。
b:通过迭代器对象判断。
c:通过迭代器对象获取。
2:应用。(添加功能,判断功能,删除功能,获取功能,长度功能)
Collection
A:添加功能(掌握)
boolean add(Object obj)://向集合中添加一个元素
boolean addAll(Collection c)://向集合中添加一个集合的元素
B:删除功能(掌握)
void clear()://删除集合中的所有元素
boolean remove(Object obj):从集合中删除指定元素
boolean removeAll(Collection c):从集合中删除一个指定集合的元素
C:判断功能(掌握)
boolean isEmpty():判断集合是否为空
boolean contains(Object obj):判断集合中是否包含指定元素
boolean containsAll(Collection c):判断集合中是否包含一个指定集合中的元素
D:遍历功能(掌握)
Iterator iterator():获取集合中的每一个元素
E:长度功能(掌握)
int size():获取集合中的元素个数
F:交集功能
boolean retainAll(Collection c):判断两个集合中是否有相同的元素
G:转换功能
Object[] toArray():把集合转换成数组
|--List
A:添加功能
void add(int index,Object obj):在指定位置添加元素
B:删除功能
Object remove(int index):根据指定索引删除元素,并把删除的元素返回
C:修改功能
Object set(int index,Object obj):把指定索引位置的值修改为指定的值并返回修改前的值
D:获取功能
Object get(int index):获取指定位置的元素
int indexOf(Object obj):返回指定元素在集合中第一次出现的索引
ListIterator listIterator():列表迭代器
|--Set
Map
A:添加功能
put(Object key,Object value)当key在集合中不存在时,添加元素;当key在集合存在时候,替换元素
B:判断功能
boolean containsKey(Object key)判断指定的键是否在集合中存在
boolean containsValue(Object value)判断指定的值是否在集合中存在
boolean isEmpty():判断集合是否为空
C:删除功能
void clear():清除所有键值对数据。
remove(Object key)根据指定的键删除键值对。
D:获取功能 D:获取功能
Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合。
Object get(Object key):根据键获取值
Set<K> keySet():所有键的集合
E:长度功能
int size()
3:遍历方式
List:
迭代器(在源码中可以看到的,开发中也经常看到)
增强for(开发中看到,JDK5以后用)
普通for
list迭代器
如果仅仅为了遍历,用任意一种即可。一般选择前两种的任意一种。
如果要做修改,或者删除指定位置的元素,或者在指定位置添加元素。用普通for。
Set:
迭代器
增强for
任选一种。
Map:
键找值。
通过键值对找键和值
A:
ArrayList<String> array = new ArrayList<String>();
方式1:
Iterator<String> it = array.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : array){
System.out.println(s);
}
方式3:
for(int x=0; x<array.size(); x++){
String s = array.get(x);
System.out.println(s);
}
方式4
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
if ("hello".equals(s)) {
lit.add("IOS");
}
}
B:
HashSet<String> hs = new HashSet<String>();
方式1:
Iterator<String> it = hs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : hs)
{
System.out.println(s);
}
C:
HashMap<String,Strting> hm = new HashMap<String,String>();
Set<String> set = hm.keySet();
for(String key : set)
{
String value = hm.get(key);
System.out.println(key+"***"+value);
}
5:什么时候用谁?
是否键值对?
是:Map
是否对键排序?
是:TreeMap
否:HashMap
不懂的情况下,使用HashMap。
否:Collection
是否唯一
是:Set
是否对元素进行排序?
是:TreeSet
否:HashSet
不懂的情况下,使用HashSet
否:List
是否要安全:
是:Vector(真正开发中也不用)
List list = Collections.synchronizedList(new ArrayList());
否:ArrayList,LinkedList
查询多:ArrayList
增删多:LinkedList
不懂的情况下,使用ArrayList
6:Collection和Collections的区别?
Collection:是Collection集合的顶层接口,定义了Collection集合的共性方法。
Collections:是一个类,定义了针对Collection集合操作的功能。有排序,查找,反转等。
Collections的功能:
排序:public static void sort(List list)
* 二分查找:public static <T> int binarySearch(List list,T key)
* 反转:public static void reverse(List list)
* 最大值:public static T max(Collection coll)
* 随机置换:public static void shuffle(List list)
7:案例
(1)Collections的功能
public class CollectionsDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<Integer> array = new ArrayList<Integer>();
// 添加元素
array.add(60);
array.add(25);
array.add(38);
array.add(213);
array.add(99);
array.add(22);
System.out.println("array:" + array);
// 排序
// public static void sort(List list)
// Collections.sort(array);
// System.out.println("array:" + array);
// 二分查找
// public static <T> int binarySearch(List list,T key)
// [22, 25, 38, 60, 99, 213]
// int index = Collections.binarySearch(array, 60);
// System.out.println("index:" + index);
// 反转
// public static void reverse(List list)
// [60, 25, 38, 213, 99, 22]
Collections.reverse(array);
System.out.println("array:" + array);
// 最大值
// public static T max(Collection coll)
// Integer i = Collections.max(array);
// System.out.println(i);
// 随机置换:public static void shuffle(List list)
Collections.shuffle(array);
System.out.println("array:" + array);
}
(2)需求:我现在用ArrayList存储多个字符串元素。* 比如说数据如下:
* hello,world,java,hello,.net,java,php,IOS,java,android
* 我要求你写程序,实现去除重复元素。
* 也就是说结果是:
* hello,world,java,.net,php,IOS,android
*
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
public static void main(String[] args) {
//创建旧集合,并添加元素
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
array.add("hello");
array.add(".net");
array.add("java");
array.add("java");
array.add("java");
array.add("php");
array.add("IOS");
array.add("java");
array.add("android");
//创建新集合
ArrayList array2 = new ArrayList();
//遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while(it.hasNext()){
String s = (String)it.next();
//在新集合中判断,看是否存在这个元素
if(!array2.contains(s)){
//如果s不再array2中存在,就添加
array2.add(s);
}
}
//array2就是没有重复元素的集合。
//遍历array2
for(int x=0; x<array2.size(); x++){
String s = (String) array2.get(x);
System.out.println(s);
}
}
}
(3) ArrayList如果存储的是学生,那么,怎么去除重复元素呢?
package cn.itcast_02;
import java.util.ArrayList;
import java.util.Iterator;
/*
* ArrayList如果存储的是学生,那么,怎么去除重复元素呢?
* 问题:如何知道学生是重复的。
* 需求:如果学生的姓名和年龄相同,我就认为是同一个学生。即重复值。
*
* 通过简单分析,我们估计是判断那里出问题了。
* 怎么办呢?
* 看判断的方法。
* 而我们又知道,判断的方法是API提供的。不是自己的写的。
* 看源码,看底层到底怎么实现的。
* 通过看源码,我们发现,底层依赖的是equals()。
* 由于学生类中,我们并没有equals()方法,所以,默认用的是Object的方法。
* 而Object类的方法,默认比较的是地址值。
* 由于学生对象都是new出来的,地址值肯定不一样,所以从这个角度考虑结论是正确的。
* 但是不符合我们的需求。
* 肿么办?
* 重写equals(),让他按照我们的需要来比较。
*/
public class ArrayListTest3 {
public static void main(String[] args) {
ArrayList array = new ArrayList();
Student s1 = new Student("郑成功", 40);
Student s2 = new Student("戚继光", 50);
Student s3 = new Student("戚继光", 50);
Student s4 = new Student("岳飞", 36);
Student s5 = new Student("岳飞", 40);
Student s6 = new Student("林则徐", 30);
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
// 创建新集合
ArrayList array2 = new ArrayList();
// 遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
// 在新集合中判断,看是否存在这个元素
if (!array2.contains(s)) {
// 如果s不再array2中存在,就添加
array2.add(s);
}
}
// array2就是没有重复元素的集合。
// 遍历array2
for (int x = 0; x < array2.size(); x++) {
Student s = (Student) array2.get(x);
System.out.println(s.getName() + "***" + s.getAge());
}
}
}
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object obj) {
// 提高效率
if (this == obj) {
return true;
}
// 提高健壮性
if (!(obj instanceof Student)) {
return false;
}
// 向下转换
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
}
(4)set案例
import java.util.HashSet;
/*
* HashSet存储自定义对象。
* 需求:我们认为一个对象如果成员变量值都相同,则为同一个对象。
*
* 请思考:
* A:哪里出问题了
* 通过简单的分析,我们知道了在add方法出问题了。
* B:怎么解决
* 看源码
* 通过看源码:我们知道,最终的操作跟如下这个判断相关
* if(e.hash == hash && ((k = e.key) == key || key.equals(k)))
* {
* 唯一。
* }
* 分析条件:
* A:这个判断跟对象的hashCode()方法相关。
* B:这个判断跟equals()方法相关。
*
*
* 总结:
* HashSet如何保证元素的唯一性的呢?
* HashSet的底层数据结构是哈希表。
* 它依赖两个方法,hashCode()和equals()。
* 顺序:
* 首先,判断对象的hashCode()值是否相同。
* 相同:
* 继续走equals()。看返回值是true还是false
* A:如果是true,说明有元素重复。该元素不添加到集合。
* B:如果是false,说明元素不重复,该元素添加到集合。
* 不同:就直接添加到集合中了。
*/
public class HashSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashSet<Student> hs = new HashSet<Student>();
// 创建元素对象
Student s1 = new Student("林青霞", 26);
Student s2 = new Student("张曼玉", 36);
Student s3 = new Student("周慧敏", 20);
Student s4 = new Student("林青霞", 26);
Student s5 = new Student("林青霞", 66);
Student s6 = new Student("林志玲", 16);
// 添加元素
hs.add(s1);
// hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
hs.add(s6);
// 遍历
for (Student s : hs) {
System.out.println(s.getName() + "***" + s.getAge());
}
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// @Override
// public int hashCode() {
// // return 0;
// /*
// * name:30,age:40
// * name:20,age:50
// */
// return this.name.hashCode() + this.age*13;
// }
//
// @Override
// public boolean equals(Object obj) {
// // System.out.println(this + "------------------------------" + obj);
// if (this == obj) {
// return true;
// }
//
// if (!(obj instanceof Student)) {
// return false;
// }
//
// Student s = (Student) obj;
// return this.name.equals(s.name) && this.age == s.age;
// }
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
(5)HashMap案例
import java.util.HashMap;
import java.util.Set;
/*
* czbk:
* yr 预热班
* jy 就业班
* 预热班:
* 01 zhangsan
* 02 lisi
* 就业班:
* 01 wangwu
* 02 zhaoliu
*
* Map的嵌套。
*/
public class HashMapDemo {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, HashMap<String, String>> czbk = new HashMap<String, HashMap<String, String>>();
// 创建元素
HashMap<String, String> yr = new HashMap<String, String>();
yr.put("01", "zhangsan");
yr.put("02", "lisi");
czbk.put("yr", yr);
HashMap<String, String> jy = new HashMap<String, String>();
jy.put("01", "wangwu");
jy.put("02", "zhaoliu");
czbk.put("jy", jy);
// 遍历集合
// HashMap<String, HashMap<String, String>> czbk
Set<String> czbkKeys = czbk.keySet();
for (String czbkKey : czbkKeys) {
System.out.println(czbkKey);
HashMap<String, String> czbkValue = czbk.get(czbkKey);
Set<String> bjKeys = czbkValue.keySet();
for (String bjKey : bjKeys) {
String bjValue = czbkValue.get(bjKey);
System.out.println("\t" + bjKey + "***" + bjValue);
}
}
}
8:泛型(理解)(1)泛型是一种把明确类型的工作放在了创建对象或者调用方法时候才去明确的特殊的类型。
(2)格式:
<数据类型>
(3)好处:
A:解决了黄色警告线问题
B:把运行期间的转换异常给提前到了编译期间
C:优化了程序设计,不需要做强制类型转换了
(4)泛型的前世今生
A:泛型类
B:泛型方法
C:泛型接口
(5)泛型的使用:(掌握)
看API中的类或者接口,其后是否跟有<>,如果有,就是泛型的应用。
一般在集合中用。
9:增强for循环(掌握)
(1)格式:
for(数组或者Collection集合的元素类型 变量 : 数组或者Collection集合的对象)
{
直接使用变量即可。
}
(2)好处:
方便了数组和Collection集合的遍历。
(3)注意:
A:增强for是用来替代迭代器的。
B:不要在用增强for遍历集合的时候,用集合对集合本身进行修改。
10:异常(理解)
(1)异常:就是程序出现的不正常情况。
(2)异常体系:
Throwable
|--Error 严重的问题,是处理不了的。要改正代码的。
|--Exception 非RuntimeException的,是需要处理的。编译期异常。
|--RuntimeException 不需要处理的,是需要改代码的。运行期异常。
举例:
Error:
地震,海啸。
Exception:
感冒了,头疼。
注意:
每种体系的子类都是以父亲的名称作为后缀。
XxxError
XxxException
(3)java虚拟机的默认处理方式
把异常的类名,原因,位置等信息显示在控制台。
一旦有异常发生,其后的代码不能继续执行。
(4)异常的解决方案:
A:自己处理
基本格式:
try{
可能发生异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
释放资源的代码;
}
注意:一旦有一次发生,就会立马执行catch里面的代码。
变形格式:
try...catch
try...catch...catch
try...catch...catch...finally
try...finally
JDK7针对多个catch进行了优化:
catch(异常1 | 异常2 | 异常3 ... 变量){}
注意:这些异常必须是平级关系。
和try...catch...catch的不同点是
JDK7的这种方案是必须平级关系,不能有子父关系。
而try...catch...catch父亲放最后是可以的。
B:抛出处理
用throws关键字在方法上声明(抛出)。
C:到底使用谁?
a:能自己处理的尽量自己处理。
b:实在不行,你先抛了在说。上就业班我们对异常是进行统一处理的。
看到问题,点击鼠标。
(5)finally的特点及面试题
A:特点
里面的代码永远会执行。除非前面退出jvm。
B:面试题
a:请说说final,finally,finalize的区别?
final, finally, finalize的区别。
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
finally是异常处理语句结构的一部分,表示总是执行。
内部类要访问局部变量,局部变量必须定义成final类型,例如,一段代码……
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,
可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。
b:finally里面的代码永远会执行吗?
c:假如在catch里面有ruturn,finally里面的代码还能被执行吗?
如果能,请问是在return前,还是在return后?
如果你能说在中间,就更好了。
(6)Exception和RuntimeException的区别?
A:Exception 编译时期异常,必须处理的。
如果在方法上,throws了该类型的异常,将来调用者必须处理。
如果在方法内部,throw了该类型的异常,必须在方法上throws该异常。
B:RuntimeException 运行时期异常,是不需要处理的。要改代码的。
如果在方法上,throws了该类型的异常,不需要处理。
如果在方法内部,throw了该类型的异常,方法上可以throws该异常,也可以不throws该异常。
(7)throw和throws的用法和区别?
A:throw
用法:用在方法内部,后面跟的是异常对象名称。
区别:用throw抛出了编译时期异常,方法上面必须用throws抛出。
用throw抛出了运行时期异常,方法上面可以不用throws抛出。
B:throws
用法:用在方法声明上,后面跟的是异常类名。
区别:用throws在方法上声明了异常,内部可以没有throw
案例
/*
* 面试题:
* 1:请问final,finally,finalize的区别?
* 2:finally里面的代码真的永远会执行吗?
* 会永远执行。但是有一个特殊情况:在代码执行到finally之前,jvm就退出了。
* 3:加入在catch里面有return语句,请问finally里面的代码还会执行吗?如果执行,是在return前,还是return后?
* 会执行。在return前执行。
* 准确答案:在return之间执行。
*/
public class FinallyTest {
public static void main(String[] args) {
// method1();
// method2();
int result = method3();
System.out.println(result);
}
private static int method3() {
int a = 10;
try {
System.out.println(a / 0);
System.out.println("a1:" + a);
} catch (ArithmeticException ae) {
System.out.println("a2:" + a); // a2:10
a = 20;
return a; //这个时候,在内存中就会有一个路径产生,该路径返回值是20.
//但是,它看到了finally代码块,所以,继续执行finally里面的内容
//当finally里面结束后,会回到以前的执行路径。
} finally {
System.out.println("a3:" + a); // a3:20
a = 30;
return a;
}