递归和迭代:
示例:分别使用递归和迭代实现n!=n*(n-1)*(n-2)...*2*1;
递归:调用自身来实现运算,采用栈来记录。缺点:占用空间大,栈太深的话容易导致堆栈溢出。
迭代:代码没有递归看着简洁,但是空间占用小,效率高。
fail-fast和fail-safe:
java.util包下面的所有的集合类都是fail-fast的,而java.util.concurrent包下面的所有的类都是fail-safe的。fail-fast的迭代器会抛出ConcurrentModificationException异常,而fail-safe的迭代器永远不会抛出这样的异常。
fail-fast:在源数据的基础上遍历。单线程下一边遍历一边修改或多线程下一个线程正在遍历一个线程却要修改数据,都会抛出ConcurrentModificationException异常。使用类:HashMap,ArrayList,HashSet。
fail-safe:在源数据的拷贝上遍历。缺点:开销大,无法保证正在读取的数据是原始对象中的最新数据。使用类:CopyOnWriteArrayList,ConcurrentHashMap。
集合:
一种用来存放对象的容器。
Collection接口下:
Set
用于处理数据集合,且要求存入的对象数据不重复。
遍历方法一:迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String string = iterator.next();
System.out.print(string + " ");
}
遍历方法二:增强型for循环,推荐用这个
for (Object obj : set) {
System.out.print(obj);
}
示例:获取一个字符串中出现了多少个单词。
HashSet:实现了Set接口,内部采用HashMap实现。特点:无序性,不重复性。
存储原理:当向Set中添加对象时,首先调用对象的hashCode()方法,计算哈希值,这个哈希值决定了对象在Set中存放的位置;若位置没有被存储则直接把对象添加进去,若位置已被占用则通过对象的equals()方法比较两个对象的值是否相同,不同的时候对象才会被添加。
因此!若要set识别类的对象的元素是否相同,必须在这个类中重写hashCode和equals方法。
示例:多个student类的对象存在重复的学号和姓名,在set中过滤相同信息。
LinkedHashSet:在HashSet的基础上添加了链表,使得遍历集合时会按添加时的顺序返回元素,但元素在存储的时候仍然是无序的。
TreeSet:实现了Set接口,内部采用TreeMap实现。特点:可对元素进行排序,不重复性。
Set排序:
使用Set存放对象时
当用HashSet存放对象时,为避免存放对象的值相同,使用compareTo时无法比较,只能使用equals和hashCode。
当使用TreeSet存放对象时,实现Compareable接口并重写compareTo就可以。
排序方式:
1、自然排序(默认)
被排序的类必须实现Comparable接口的compareTo方法。单个对象内容排序的时候可以不写。
2、比较器排序(实现Comparator接口的compare方法,仅用于TreeSet。)
写一个实现了Comparator接口的类,把这个类作为TreeSet的参数传进去,TreeSet将优先按照这个类中定义的compare方法对元素进行排序。
List
用于处理序列,记录每个存入对象的索引顺序,并可依据索引返回对象。
遍历方法一:迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String string = iterator.next();
System.out.print(string + " ");
}
遍历方法二:增强型for循环(推荐)
for (Object obj : list) {
System.out.print(obj);
}
遍历方法三:一般for循环
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
遍历方法四:lamada表达式
list.forEach(String ->{
System.out.println(String);
});
ArrayList:数据模型:数组。特点:查找快,增删相对慢。
示例:在ArrayList中添加列表数据,并输出结果。
LinkedList:数据模型:双向链表。特点:增删快,查找相对慢(尤其不推荐用方法三去查找数据)。另外提供了操作表头和表尾的方法,因此可以当成队列、栈使用。
示例1:在LinkedList中添加列表数据,并输出结果。
示例2:把LinkedList当成栈来使用,实现斐波那契数列。
Vector(了解):数据模型:动态数组。特点:需要拓展数组的时候用。与ArrayList不同,Vector在操作数据的方法上都添加了synchronized,即某一时刻只有一个线程能够修改Vector,有效避免多线程环境下的脏数据,同时,访问速度比ArrayList慢。
示例:使用Vector实现增加数据、遍历数据、移除数据。
Stack(八辈子用不着一回系列):数据模型:栈。特点:FILO(先进后出)。
List排序:
1、自然排序(默认)
被排序的类实现Comparable接口的compareTo方法。单个对象内容排序的时候可以不写。调用Collections.sort(list)即可。
2、比较器排序(实现Comparator接口的compare方法)
写一个实现了Comparator接口的类A,把这个类作为Collections.sort(list, new A());的第二个参数传进去即可。
Map接口下:
Map(可以放List,String,Interage)
用于处理键值对。
遍历方法一(只需要key或value):如果key相同则输出的是最新覆盖的值,Set则是添加第一个,之后相同的值则不会添加
for(Object object : map.keySet()) {
System.out.println("key: " + object);
}
for(Object object : map.values()) {
System.out.println("value: " + object);
}
遍历方法二:
for(Object object : map.keySet()) {
System.out.print("key: " + object);
System.out.println(", value: " + map.get(object));
}
遍历方法三(推荐):
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
}
遍历方法四(遍历时需要删除元素时,推荐使用):
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
}
遍历方法五(lambda表达式):
map.forEach((key, value) -> {
System.out.println("key: " + key + ", value: " + value);
});
HashMap:
非线程安全,高效,支持null值。多线程环境下,可用Map<String, String> map2 = Collections.synchronizedMap(map);实现线程安全,或者改用ConcurrentHashMap。
示例:放点值,看结果。
HashTable(已过时,但经常被拿来与HashMap比较):
线程安全(内部方法基本都以synchronized修饰),低效,不支持null值
示例:看源码注释,了解一下什么情况下用什么类替代HashTable。
不考虑线程安全时可以用HashMap替代HashTable,考虑线程安全时用ConcurrentHashMap替代HashTable
LinkedHashMap(了解):遍历时将元素按照放入的顺序输出。
示例:与HashMap存储相同的数据,输出结果。
TreeMap(了解):键的部分按照顺序排序。
示例:Map<String, String>正序输出、lambda倒序输出。
Properties:继承自HashTable,经常用于读取.properties、.xml等配置文件信息。
示例:读取properties文件,读取XML文件。
泛型:
1、限制集合中存放的对象类型;
2、方法中的泛型;
3、自定义泛型;