文章目录
对象数组
- 对象数组指的就是存储引用类型的数组
对象数组的使用
/*
*对象数组(引用数组):该数组中存储的是引用类型因此我们叫它对象数组或者引用数组
* 引用数组中存储的是对象的地址值而不是对象
*/
public class Demo {
public static void main(String[] args) {
//1.定义一个Student类型的数组
//int[] arr = new int[3]
Student[] stus=new Student[2];
//2.给数组中的元素赋值
//arr[0]=3;
stus[0]=new Student("张三",13);
stus[1]=new Student("李四",24);
//3.遍历这个引用数组
/*
* for(int i=0;i<arr.length;i++){
* System.out.println(arr[i])
* }
*/
for(int i=0;i<stus.length;i++){
System.out.println(stus[i]);
}
}
}
内存图
List体系
List接口介绍
api中介绍:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素。
-
List接口:
- 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
-
List接口的常用子类有:
-
ArrayList集合
-
LinkedList集合
-
ArrayList类
ArrayList实现原理(思想)
-
ArrayList集合特点:
底层使用是一个引用数组(Object[])
-
扩容思想:
新建一个集合的时候,底层会开辟长度为10的数组,调用add()方法会不断的往数组中添加元素当添加了10个元素,再添加第11个元素的时候,数组满了,无法存入,此时会新建一个长度为原来长度1.5倍的数组(10+10/2),接着会把原有元素拷贝到新数组中,再把第11个元素追加到末尾
ArrayList中特有方法
-
增加元素方法
add(Object e):向集合末尾处,添加指定的元素
add(int index, Object e):向集合指定索引处,添加指定的元素,原有元素依次后移
-
删除元素删除
remove(Object e):将指定元素对象,从集合中删除,返回值为被删除的元素
remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素
-
替换元素方法
set(int index, Object e):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素
-
查询元素方法
get(int index):获取指定索引处的元素,并返回该元素
方法演示:
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
//list中可以存储任意数据类型,必须是对象
ArrayList list = new ArrayList();
list.add(12);//12是Integer一个对象,自动装箱
list.add("abc");
list.add("def");
list.add("abc");
System.out.println(list);//[12, abc, def, abc]
list.add(3,"zzz");
System.out.println(list);//[12, abc, def, zzz, abc]
System.out.println( list.get(1));//abc
list.set(3,"www");
System.out.println(list);//[12, abc, def, www, abc]
list.remove("abc");
System.out.println(list);//[12, abc, def, www, abc]
}
}
ArrayList存储自定义对象
public class Person {
private int id;
private String name;
//构造方法
public Person(int id, String name) {
this.id = id;
this.name = name;
}
//getter()和setter()
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//重写toString()
@Override
public String toString() {
return "Person{" + "id=" + id + ", name='" + name + '\'' + '}';
}
}
import java.util.ArrayList;
import java.util.Iterator;
public class PersonDemo {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person(01,"张三"));
list.add(new Person(02,"李四"));
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//Person{id=1, name='张三'}
//Person{id=2, name='李四'}
}
}
ArrayList特点
查询元素较快:因为底层是数组,数组有索引
增删元素较慢:
添加慢,因为每次添加都需要移动大量的元素,导致浪费内存资源,效率低
- 添加慢的原因:
- 删除慢的原因:
LinkedList类
LinkedList实现思想
底层使用一个链表,第一个元素记录下一个元素的地址值最终形成一条链子
LinkedList特有方法
/*
* LinkedList:
* 原理:
* LinkedList底层使用是链表数据结构
* LinkedList<E>成员方法:
* void addFirst(E e):不断往链表的头部添加,遍历集合的时候从链头开始遍历
void addLast(E e):不断地往链表尾部追加,遍历集合的时候从链头开始遍历
*
* E getFirst()//取链头的第一个元素,但是不会删掉链头元素
E getLast() //取炼尾(最后一个)的元素,但是不会删掉链尾的元素
E removeFirst()//取链头的第一个元素,但是会删掉链头的元素
E removeLast() //取链尾的的元素,但是会删掉链尾的元素
*/
LinkedList特点
查询元素相对ArrayList较慢:因为链表都是从头开始查
增删元素相对ArrayList较快:因为链表仅仅需要改变元素中记录的地址值,而不需要移动大量元素,节省内存开销提高效率
- LinkedList增删元素原理:
栈和队列数据结构
栈:特点:元素后进先出(先进后出) :手枪弹夹
队列:特点:元素先进先出(后进后出):银行叫号
Set体系
学习Collection接口时,记得Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的元素就是不重复的。
Set接口介绍
查阅HashSet集合的API介绍:此类实现Set接口,由哈希表支持(实际上是一个 HashMap集合)。HashSet集合不能保证的迭代顺序与元素存储顺序相同。
即特点为:无序,不重复
HashSet类
HashSet基本使用
HashSet依然具有集合通用的特点:利用add添加元素,使用迭代器遍历,使用增强for遍历
方法列表:
add() remove() contains() clear() size()
-
Set无序,所有没有下标的获取方式。因此没有get(i)
-
Set中不能查看一个元素
/*
* Set接口:没有索引,存储的元素唯一,存取顺序不一定一致
* HashSet:没有索引,保证元素唯一,存的顺序和取的顺序不一定一致
* 成员方法:
* Iterator<E> iterator()
*/
import java.util.HashSet;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
HashSet<String> hs=new HashSet<String>();
hs.add("aa");
hs.add("bb");
hs.add("cc");
//1.获取迭代器对象
Iterator<String> it=hs.iterator();
//2.循环遍历
//迭代器
while(it.hasNext()){
String str=it.next();
System.out.println(str);
}
/*增强for
for(String str : hs){
System.out.println(str);
}
*/
}
}
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
//Set集合过滤字符串
public class Demo {
//Scanner输入字符串去重
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入字符串:");
String str = input.nextLine();
//1.String-->Char[]
char[] cs = str.toCharArray();
//2.Set集合
Set<Character> set = new HashSet<>();
//3.将每个字符放在Set中
for (int i = 0 ; i < cs.length ; i++){
set.add(cs[i]);//add()自带过滤重复
}
System.out.println(set);
}
}
add()判断对象是否重复,依赖contains()
contains()底层依赖equals(),重写equals()就能在Set集合中解决对象重复的问题。
哈希算法
- 哈希算法相对于普通查找更快
- 哈希算法保证唯一原理
HashSet存入字符串保证唯一原理
存入HashSet的字符串依赖两个方法,一个是hashCode()方法,一个是equals()方法,注意这两个方法出自Object类,但是String都把这两个方法重写了,String的类的hashCode()方法不再像Object类的hashCode()方法返回内存地址值,而是根据一定的算法计算字符串中字符的ASCII码值,String类的equals()方法就是比较两个字符串的内容
import java.util.HashSet;
/*
* HashSet唯一原理
* 先调用hashCode()方法比较元素的哈希值
* 如果添加的元素哈希值与集合中的元素的哈希值不同,直接存入
* 如果添加的元素哈希值与集合中的元素的哈希值相同
* 调用equals()方法比较两个元素的内容
* equals()返回true,说明两个元素内容相同,认为重复,不存
* equals()返回false,说明两个元素内容不同,存
* Object类中原始的hashCode()返回的就是内存地址值
*/
public class Demo {
public static void main(String[] args){
HashSet<String> hs=new HashSet<String>();
hs.add("ab");//当存入第一个ab时候直接存入
hs.add("ab");//当存入第二ab的时候,先调用hashCode()方法获取两个元素哈希值,比较发现相同
//在调用equals方法比较,"ab".euqlas("ab")//true,第二个ab就不存
hs.add("bc");//当存入bc的时候,先调用hashCode()方法获取两个元素哈希值
//比较发现不同,直接存入
System.out.println(hs);//[ab, bc]
System.out.println("ab".hashCode());//3105
System.out.println("bc".hashCode());//3137
}
}
HashSet存取自定义对象保证唯一原理
当我们存储自定义对象中出现同名同年龄的,利用HashSet不能去重:
因为Person利用的是从Object类中继承的hashCode方法,获取的是元素的地址值比较
而每个Person都是新new的Person,地址值均不同
public class Person /*extends Object*/ {
private String name;
private int age;
public Person(String name, int age) {
super();
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;
}
}
import java.util.HashSet;
/*
* 利用HashSet存储自定义对象
*/
public class PersonDemo {
public static void main(String[] args) {
//1.创建HashSet集合
HashSet<Person> hs=new HashSet<Person>();
//2.创建3个Person对象
/*Person p=new Person("张三",12);
*hs.add(p);
*/
hs.add(new Person("张三",12));//匿名对象
hs.add(new Person("张三",12));//调用hashCode()方法获取哈希值(内存地址值),去比较
//第二个Person对象的哈希值和第一个Person的哈希值不同
//第二个Person直接存入
hs.add(new Person("王五",16));
//3.遍历HashSet集合
for(Person p : hs){
System.out.println(p.getName()+" "+p.getAge());
}
//张三 12
//张三 12
//王五 16
}
}
我们尝试改写(重写)原有的hashCode与equals方法保证同名同年龄的人被过滤掉
public class Person /*extends Object*/ {
private String name;
private int age;
public Person(String name, int age) {
super();
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;
}
/*我们在重写hashCode()一般用上这个类的所有属性来产生哈希值*/
/*@Override
public int hashCode() {
//return 10;
return name.hashCode() + age;
}*/
/*
*return 10,让所有元素都产生了相同哈希值,所有元素都得去调用
*equals()比较
* 对于new Person("张三", 12)还有new Person("王五", 16)
* 两者的姓名和年龄都不同,没必要再去调用equals比较
*/
@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;
}
/*
* euqual方法的重写与之前的相同
* 如果两个人的姓名和年龄均相同,认为是同一个人,返回true
* 如果两个人的姓名和年龄至少有一个不同返回false
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) 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;
}
}
import java.util.HashSet;
public class PersonDemo {
public static void main(String[] args) {
// 1.创建HashSet集合
HashSet<Person> hs = new HashSet<Person>();
// 2.创建3个Person对象
Person p1=new Person("张三", 12);
Person p2=new Person("张三", 12);
Person p3=new Person("王五", 16);
hs.add(p1);//p1直接存入
hs.add(p2);//存入p2,需要调用hashCode()方法获取p1,p2的哈希值
//哈希值相同,需要再去比较equals(),返回true,认为相同元素,不存
hs.add(p3);//存入p3,需要调用hashCode()方法获取p3,p1的哈希值
//不同,直接将p3存入
System.out.println(p1.hashCode());//776222
System.out.println(p2.hashCode());// 776222
System.out.println(p3.hashCode());// 938522
// 3.遍历HashSet集合
for (Person p : hs) {
System.out.println(p.getName() + " " + p.getAge());
}
//王五 16
//张三 12
}
}