第8天_面向对象(List、Set、数据结构、Collections)
一.数据结构
1.什么是数据结构
容器中存放组织数据的一种结构
2.常见的4+1中数据结构
堆栈结构
可以看作只有一端开口的容器,先进后出(FILO)
队列结构
可以看成两端开口的容器。一端进,一端出,先进先出(FIFO)
数组结构
在内存中是一块连续的区域,查询快(通过索引),增删慢(长度固定)。(垃圾回收机制)
链表结构
在内存中可以分散,链表中的元素我们一般成为节点,一般有两个属性,数据域和指针域
查询慢,增删快
红黑树结构
查询速度非常恐怖O(log(n))
增删速度包括创建时都是非常慢的
哈希表结构底层就是数组和链表,jdk8之后加入红黑树优化。
二.List接口
1.List接口的特点
a.有序的collection(也成为序列)。
b.有索引
c.元素可重复
API的描述:
有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
2.List接口中常用的方法以及常用实现类
a.拥有Collection接口中的方法和迭代器
b.还有四个和索引相关的增删改查方法
public void add(int index, E e):插入元素
public E remove(int index):根据索引删除元素
public E set(int index, E e):修改指定索引的元素
public E get(int index):根据索引获取元素
c.List接口的实现类
ArrayList
LinkedList
Vector
3.ArrayList的数据结构以及使用
ArrayList底层是数组结构,特点是查询快,增删慢!!!
特有方法:无
4.LinkedList的数据结构以及使用
LinkedList底层是链表结构,特点是查询慢,增删快!!!
特有方法(8个):8个和首尾操作相关的方法
public void addFirst(E e):添加首
public void addLast(E e):添加尾
public E removeFirst():删除首
public E removeLast():删除尾
public E getFirst():返回首
public E getLast():返回尾 public E pop():删除首,就是跟removeFirst一样的
public void push(E e):添加首,就是跟addFirst一样的
addFirst和removeFirst是1.2就有的,java是1.5开始火的,这两个方法是jdk1.6之后添加的,商业需要,为了吸引更多的开发者(别的语言中增添方法名就是push和pop)
public class TestLinkedList {
public static void main(String[] args) {
//1.创建一个LinkedList
LinkedList<String> list = new LinkedList<String>();
//2.添加首尾
list.addLast("刘岩");
list.addFirst("贾乃亮");
list.addLast("蔡徐坤");
list.addFirst("马蓉");
list.addLast("王宝强");
list.addFirst("宋吉吉");
list.addLast("李小璐");
list.addFirst("PGOne");
//3.打印
//"PGOne" "宋吉吉" "马蓉" "贾乃亮" "刘岩" "蔡徐坤" 王宝强" "李小璐"
System.out.println(list);
//3.删除首尾
String first = list.removeFirst();
System.out.println(first);
System.out.println(list);
String last = list.removeLast();
System.out.println(last);
System.out.println(list);
//[宋吉吉, 马蓉, 贾乃亮, 刘岩, 蔡徐坤, 王宝强]
//4.获取首尾
String first1 = list.getFirst();
System.out.println(first1);
System.out.println(list);
String last1 = list.getLast();
System.out.println(last1);
System.out.println(list);
//[宋吉吉, 马蓉, 贾乃亮, 刘岩, 蔡徐坤, 王宝强]
//5.push和pop
list.push("666");
System.out.println(list);
String pop = list.pop();
System.out.println(pop);
System.out.println(list);
}
}
三.Set接口
1.Set接口的特点
a.无序的(是指存的和取的顺序是不一定一致的,LinkedHashSet除外,它是有序的)
b.无索引
c.元素唯一
2.Set接口的常用方法以及常用子类
a.拥有Collection接口中的方法和迭代器
b.特有方法:无
c.Set接口常见的实现类
HashSet(无序)
LinkedHashSet(有序)
TreeSet
3.HashSet的数据结构以及使用
HashSet底层采用哈希表结构
特有方法:无
public class TestHashSet {
public static void main(String[] args) {
//1.创建一个HashSet
HashSet<String> set = new HashSet<String>();
//2.添加
set.add("jack");
set.add("jack");
set.add("jack");
set.add("rose");
set.add("rose");
set.add("lilei");
set.add("hanmeimei");
set.add("hanmeimei");
set.add("lucy");
set.add("lucy");
set.add("lucy");
System.out.println(set);
//[lilei, hanmeimei, rose, lucy, jack]
}
}
4.哈希表结构的介绍[扩展]
哈希表结构 = 数组(默认长度16) + 链表 + 红黑树(jdk1.8)
i.对象的哈希值(对象的“数字指纹”)
我们怎么获取到对象的哈希值?
只要调用对象的hashCode方法即可获取到对象的哈希值
Java中的地址值是假的!而是哈希值转成了16进制而已
Java中有没有真正的地址值?
有!!!对象名中保存就是真正的地址值
但是我们打印不出来,因为我们打印对象名的时候,会默认调用toString方法,屏蔽了真正的地址值,是一 种内存保护机制,因此Java的安全性很高
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}//返回值为包名.类名@hashCode的十六进制值
不同对象的Hash值可能一样的
"abc"和"acD"都是96354(hashCode方法在String类重写了)
*************结论:哈希表结构如何保证元素的唯一性??***************
哈希表会比较新旧元素的哈希值,以及调用equals方法,
只有哈希值一致的情况下,并且equals返回true,才判定元素重复
*******************************************************************
注意:桶的长度为8,当桶中的元素超过8时,结构自动变成红黑树
5.LinkedHashSet的数据结构以及使用
LinkedHashSet底层采用链式哈希表
特有方法:无
public class TestLinkedHashSet {
public static void main(String[] args) {
//1.创建一个HashSet
LinkedHashSet<String> set = new LinkedHashSet<String>();
//2.添加
set.add("lucy");
set.add("hanmeimei");
set.add("rose");
set.add("rose");
set.add("rose");
set.add("lilei");
set.add("jack");
System.out.println(set);
//[lucy, hanmeimei, rose, lilei, jack]
}
}
练习:使用哈希表结构保存自定义类型的元素******************
******************************************************************************
使用哈希表结构保存自定义类型时,
为了保证元素是唯一,需要重写自定义类型中的hashCode和equals方法(工具自动生成)
******************************************************************************
public class Cat {
int age;
String name;
public Cat() {
}
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
//为了保证元素的唯一性,自定义类型必须重写hashCode和equals方法
//alt+insert
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cat cat = (Cat) o;
return age == cat.age &&
Objects.equals(name, cat.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
//练习:使用哈希表结构保存自定义类型的元素*********************
public class HashCodeTestDemo {
public static void main(String[] args) {
//1.LinkedHashSet
LinkedHashSet<Cat> cats = new LinkedHashSet<Cat>();
//2.保存猫
cats.add(new Cat(1, "小猫咪"));
cats.add(new Cat(2, "中猫咪"));
cats.add(new Cat(3, "大猫咪"));
cats.add(new Cat(3, "大猫咪"));
cats.add(new Cat(4, "老猫咪"));
cats.add(new Cat(5, "死猫咪"));
//3.打印
System.out.println(cats);
}
}
6.可变参数
可变参数是指参数的个数可以变化
格式:
数据类型... 变量名
本质:
实际上可变参数就是数组(语法糖)
注意:
a.一个方法最多只能有一个可变参数
b.如果既有可变参数,也有正常参数,正常参数要写在可变参数的前面
public class TestDemo {
public static void main(String[] args) {
//调用方法
System.out.println(getSum());
System.out.println(getSum(1));
System.out.println(getSum(1, 2));
System.out.println(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9,10));
}
//使用可变参数
public static int getSum(int... a) {
//数组求和
int sum = 0;
for (int i : a) {
sum+=i;
}
return sum;
}
}
四.Collections
1.Collections的介绍
Collections是一个工具类(方法都是静态的)
2.常用功能方法
public static void shuffle(List<?> list):打乱集合顺序
public static void sort(List<?> list):升序排列集合
public class CollectionsDemo01 {
public static void main(String[] args) {
//1.sort方法
ArrayList<Integer> nums = new ArrayList<Integer>();
//2.数据
nums.add(80);
nums.add(20);
nums.add(70);
nums.add(40);
nums.add(10);
nums.add(50);
nums.add(100);
nums.add(60);
nums.add(30);
nums.add(90);
//3.打印
System.out.println(nums);
//4.排序
Collections.sort(nums);
//5.打印
System.out.println(nums);
}
}
关于sort方法的排序规则:
如果元素是数值类型,按照大小升序
如果元素是字符类型,按照ASCII码值升序
如果元素是字符串类型,首先按照首字母的ASCII码值升序,首字母一样按照次字母ASCII码值升序,依次类推
3.扩展1:Comparator<T>比较器接口******************
public class CollectionsDemo02 {
public static void main(String[] args) {
//1.sort方法
ArrayList<Integer> nums = new ArrayList<Integer>();
//2.数据
nums.add(80);
nums.add(20);
nums.add(70);
nums.add(40);
nums.add(10);
nums.add(50);
nums.add(100);
nums.add(60);
nums.add(30);
nums.add(90);
//4.排序
Collections.sort(nums,new Comparator<Integer>(){
//此方法称为比较方法
//返回值表示
//正数 表示前者大于后者
//0 表示前者等于后者
//负数 表示前者小于后者
@Override
public int compare(Integer o1, Integer o2) {
//升序 前-后
// return o1-o2;
return o2-o1;
}
});
//5.打印
System.out.println(nums);
}
}
4.排序练习(代码实现)
/**
* 使用集合保存学生对象,对集合进行排序
*/
public class CollectionsDemo03 {
public static void main(String[] args) {
//1.创建一个ArrayList
ArrayList<Student> ss = new ArrayList<Student>();
//2.添加学生
ss.add(new Student(20,"haneimei",50));
ss.add(new Student(10,"jack",90));
ss.add(new Student(8,"ady",95));
ss.add(new Student(9,"tonny",100));
ss.add(new Student(25,"yy",30));
//3.遍历
for (Student s : ss) {
System.out.println(s);
}
System.out.println("===========================");
Collections.sort(ss, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//口诀:升序 前减后
//a.按照年龄降序
// return o2.age-o1.age;
//b.按照分数升序
// return o1.score-o2.score;
//c.按照名字的长度降序
// return o2.name.length()-o1.name.length();
//d.按照姓名的第二个字母降序
return o2.name.charAt(1)-o1.name.charAt(1);
}
});
for (Student s : ss) {
System.out.println(s);
}
}
}
总结:
-[] 能够说出List集合特点
有序,有索引,可重复
-[] 能够说出常见的数据结构
-[] 能够说出常见的数据结构
-[] 能够说出数组结构特点
-[] 能够说出栈结构特点
-[] 能够说出队列结构特点
-[] 能够说出单向链表结构特点
-[] 能够说出Set集合的特点
无序,无索引,唯一
-[] 能够说出哈希表的特点
哈希表中的元素是唯一的
哈希表通过哈希值和equals共同保证元素的唯一性
-[] 使用HashSet/LinkedHashSet集合存储自定义元素
自定义类型需要重写hashCode和equals
-[] 能够使用集合工具类的常用方法
public static void shuffle(List<?> list):打乱集合顺序
public staitc void sort(List<?> list):升序排序集合 -[] 能够使用Comparator比较器进行排序
Collections.sort(集合<E>, new Comparator<E>{
public int compare(E e1, E e2){
升序 前减后
}
});