数组
定义一个数组
格式:数据类型[] 数组名 = new 数据类型[长度];
格式:数据类型[] 数组名 = new 数据类型[]{值1,值2,…,值n};
格式:数据类型[] 数组名 = {值1,值2,…,值n};
集合
集合的概念:
*
* 1.数组的弊端:
* 1).长度是固定的,后期不能改变;
* 2).数组一旦定以后,其类型就固定了,只能存储此类型数据;
* 2.Java为我们提供了一些类,这些叫:集合类。这些集合类功能类似于"数组",
* 为程序员做"容器"用的。
* 3.集合的好处:
* 1).我们程序员使用集合时,可以不用关心"长度"信息,我们只需要往里面存东西,或者
* 从内部删除元素
体系结构
1.体系结构:
Collection(接口):单列集合
|--List(接口):1.有序;2.可以存储重复值
|--ArrayList(类):数组实现;线程不安全(不同步),效率高;
|--Vector(类):数组实现;线程安全的(同步),效率低;
|--LinkedList(类):链表;线程不安全的(不同步),效率高;
|--Set(接口):1.无序的;2.不能存储重复值
|--HashSet(类):哈希表;
保证元素唯一性:hashCode()和equals()
|--LinkedHashSet(类):链表、哈希表;(特例:有序的)
由链表保证顺序;
由哈希表保证唯一性;
|--TreeSet(类):树;
对元素排序和保证元素唯一性:
1.自然排序:
1).自定义类,实现:Comparable接口;
2).重写compareTo()方法;
2.比较器排序:
1).自定义比较器,实现:Comparetor接口;
2).重写compare()方法;
3).实例化TreeSet时,将自定义比较器作为参数传递给TreeSet的构造方法;
Map(接口):双列集合
|--HashMap(类):键:哈希表结构
|--LinkedHashMap(类):键:链表、哈希表结构;
|--TreeMap(类):键:树;
|--Hashtable(类):键:哈希表结构
HashMap和Hashtable的区别:
1.HashMap可以存储null键和null值;
Hashtable不能存储null键和null值;
2.HashMap线程不安全的(不同步);
Hashtabel线程安全的;
2.将数组转换为集合:Arrays-->asList()
它的返回值Arrays的内部类:ArrayLisst
对于此返回值:
不能对集合元素:新增、删除;
可以对集合元素:修改;
3.数据结构:
1).数组:查询快;增删慢;
2).链表:查询慢;增删快;
3).哈希表:综合了数组和链表的优点,查询、增、删都很快;关键取决于哈希算法;
4).栈:先进后出;
5).队列:先进先出;
6).树:小的存到左边,大的存到右边,相同的不存;
4.遍历的方式:
Collection
1).toArray();
2).iterator();
3).增强for();
|--List:
4).ListIterator:
5).Collection的size()和List的get()
|--Set:
(无)
Map
1).keySet():键集合;
2).entrySet():键值对的集合;
Collection
它是List和Set的顶层接口;
1.基本方法:
* boolean add(Object e):向集合中添加一个元素
boolean remove(Object o):从集合中移除一个元素
void clear():清空集合
boolean contains(Object o):判断集合中是否包含参数对象
boolean isEmpty():判断集合是否为空
int size():获取集合内元素的数量
2.批量的方法:
boolean addAll(Collection c):将参数集合加入到当前集合中;
boolean removeAll(Collection c):移除此 collection 中那些也包含在指定 collection 中的所有元素
boolean containsAll(Collection c):如果此 collection 包含指定 collection 中的所有元素,则返回 true。
boolean retainAll(Collection c):移除此 collection 中未包含在指定 collection 中的所有元素。
3.遍历的方法:
1.Object[] toArray():将集合中的元素转换为Object[]数组
2.Iterator iterator():迭代器
List
List(接口):1.有序的;2.可以存储重复元素
特有功能:
* void add(int index,Object element):将element添加到index位置,原index位置上的元素,及后续元素全部后移;
Object remove(int index):移除index位置上的元素;
Object get(int index):获取index位置上的元素;
Object set(int index,Object element):将index位置上的元素替换为参数的element元素
遍历的方法:
1.ListIterator listIterator():
2.结合Collection的size(),和本接口的get(int index)方法,可以使用for循环遍历;
//3.遍历集合
//方式一:ListIterator()
ListIterator listIt = list.listIterator();
while(listIt.hasNext()){
System.out.println(listIt.next());
}
System.out.println("向前遍历:");
while(listIt.hasPrevious()){
System.out.println(listIt.previous());
}
//方式二:结合Collection的size(),和本接口的get(int index)方法,可以使用for循环遍历;
for(int i = 0;i < list.size() ; i++){
System.out.println(list.get(i));
}
并发修改异常:
*
* 1.产生原因:通常是当我们使用"迭代器"遍历集合时,通过"集合对象"去修改集合中的元素,
* 这时,就会产生并发修改异常;
* 2.解决方式:
* 通过迭代器遍历,就通过迭代器去修改;
*/
自定义一个List
public class MyArrayList {
private Object[] objArray = new Object[2];
private int index = 0;
//模拟add()方法
public void add(Object obj){
objArray[index] = obj;
index++;
//判断数组是否已满,如果满,就扩容
if(index == objArray.length){
//扩容
//1.定义新数组
Object[] newArray = new Object[objArray.length * 2];
//2.将原数组中的元素复制到新数组
for(int i = 0;i < objArray.length ; i++){
newArray[i] = objArray[i];
}
//3.将原数组丢弃
objArray = newArray;
}
}
//模拟size()方法:返回当前元素的数量
public int size(){
return index;
}
//模拟get(int index)方法获取元素
public Object get(int idx){
if(idx >= this.index){
return null;
}
return objArray[idx];
}
}
链表
java 自定义一个链表
public class MyLinkedList {
//存储首链
private Box firstBox = null;
//记录元素数量
private int count = 0;
//模拟add()方法
public void add(Object obj){
//1.实例化一个Box
Box box = new Box();
box.obj = obj;
//计数器
count++;
//2.判断是否是首链
if(this.firstBox == null){
this.firstBox = box;
}else{
//3.遍历,找到最后一个链
Box tempBox = this.firstBox;
while(tempBox.next != null){
tempBox = tempBox.next;
}
//4.此时tempBox就是最后一环,将box连接上去
tempBox.next = box;
}
}
//模拟size()方法
public int size(){
return this.count;
}
//模拟get()方法
public Object get(int index){
if(index >= count){
return null;
}
//从首链开始找,并且开始计数
int n = 0;
Box tempBox = this.firstBox;
while(tempBox.next != null && n != index){
tempBox = tempBox.next;
n++;
}
return tempBox.obj;
}
private class Box{
public Object obj;
public Box next;
}
}
List三个子类的特点
|--List(接口):1.有序;2.可以存储重复值;
* |--ArrayList(类):数组实现;线程不安全的(不同步的),效率高;
* (无特有成员方法,全部使用父类的)
* |--Vector(类):数组实现;线程安全的(同步的),效率低;
* 特有成员:
* public void addElement(Object obj):将元素obj添加到集合;
public Object elementAt(int index):获取index位置上的元素;
* |--LinkedList(类):链表实现;线程不安全的(不同步的),效率高;
* 特有成员:
public void addFirst(E e)及addLast(E e)
public E getFirst()及getLast()
public E removeFirst()及public E removeLast()
LinkedList模拟栈数据结构的
public class MyLinkedList {
private LinkedList list = new LinkedList();
public void add(Object obj){
//压栈
this.list.addFirst(obj);
}
public int size(){
return list.size();
}
public Object getFirst(){
Object obj = list.getFirst();
//移除第一个元素
list.removeFirst();
return obj;
}
}
增强for的概述和使用
/*
* 增强for的概述和使用
*
* 1.增强for(也叫:foreach循环)可以很简便的语法遍历:数组、集合
* 2.例如遍历数组:编译后,被编译成"普通for循环"
* int[] intArray = {1,43,432,432,43};
* for(int n : intArray){
* System.out.println(n);
* }
* 遍历集合:编译后,被编译为"迭代器的方式"
* ArrayList<String> strList = new ArrayList<>();
* strList.add("aaa");
strList.add("bbb");
strList.add("ccc");
strList.add("ddd");
for(String s : strList){
System.out.println(s);
}
3.增强for特点:
1).在使用增强for时,没有使用"循环变量";
2).所以,如果在循环过程中需要使用循环变量,那么还得使用普通for循环;
如果不需要循环变量,只是简单的从头遍历到结尾,那么可以考虑使用"增强for";
*/
可变参数:
/*
* 可变参数:
*
* 1.在定义方法时,如果不确定需要的某种类型的形参有多少个,这时可以使用"可变参数";
* 例如:public static int sum(int ... nums){
* }
* 2.可变参数,在方法内部,按照"数组"的方式去处理;
* 3.在方法形参列表中,可变参数可以跟其它普通参数共存,但"可变参数"要位于形参列表的末尾;
* 4.调用时,对于"可变参数"的"实参"可以没有,也可以有多个;
*/
set
|--Set(接口):1.无序的;2.不能存储重复元素;
|--HashSet(类):哈希表实现;
保证元素唯一性:元素的hashCode()和equals()
|--LinkedHashSet(类):链表、哈希表实现(特例:有序的)
由链表保证顺序;
由哈希表保证元素唯一;
|--TreeSet(类):树实现;
排序和保证元素唯一性:
1.自然排序:
1).要存储的元素实现:Comparable接口
重写compareTo()方法;
"a".compareTo("b"):负数:存到左边
0:不存;
正数:存到右边
2.比较器:
1).要存储的元素无需实现任何接口;
2).自定义比较器,实现:Comparator接口
重写:compare()方法
3).在实例化TreeSet时,将自定义比较器传递给TreeSet的构造方法;
HashSet
/*
* 当使用HashSet存储自定义对象时,我们要重写hashCode()和equals()方法;
*
* 因为:HashSet内部的add()方法,先判断hashCode()是否相同,如果相同,再判断equals(),如果equals()也相同:不存;
*
* 源码:if(e.hash == hash && ((k = e.key) == key || key.equals(k))){
* }
*
*/
public class Demo {
public static void main(String[] args) {
//1.实例化一个Set
Set<Student> stuSet = new HashSet<>();
//2.填充元素
stuSet.add(new Student("刘德华",20));
stuSet.add(new Student("张学友",22));
stuSet.add(new Student("黎明",24));
stuSet.add(new Student("郭富城",26));
//添加重复元素
stuSet.add(new Student("郭富城",26));
//3.遍历
for(Student stu : stuSet){
System.out.println(stu.name + "," + stu.age);//取出时,跟存入的顺序不同;
}
}
}
public class Student {
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.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;
}
}
哈希表
HashSet源码,其实用的是HashMap
class HashSet{
private HashMap map = new HashMap();
public void add(Object obj){
map.put(obj, new Object());
}
}
class HashMap{
public void put(Object key , Object v){
//......
int hash = hash(key);//生成哈希值
}
}
TreeSet
/*
* 当使用TreeSet存储自定义对象时:
* 1.实现"自然排序":
* 1.要存储的元素实现Comparable接口;
* 2.并重写compareTo()方法;
* 或者
* 2.实现"比较器":
* 1.要存储的元素,无需实现任何接口;
* 2.自定义比较器类,实现:Comparator接口;
* 重写:compare()方法;
* 3.在实例化TreeSet时,将自定义的比较器传给TreeSet构造方法;
*/
自然排序
public class Student implements Comparable<Student>{
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
System.out.println("this.name = " + this.name + " o.name = " + o.name);
//1.先按姓名排序
int n1 = this.name.compareTo(o.name);
//2.如果姓名相同,按年龄排序
int n2 = (n1 == 0 ? this.age - o.age : n1);
return n2;
}
}
比较器排序
public class Demo {
public static void main(String[] args) {
//1.实例化一个TreeSet
TreeSet<Student> stuSet = new TreeSet<>(new MyComparator());
stuSet.add(new Student("zhangxueyou",20));
stuSet.add(new Student("liudehua",22));
stuSet.add(new Student("zhangziyi",24));
for(Student stu : stuSet){
System.out.println(stu.name + "," + stu.age);
}
}
}
class MyComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
System.out.println("o1.name = " + o1.name + " o2.name = " + o2.name);
//1.先按姓名比
int n1 = o1.name.compareTo(o2.name);
//2.如果姓名相同,比较年龄
int n2 = (n1 == 0 ? o1.age - o2.age : n1);
return n2;
}
}
树结构
Map
* Map(接口):双列集合:在存储时,同时指定两个字段;一个做"键",一个做"值"(键值对);
* |--HashMap:哈希表结构:
* |--LinkedHashMap:链表、哈希表结构:
* 1.有序的;由链表保证顺序;
* 2.由哈希表保证元素唯一;
* |--TreeMap:树结构:
* 以上Map接口的各种"数据结构"全部是针对"键"有效,跟"值"无关;
Map接口的基本功能:
Map接口的基本功能:
*
* 注:以下方法中标示为:K的表示:键,V的表示:值
*
* V put(K key,V value) :向集合中添加"键值对",如果发生重复的键,将用新值替换原值,并将原值返回;
V remove(Object key):移除key所指定的"键值对"
void clear():清空集合
boolean containsKey(Object key):判断是否包含指定key
boolean containsValue(Object value):判断是否包含指定的value
boolean isEmpty():判断集合是否为空
int size():集合中"键值对"的数量
* Map的获取功能:
* V get(Object key):使用指定key查找对应"值"
Set<K> keySet():获取所有的"键"的集合(Set集合)
Collection<V> values():获取所有"值"的集合(Collection集合)
Set<Map.Entry<K,V>> entrySet():返回所有的"键值对-对象";Entry是Map的内部类;
一个Entry内部封装了一个"键"和一个"值"
* Map的遍历方式:
*
* 1.keySet():获取所有"键"的集合,然后遍历键集合;并结合get(K key)方法获取相应的值;
* 2.entrySet():获取所有"键值对"的集合;
*
"aababcabcdabcde",获取字符串中每一个字母出现的次数
要求结果:
a(5)b(4)c(3)d(2)e(1)
public class Demo {
public static void main(String[] args) {
//1.定义字符串
String str = "aababcabcdabcde";
//2.准备一个TreeMap
TreeMap<Character,Integer> map = new TreeMap<>();
//3.遍历字符串,取出每个字符
for(int i = 0 ;i < str.length() ; i++){
char c = str.charAt(i);
//4.用"字符"做键,到map中查找相应的值
Integer value = map.get(c);
//5.value有两种情况:1).null,之前没存过;2).非null,之前已经存过了
if(value != null){
value++;
//用字符做键,新的value做值,再次添加到集合中;将会用新值替换原值
map.put(c, value);
}else{
map.put(c, 1);
}
}
//封装结果字符串
StringBuffer buf = new StringBuffer();
//遍历集合
Set<Character> keys = map.keySet();
for(char c : keys){
buf.append(c).append("(").append(map.get(c)).append(")");
}
System.out.println(buf);
}
}