1>List集合特有的功能
void add(int index,E element) 在指定位置添加元素
E remove(int index) 删除指定位置的元素
E get(int index) 获取指定位置元素
E set(int index,E element) 修改指定位置的元素
2> List集合的遍历
掌握size和get方法的应用
List list = new ArrayList();
list.add(new Student(“aa”,23));
list.add(new Student(“ab”,23));
list.add(new Student(“ac”,23));
for(int i=0;i<list.size();i++){
Object obj = list.get(i);
sysout(obj);
}
3>并发修改异常
》如果对一个集合要一边遍历,一边添加元素,使用ListIterator这个类来实现
》ListIterator提供一个add方法来添加元素,
》ListIterator与Iterator这两个接口的关系继承
4>ListIterator的其它方法
hasPrevious方法 : 判断是否有上一个元素
previous方法: 获取上一个元素
=代码样式===========
ListIterator iterator = list.listIterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("=========");
while(iterator.hasPrevious()){//判断是否有上一个元素
//取出上一个元素
Object obj = iterator.previous();
System.out.println(obj);
}
===========================================================================
-
Vector
Vector实现List接口,方法基本上都添加了同步的声明,所以它是线程安全,性能差
Vector在开发中用的比较少 -
数据结构-数组和链表
数组:查找和修改快,增加删除慢
链表:查找和修改慢,增加删除快
7. 集合之间的区别:
一、Vector和ArrayList的区别
Vector是线程安全的,效率低
ArrayList是线程不安全的,效率高
共同点:都是数组实现的
二、ArrayList和LinkedList的区别
ArrayList底层是数组实现,查询和修改快
LinkedList底层是链表结构实现,增和删比较快,查询和修改比较慢
共同点:都是线程不安全的
三、List有三个子类,我们到底使用谁呢?
查询多用ArrayList
增删多用LinkedList
如果都多ArrayList
8. 去除ArrayList中重复元素
去除字符串:
思路-创建一个新集合,遍历旧的集合,把每一个元素添加到新的集合
在添加到新的集合前,要判断这个元素是否在新的集合中已经存在(contains方法)
去除自定义对象:
思路-创建一个新集合,遍历旧的集合,把每一个元素添加到新的集合
在添加到新的集合前,要判断这个元素是否在新的集合中已经存在(contains方法)
还要重写equals方法
-
LinkedList的使用
addFirst(E e) 把元素添加到第一个位置
addLast(E e) 把元素添加到最后的位置
getFirst() 获取第一个元素
getLast() 获取第二个元素
removeFirst() 删除第一个元素
public E removeLast() 移除第一个元素 -
栈和队列
栈:先进后出
队列:先进先出
11>用LinkedList模型栈数据结构
=代码==========
class Stack{
//创建一个集合
LinkedList list = new LinkedList();
//进栈
public void in(Object obj){
//把元素添加集合
list.addFirst(obj);//集合前面的是栈顶,后面是栈底
//list.addLast(obj);
}
//出栈
public Object out(){
return list.removeFirst();
}
}
- 用LinkedList的pop和push方法
pop:出栈
push:进栈
13>泛型集合
/**
- 泛型:
- 1.泛型的作用:把类型明确的工作推前到创建对象或者调用方法的时候。
- 2.泛型是一种参数化类型,把类型当作参数一样传递来明确集合的元素类型
- 泛型好处
- 1.提高安全性(将运行期的错误转换到编译期)
- 2.省去强转的麻烦
/
/** - 1.如果集合添加基本数据类型,内部会提升为包装类型
- int -> Integer
- double -> Double
- 2.List list = new ArrayList(); 这样声明一个集合对象,默认是可以添加任何类型的元素
- 3.如果在声明集合时,不添加泛型,就会有安全隐患(类型转换异常)
- 4.声明一个泛型集合:List list = new ArrayList();
- 代表list只能存字符串元素
*/
1》泛型迭代器
Iterator iterator;
Iterator iterator;
2》泛型注意事项
// 1.默认声明一个泛型集合,前后类型要一至
List list1 = new ArrayList();
// 2.这样声明前后类型不一至是不可以的
//不可以前面写父类,后面写子类
//List list2 = new ArrayList();
// 3.集合泛型的声明,可以只声明前面的泛型,jdk1.7的新特性:菱形泛型,开发时建议还是写成前后一至
//1.6 1.5的jdk不能写菱形泛型
List list3 = new ArrayList<>();
// 4.集合声明的泛型,代表此类或者子类都可以成为集合的元素,eg: Person -> Student
List list4 = new ArrayList();
// 5.声明的泛型类型一定是引用数据类型(类)
//泛型是基本数据类型
//List list6 = new ArrayList();
List list6 = new ArrayList();
3》泛型的由来
解决类型转换异常
04》声明泛型类和泛型方法
**
- 掌握:
- 如何声明一个泛型类和方法
- 1.声明一个泛型类
- class Tool
- 声明泛型方法格式: public 返回类型(T) 方法名(泛型类型T 变量名)
- 2.声明一个泛型方法(无返回值,有泛型参数)
- public void print(T t)
- 3.声明一个泛型方法(有返回值,无参数)
- public T get(int index)
- 4.声明一个泛型属性
- private T o;
public T getO() {
return o;
}
public void setO(T o) {
this.o = o;
}
*/
05》泛型高级之通配符
// 1.泛型通配符<?> 一般在声明变量类型时使用
// 任意类型,如果没有明确,那么就是Object以及任意的Java类了
//打印集合对象
public static void print(List<?> list){
System.out.println(list);
}
// 2.? extends E 【E是父类,?子类】
// 向下限定,E及其子类
/**
* addAll(Collection<? extends Person> c)
* 添加的集合可以是 Person类型【List list4】,或者是Person的子类【List list6】
*/
//List list5 = new ArrayList();
/**
* addAll(Collection<? extends Student> c)
* 添加的集合可以是 Student类型【List<Student> list6】,或者是Student的子类【List<Person> list4】
*/
List<Student> list5 = new ArrayList<Student>();
- ? super E 【?是父类,E子类】
向上限定,E及其父类
04》增强for循环
简体数组和集合遍历
格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
int[] arr1 = {120,110,119};
for(int num : arr1){
System.out.println(num);
}
//2.集合
List<String> list = new ArrayList<String>();
list.add("小子");
list.add("孙子");
list.add("老子");
int i = 0;
for(String str : list){
i++;
System.out.println("第" + i + "个元素:" + str);
}
05》三种迭代能否删除元素
普通for循环,可以删除,但是索引要(–减减 )
迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
增强for循环不能删除
06》静态导入[很少用]
静态导入是只导入类的静态方法
import static 包名+类名+方法名;
07》可变参数
可变参数,就是调用方法的时候,可以传n个参数
test1(int … nums);//传n个数字
test2(Object … objs);//传n个任意对象
注意:如果方法有多个参数名,可变参数名必须要放在最后
08》Arrays.asList方法:把数组转成集合
List<String> list1 = Arrays.asList("Gosling","Lucy","Lily");
System.out.println(list1);
List<Student> list2 = Arrays.asList(new Student(),new Student(),new Student());
System.out.println(list2);
13》Collection的toArray方法:把集合的元素 添加到 指定数组中
Collection<String> col = new ArrayList<String>();
col.add("Gosling");
col.add("gyf");
//声明一个字符串数组
String[] strs = new String[2];
System.out.println("===================");
//把集合里的元素 存在 指定的数组中
col.toArray(strs);
for(String str : strs){
System.out.println(str);
09》集合嵌套之List嵌套List
案例需求
1.一个班的n学生是一个集合
2.一个学校n班也是一个集合
3.如何将这些数据用一个集合来表示
//1、用集合来表示两个班级
List<Student> java1 = new ArrayList<Student>();
java1.add(new Student("小刘", 18));
java1.add(new Student("小张", 18));
java1.add(new Student("小关", 18));
List<Student> java2 = new ArrayList<Student>();
java2.add(new Student("李某某", 18));
java2.add(new Student("黄某某", 18));
java2.add(new Student("李某某", 18));
//2.用集合来表示学校school
List<List<Student>> school = new ArrayList<List<Student>>();
school.add(java1);
school.add(java2);
//3.遍历
//3.1遍历班级
for(List<Student> stus : school){
System.out.println("班级...");
//3.2 遍历学生
for(Student stu : stus){
System.out.println(stu);
}
}
Set:接口
- 1.一个不包含重复元素的 collection。
- 2.最多包含一个 null 元素
- 3.一般使用它实现类:HashSet,LinkedHashSet,TreeSet
- 4.Set集合存和取的顺序不一样,【每一次取的顺序都可能不一样】
List:接口
- 1.List是可存储相同元素
- 2.List存的取的元素顺序是一样**
HashSet
- 1.此类实现 Set 接口
- 2.由哈希表(实际上是一个 HashMap 实例)支持。
- 3.它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
- 4.此类允许使用 null 元素。
set遍历方法
Set遍历一、增强for循环
Set遍历二、迭代器
- hashCode与equals的原理
通过set集合的add方法添加元素时,内部会调用hashcode和equals方法
如果比较的hashcode的值是一样的话,会调用equals方法,equals方法返回true,就不存元素,返回false就存元素
如果比较的hashcode的值不一样,就直接存元素
5》hashCode与equals的优化
/**
- 例子:
Person属性:
-name
-age - 1.如果名字不一样,就不需要调用equals方法,从而优化代码
- return this.name.hashCode()
- 2.hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
return this.name.hashCode() + this.age;
*/
-
LinkedHashSet
LinkedHashSet是HashSet的子类
LinkedHashSet 存和取的顺序是一样 -
TreeSet
TreeSet是一种能排序集合
默认情况下,TreeSet存Integer时,由小到大排序
默认情况下,TreeSet存String时,字母的由小到大排序
Integer和String这两个类都内部实现了comparable接口 -
TreeSet保存自定义对象
>自定义对象必须实现comparable接口?
实现这个接口的目的是告诉TreeSet你的元素的排序规则 >实现了comparable接口的类,要实现compareTo方法
compareTo方法:
0-只存一个元素,第一个元素
-1:存的顺序倒序
1:存的顺序正序
9. TreeSet排序的原理 TreeSet是使用二叉权存数据
0:不存
负数:存在左边
正数:存在右边
-
Person 要按年龄和名字进行排序
public int compareTo(Person other) { //1.按年龄的由小到大排序 int num = this.age - other.age; System.out.println(this.name + "..比较..." + other.name + " 年龄差:" + num); //if(num == 0) num = 1; //2.如果年龄一样,根据名字排序 [字符串一样,比较的结果也是0] if(num == 0){ num = this.name.compareTo(other.name); } return num;
}
-
Student 要按名字的长度,名字和年龄进行排序
public int compareTo(Student other) {
// TODO Auto-generated method stub
//1.按照姓名长度
int num = this.name.length() - other.name.length();//2.字母排序 /*if(num == 0){ num = this.name.compareTo(other.name);//由小到大字母排序 //num = other.name.compareTo(this.name);//由大到小字母排序 }*/ num = (num == 0) ? this.name.compareTo(other.name) : num; //3.年龄排序 /*if(num == 0){ num = this.age - other.age;//由小到大 }*/ num = (num == 0) ? this.age - other.age : num; return num; }
01.TreeSet的Comparator排序方式
/**
- TreeSet的排序方式有2种
- 1.自然顺序(Comparable)
- 2.比较器顺序(Comparator)
- public TreeSet(Comparator<? super E> comparator)
- 使用场景:如果元素的类型是final类型,不被重写,这个时候选择Comparator排序方式
- 3.如果希望有相同的元素存在,在compareTo或者compare方法,返回1就行了。
*/
02.TreeSet排序原理总结
TreeSet的特点:
–TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
–TreeSet排序方式有两种自然顺序和比较器顺序
自然顺序(Comparable)
TreeSet类的add()方法中会把存入的对象提升为Comparable类型
调用对象的compareTo()方法和集合中的对象比较
根据compareTo()方法返回的结果进行存储
比较器顺序(Comparator)
创建TreeSet的时候可以制定 一个Comparator
如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的规则比较
add()方法内部会自动调用Comparator接口中compare()方法排序
调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
–两种比较方式的区别
1.TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
2.TreeSet如果传入Comparator, 就优先按照Comparator
03.案例:在一个集合中存储了无序并且重复的字符串,让其有序(字母顺序),而且还不能去除重复
Set<String> names = new TreeSet<String>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
int num = o1.compareTo(o2);//由小到大
num = num == 0 ? 1 : num;//保存同名元素
return num;
}
});
names.add("orange");
names.add("banana");
names.add("apple");
names.add("banana");
04.案例:从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印
/**
- 掌握:
- 1.数字的倒序实现
- 2.把str转成int
*/
public static void main(String[] args) {
//从键盘输入接收多个整数, 直到输入quit时结束输入.
//把所有输入的整数倒序[由大到小]排列打印
//1.创建TreeSet集合
Set<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2 - o1;//倒序排列
}
});
//2.接收整数存在TreeSet中
Scanner scanner = new Scanner(System.in);
System.out.println("请多次输入数字按回车,如果退出请输入quit");
while(true){
//接受用户的输入
String str = scanner.nextLine();
if(str.equals("quit")){
break;//退出死循环
}
//Integer.parseInt(str) 把字符串转成int
set.add(Integer.parseInt(str));
}
//3.打印集合
for(Integer i : set){
System.out.println(i);
}
}
}
05.键盘录入学生信息按照总分排序后输出在控制台
/**
-
1.创建学生类
-
添加3个学科(语文,数学,英语)成绩属性
-
添加名字属性
-
在有参构造方法中把总分算好
-
2.把n个学生添加到TreeSet中
-
3.TreeSet要进行总分排序
@Override
public int compareTo(Student o) {
// TODO Auto-generated method stub
//总分排序【由大到小】
int num = o.totalScore - this.totalScore;//如果总分一样,就按照名字排序 num = num == 0 ? this.name.compareTo(o.name) : num; //同名的学生可能有些没法排序 num = num == 0 ? 1 : num; return num;
- Map介绍
Map是属于java.util的一个接口Map<K,V>
类型参数:
K - 映射所维护的键的类型
V - 映射值的类型
Map是将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map接口和Collection接口的不同
–Map是双列的,Collection是单列的
–Map的键唯一,Collection的Set是唯一的,List不是惟一的
Map:有几个常用的子类HashMap,LinkedHashMap,TreeMap,Hashtable,Properites
-
Map的功能
a>添加功能
V put(K key,V value):添加元素。
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
b>删除功能
void clear():移除所有的键值对元素
V remove(Object key):根据键删除键值对元素,并把值返回
c>判断功能
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
d>获取功能
V get(Object key):根据键获取值
Set keySet():获取集合中所有键的集合
Collection values():获取集合中所有值的集合
e>长度功能
int size():返回集合中的键值对的个数 -
HashMap使用注意事项
声明HashMap时的键值可以是任意对象
如果有重复的键,会把以前的替换
值能为空
键能为空,但这样写没什么意义
put方法的返回值
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值 -
Map的遍历,有两种方式
a>Map集合的遍历一(键找值)
通过key得到value
通过entry得到key和value
例子:
1.创建Map对象
Map<String,String> map = new HashMap<String,String>();
map.put(“name”, “刘姐”);
map.put(“age”, “48”);
map.put(“gender”, “女”);
map.put(“height”, “1.62”);//3.遍历
//3.1获取map所有键
Set keys = map.keySet();
//3.2遍历键
for(String key : keys){
//3.3 通过key获取值
String value = map.get(key);//打印key&value System.out.println(key + " : " + value);
}
键值对对象找键和值源码分析
1.Map.Entry理解成"键值对对象"
2.Map.Entry是一个接口,它的实现类是HashMap$Node
3.Map.Entry是有个key和value属性,通过get方法可以取值
4.遍历Entry的两种方法,通过迭代器和for增强 -
遍 历
Set<Entry<String, Integer>> entries = map.entrySet();//2.1通过增强for循环来遍历Set /*for(Entry<String, Integer> entry : entries){ //Map.Entry 的实现类HashMap$Node System.out.println(entry.getClass()); System.out.println(entry.getKey() + "---" + entry.getValue()); }*/ //2.2 通过迭代器来遍历Set
Iterator<Entry<String, Integer>> iterator = entries.iterator();
while(iterator.hasNext()){
Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + “—” + entry.getValue());
}3.案例 :HashMap集合键是Student,值是String
public class Demo01 {
public static void main(String[] args) {
/* 案例 :HashMap集合键是Student,值是String
键是学生对象,代表每一个学生
值是字符串对象,代表学生归属地注意事项: 1.打印的key是student的toString方法返回的字符串 2.如果key相同,会把前面的值替换掉,但是必须是同一个对象 3.HashMap是无序的 4.new出来的都不是相同的key,因为地址不同。如果属性一样,想替换前面对应属性一样的valus时候,需要重写equals&hashcode方法 */ Map<Student,String> map = new HashMap<Student,String>(); map.put(new Student("小刘", 18), "湖北"); map.put(new Student("小胡", 18), "湖南");
// Student stu = new Student(“小官”, 18);
// map.put(stu, “广东”);
// map.put(stu, “广西”);
map.put(new Student(“小官”, 18), “广东”);
map.put(new Student(“小官”, 18), “广西”);//System.out.println("map:" + map); //遍历 Set<Entry<Student, String>> entries = map.entrySet(); for(Entry<Student, String> entry : entries){ System.out.println(entry.getKey() + " --- " + entry.getValue()); } }
}
class Student{
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
}
01.LinkedHashMap
- LinkedHashMap是存和取的顺序是一样
- HashMap是存和取的顺序不是一样
- LinkedHashMap它是继承HashMap
02.TreeMap
-
TreeMap会对键key进行排序
-
TreeMap的key,如果是自定义对象话,这个对象要实现Comparable接口,
-
或者说在new TreeMap的时候,传一个comparator参数
03.集合的嵌套例子,Map嵌套Set 1.创建两个班(Set) Set<Student> javaClass = new HashSet<Student>(); javaClass.add(new Student("小贾", 28)); javaClass.add(new Student("小牛", 18)); Set<Student> h5Class = new HashSet<Student>(); h5Class.add(new Student("小丽", 28)); h5Class.add(new Student("小红", 18)); //2.创建一个学校(Map) //Key:班级名字,Value:这个班所有学生 /*** * HashMap嵌套HashSet,或者说Map里嵌套Set */ Map<String,Set<Student>> school = new HashMap<String,Set<Student>>(); school.put("Java班级", javaClass); school.put("H5班级", h5Class); //3.遍历 //3.1遍历学校里的班级 for(Entry<String,Set<Student>> entry : school.entrySet()){ System.out.println("班级名称:" + entry.getKey()); //3.2 遍历班级里学生 //Set<Student> myClass = entry.getValue(); for(Student stu : entry.getValue()){ System.out.println(stu); } }
04.面试题:HashMap和Hashtable区别
/* 1.Hashtable是JDK1.0版本出现的,是线程安全的,效率低,有加锁[很少用]
* 2.HashMap是JDK1.2版本出现的,是线程不安全的,效率高
3.Hashtable不可以存储null键和null值
4.HashMap可以存储null键和null值*/
05.Collections集合工具类
Collections成员方法
public static void sort(List list) 排序
public static int binarySearch(List<?> list,T key) 二分查找
public static T max(Collection<?> coll) 取大值
public static void reverse(List<?> list) 反转
public static void shuffle(List<?> list) 打乱顺序
06.泛型固定下边界 【? super E】
/*泛型固定下边界 ? super E
1.【? extends E】-表示泛型固定上边界
? 表示子类,E表示父类
ArrayList.addAll(Collection<? extends Person> c)
2.【? super E】 -表示泛型固定下边界
? 表示父类,E表示的是子类
ArrayList.sort(Comparator<? super Student> c)
3.【? extends E 】针对存的操作
4.【? super E】 针对取的操作*/