数据结构 数组结构 链表结构 二分数 哈希表
1.List接口 接口的方法有增删改查
Set接口
Set中的方法就是增删改查 不能加入重复元素因为调用了equals方法
HashSet数据结构基于哈希表作用可以快速查找,存入的元素必须定义hashcode方法
LinkedHashSet具有HashSet的查询速度,且内部使用链表维护了元素插入的顺序
TreeSet数据结构基于二分树,保持Set的次序如果要排序必须实现Comparable接口,覆盖里面的方法
例子
package com.westo.javase.lesson01;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* 方法 操作实例
* @author likailong
*
*/
public class CollectionsDemo01 {
public static void main(String[] args) {
//method_1();
method_2();
}
/**
* 反转元素
*/
static void method_2() {
List
Set
Collections.addAll(allList,"a","c","c");
Collections.reverse(allList);
Iterator
while(iter.hasNext()){
System.out.println(iter.next()+"**");
}
Collections.addAll(allSet,"a","c","c");
Iterator
while(iter1.hasNext()){
System.out.println(iter1.next()+"**");
}
}
/**
*
* 向集合添加元素
*/
static void method_1() {
List
Set
Collections.addAll(allList,"a","c","c");
Iterator
while(iter.hasNext()){
System.out.println(iter.next()+"**");
}
Collections.addAll(allSet,"a","c","c");
Iterator
while(iter1.hasNext()){
System.out.println(iter1.next()+"**");
}
}
}
package com.westo.javase.lesson01;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class CollectionsDemo03 {
public static void main(String[] args) {
List
Collections.addAll(all, "a","c","b");
int point=Collections.binarySearch(all, "v");
System.out.println(point);
point=Collections.binarySearch(all, "2");
System.out.println(point);
Collections.replaceAll(all, "a", "1");
Iterator
while(ite.hasNext()){
System.out.print(ite.next()+",");
}
Collections.sort(all);//因为string实现了comparable接口所以可以比较
ite=all.iterator();
while(ite.hasNext()){
System.out.println(ite.next()+",");
}
}
package com.westo.javase.lesson01;
import java.util.HashMap;
import java.util.Map;
/**
* 实验结果 如果用一个自定义对象标识map中的 key必须覆盖equals() ,,hashCode()
* 这样才可以用匿名对象找到对应的值
* @author likailong
*
*/
public class HashMapDemo02 {
public static void main(String[] args) {
method_1();
method_2();
}
static void method_2() {
Map
map=new HashMap
map.put(new Persons("张三",30), "zhangsan");
System.out.println(map.get(new Persons("张三",30)));
}
static void method_1() {
Map
map=new HashMap
Persons per=new Persons("张三",30);
map.put(per, "zhangsan");
System.out.println(map.get(per));
}
}
package com.westo.javase.lesson01;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Map接口不能直接迭代 因为Map存储的是一对值 而Iterator一次只能找到一个 如果必须Iterator输出
* 1.将Map接口的实例通过entrySet变成Set接口对象 2.通过Set接口实例为Iterator实例化
* 3.通过Iterator迭代输出,每个内容都是Map.Entry对象 4,通过 Map.Entry进行键值分离
*
* @author likailong
*
*/
public class IterarorDemo01 {
public static void main(String[] args) {
Map
map=new HashMap
map.put("A", "AB");
map.put("C", "BC");
map.put("B", "CD");
map.put("E", "EF");
Set
allset=map.entrySet();
Iterator
iter=allset.iterator();
while(iter.hasNext()){
Map.Entry
System.out.println(me.getKey()+"**"+me.getValue());
}
for(Map.Entry
System.out.println(me.getKey()+"--->"+me.getValue());
}
}
}
package com.westo.javase.lesson01;
public class Persons {
private String name;
private int 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;
Persons other = (Persons) 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;
}
@Override
public String toString() {
return "Persons [name=" + name + ", age=" + age + "]";
}
public Persons(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
package com.westo.javese.lesson02;
/**
* 数组数据结构
* 方便查找
* 不方便增加和删除对象
*/
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo {
public static void main(String[] args) {
List
allList=new ArrayList
allList.add("hello");
allList.add(0,"world");
allList.add("MLDN");
allList.add("www.westo.com");
String str[]=allList.toArray(new String []{});
System.out.print("指定数组类型:");
for (int i = 0; i < str.length; i++) {
System.out.print(str[i]+",");
}
System.out.print("\n返回对象数组:");
Object obj[]=allList.toArray();
for (int i = 0; i < obj.length; i++) {
String temp=(String) obj[i];
System.out.print(temp+",");
}
}
}
package com.westo.javese.lesson02;
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo02 {
public static void main(String[] args) {
List
allList=new ArrayList
System.out.println("集合是否为空"+allList.isEmpty());
allList.add("hello");
allList.add(0,"world");
allList.add("mlin");
allList.add("www.westo.cn");
System.out.println(allList.contains("hello")?"hello字符串存在":"hello字符串不存在");
List
System.out.print("集合截取");
for (int i = 0; i < allSub.size(); i++) {
System.out.print(allList.get(i)+",");
}
System.out.println("");
System.out.println("mlin的位置"+allList.indexOf("mlin"));
System.out.println(allList.isEmpty());
}
}
2:Set集合(理解)
(1)Set集合的特点
无序,唯一
(2)HashSet集合(掌握)
A:底层数据结构是哈希表(是一个元素为链表的数组)
B:哈希表底层依赖两个方法:hashCode()和equals()
执行顺序:
首先比较哈希值是否相同
相同:继续执行equals()方法
返回true:元素重复了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合
C:如何保证元素唯一性的呢?
由hashCode()和equals()保证的
D:开发的时候,代码非常的简单,自动生成即可。
E:HashSet存储字符串并遍历
F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)
(3)TreeSet集合
A:底层数据结构是红黑树(是一个自平衡的二叉树)
B:保证元素的排序方式
a:自然排序(元素具备比较性)
让元素所属的类实现Comparable接口
b:比较器排序(集合具备比较性
3:Collection集合总结(掌握)
Collection
|--List 有序,可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高
|--Set 无序,唯一
|--HashSet
底层数据结构是哈希表。
如何保证元素唯一性的呢?
依赖两个方法:hashCode()和equals()
开发中自动生成这两个方法即可
|--LinkedHashSet
底层数据结构是链表和哈希表
由链表保证元素有序
由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树。
如何保证元素排序的呢?
自然排序
比较器排序
如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
案例用户登录系统的实现
package cn.itcast.dao;
import cn.itcast.pojo.User;
public interface UserDao {
/**
* 用户登录模块
* @param username 用户名
* @param password 密码
* @return 登录是否成功
*/
public abstract boolean isLogin(String username,String password );
/**
* 用户注册模块
* @param use用户注册的信息
*/
public abstract void regist(User use);
}
package cn.itcast.dao.imp;
import java.util.ArrayList;
import cn.itcast.dao.UserDao;
import cn.itcast.pojo.User;
/**
* 用户操作的具体实现类 集合版
*
* @author likailong
*
*/
public class UserDaoImpl implements UserDao {
/**
* 登陆的具体实现
* 为了让集合可以多个用到 定义为成员变量
* 为了让多个对象用一个集合,也就是说只创建一次加static修饰
*/
private static ArrayList
@Override
public boolean isLogin(String username, String password) {
boolean flag=false;
for(User u:array){
if(u.getUsername().equals(username)
&&u.getPassword().equals(password)){
flag=true;
break;
}
}
return flag;
}
/**
* 注册的具体实现
*/
@Override
public void regist(User use) {
array.add(use);
}
}
package cn.itcast.game;
import java.util.Random;
import java.util.Scanner;
public class GuessNumberGame {
private GuessNumberGame() {
}
@SuppressWarnings("resource")
public static void start() {
Random ran=new Random();
int number=ran.nextInt(100);
int count = 0;
while (true) {
System.out.println("请输入一个(0-100)数字:");
Scanner sc = new Scanner(System.in);
int guessNamber = sc.nextInt();
count++;
if (guessNamber > number) {
System.out.println("你猜的数字" + guessNamber + "大了");
} else if (guessNamber > number) {
System.out.println("你猜的数字" + guessNamber + "小了");
} if (guessNamber == number) {
System.out.println("恭喜你猜对了 ****奖励小美眉一个");
System.out.println("你猜了" + count + "次");
break;
}
}
}
}
package cn.itcast.pojo;
/**
* 用户基本描述类
* @author likailong
*
*/
public class User {
private String username;
private String password;
public User() {
super();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.itcast.test;
import java.util.Scanner;
import cn.itcast.dao.UserDao;
import cn.itcast.dao.imp.UserDaoImpl;
import cn.itcast.game.GuessNumberGame;
import cn.itcast.pojo.User;
/**
* 用户测试类
*
* @author likailong
*
*/
public class UserTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
while (true) {
System.out.println("--------欢迎页面--------");
System.out.println("1,登录");
System.out.println("2,注册");
System.out.println("3,退出");
System.out.println("请输入你的选择");
Scanner sc = new Scanner(System.in);
String ChoiceString = sc.nextLine();
UserDao ud = new UserDaoImpl();
switch (ChoiceString) {
case "1":
System.out.println("--------登录页面--------");
System.out.println("请输入用户名:");
String Usename = sc.nextLine();
System.out.println("请输入用密码:");
String Password = sc.nextLine();
boolean flag = ud.isLogin(Usename, Password);
if (flag) {
System.out.println("登陆成功");
System.out.println("你要玩游戏吗? y/n");
while (true) {
String resultString = sc.nextLine();
if (resultString.equalsIgnoreCase("y")) {
GuessNumberGame.start();
System.out.println("你还玩吗? y/n");
} else {
break;
}
}
System.out.println("谢谢使用,欢迎下次使用");
System.exit(0);
} else {
System.out.println("登陆失败");
}
break;
case "2":
System.out.println("--------注册页面--------");
System.out.println("请输入用户名:");
String newUsename = sc.nextLine();
System.out.println("请输入用密码:");
String newPassword = sc.nextLine();
User user = new User();
user.setUsername(newUsename);
user.setPassword(newPassword);
ud.regist(user);
System.out.println("注册成功");
break;
case "3":
default:
System.out.println("谢谢使用,欢迎下次使用");
System.exit(0);
break;
}
}
}
}
ArrayList实现原理源码分析
ArrayList是List接口的可变数组实例,实现了所有可选操作,并允许null在内的所有元素,除了实现List接口的所有方法还具有自己的一些方法来操作内部用来操作数组的大小。每个ArrayList实例都有一个容量,这个容量是用来存储制列表元素的数组的大小,它总是等于列表元素的大小。随着不断向ArrayList不断加元素他的长度会自动增长。自动增长带来旧数据向新数组的重新拷贝,因此在如果知道数据的大小做好自定义大小,再添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量。
注意此实现是不同步的。如果多个线程同时访问同一个ArrayList实例,而其中至少一个线程从结构改变了列表,那么他必须保证外部同步。
源代码分析
采用了快速失败机制
通过记录 modCount++;
的参数来是实现,在面对并发的修改,迭代器就会完全失败。
public class ArrayList
implements List
{
private static final long serialVersionUID = 8683452581122892189L;
/**
默认一个数组长度
*/
private static final int DEFAULT_CAPACITY = 10;
/**
*建立一个 Object[] EMPTY_ELEMENTDATA = {};数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
建立一个 Object[] EMPTY_ELEMENTDATA = {};数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
transient不能被序列化关键字
transient Object[] elementData;
private int size;//定义一个size;
构造函数
构造一个制定初始容量的空列表
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 构造一个默认长度为十的数组集合
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
构造一个包含指定Collection的元素的列表,这些元素按照该Collection集合的迭代器返回他们的顺序
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
将底层的数组的容量调成当前列表的 容量
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
调整数组长度
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
调整数组长度
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
调整数组长度
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/
public Object clone() {
try {
ArrayList> v = (ArrayList>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
@SuppressWarnings("unchecked")
public
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
// Positional Access Operations
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
throws IndexOutOfBoundsException {@inheritDoc}
*/
存储
用指定的元素代替此列表中指定位置的元素并且返回以前该位置的元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
将指定的的元素加入到列表的尾部
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
将指定的元素插入此列表的指定位置
如果当前位置有元素则向右移动当前位于该位置的元素以及所有后续元素
public void add(int index, E element) {
rangeCheckForAdd(index);//调用检查是否角标与越界的方法如果越界则抛出异常 throws IndexOutOfBoundsException {@inheritDoc}
//如果数组长度不足则进行扩容
ensureCapacityInternal(size + 1);
//将elementData中从index位置开始,长度为 size - index的元素拷贝到从下标为index + 1位置开始的新的elementData数组中,即当前位于该位置的元素和往后的的元素统一右移动
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
移除此列表中指定位置的元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
移除此列表中首次出现的指定元素如果存在应该是ArrayList的重复元素
public boolean remove(Object o) {
因为ArrayList可以存放null所以分情况
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
快速移除方法
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
按照指定的Collection的迭代器所返回的元素的顺序,将该Collection的所有元素加到此列表的尾部
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
从指定的位置将Collection的元素加到此列表中
public boolean addAll(int index, Collection extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
范围检查的方法
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
范围检查的方法
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
public boolean removeAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
public boolean retainAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}