Java类集的引出
类集实际上就属于动态对象数组,在实际开发中,数组的使用频率并不高,因为其长度固定这一特点,也成为其缺陷。为了解决此问题,Java提供了动态对象数组实现框架–Java类集框架。Java集合框架实际上就是Java针对数据结构的一种实现,而在数据结构之中,最为基础的就是链表。
Collection 集合接口
在Java的类集里(java.util)提供了两个最为核心的接口:Collection、Map接口。
Collection是单个集合保存的最大父接口。
public intterface Collection <E> extends Iterable<E>
常用方法有:
- public boolean add(E e);//向集合添加数据
- public boolean addAll (Collection < ? extends E>c);//向集合添加一组数据
- public void clean();//清空集合数据
- public boolean contains(Object o);//查找数据是否存在,要使用equals()方法
- public boolean remove (Object o);//删除数据,要使用equals()方法
- public int size ();//取得集合长度
- public Object [] toArray();//将集合变为对象数组返回
- public Iterator < E> iterator ();//取得 Iterator接口对象,用于集合输出
使用得较多的是add()和iterator()方法,还有一点,一般来说我们不会直接使用Collection接口,它只负责给我们提供一个储存数据的标准,并不能区分存储的类型,所以更多的时候是使用它的子接口:List(允许数据重复写入),Set(不允许数据重复写入,有重复数据时不报错,但不写入)
List接口
在实际开发中,List属于高频率使用,而且它扩充了两个重要方法:
- public E get (int index);//根据索引保存数据
- public E set (int index,E element);//修改数据
get()方法的存在是是List的特殊之处,属于List自己扩充方法之一,在Collection接口中是没有的,List接口有三个常用的子类:
- ArrayList //底层Array 使用90%
- Vector //底层 Array 基本不用
- LinkedList //底层 Link 使用频率 10%
ArrayList 子类(优先考虑)
基本操作
package practice;
import java.util.ArrayList;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");//数据写入
list.add("hello");//测试重复数据
list.add("Jan");
System.out.println(list);//打印
System.out.println(list.get(2));//get测试,取Jan
System.out.println(list.set(0, "morning"));//修改0号元素
System.out.println(list.size());//长度获取
System.out.println(list);//再次打印
System.out.println(list.contains("Jan"));//数据查找
System.out.println(list.contains("jan"));//数据查找
list.clear();//清空
System.out.println(list);//打印结果
}
}
//++++++++++++++++++++++++++++++++++++++
Result:
[hello, hello, Jan]
Jan
hello
3
[morning, hello, Jan]
true
false
[]
现在将List<String> list = new ArrayList<>();
替换成Collection<String> list = new ArrayList<>();
可以发现,代码中的get()、set()报错,因为这两个方法是List扩展的,在Collection中并没有,但是其他方法依然可以用。
package practice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
// List<String> list = new ArrayList<>();
Collection<String> list = new ArrayList<>();
list.add("hello");//数据写入
list.add("hello");//测试重复数据
list.add("Jan");
System.out.println(list);//打印
// System.out.println(list.get(2));//get测试,取Jan
// System.out.println(list.set(0, "morning"));//修改0号元素
System.out.println(list.size());//长度获取
System.out.println(list);//再次打印
System.out.println(list.contains("Jan"));//数据查找
System.out.println(list.contains("jan"));//数据查找
list.clear();//清空
System.out.println(list);//打印结果
}
}
//++++++++++++++++++++++++++++++++++
Result
[hello, hello, Jan]
3
[hello, hello, Jan]
true
false
[]
可以看出,List接口是Collection的子接口,所以除扩充方法外,List中的方法在Collection中依然可以使用,不过开发中依然不建议使用Collection。
集合与简单Java类
在实际开发中,集合里保存最多一般是简单Java类
class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@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 == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class TestDemo{
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("Jan", 23));//装入数据
list.add(new Person("Dog", 20));
list.add(new Person("sb", 30));
System.out.println(list);//打印一下
list.remove(new Person("sb", 30));//删除
System.out.println(list);//再打印一下
System.out.println(list.contains(new Person("Dog", 20)));
}//数据查找
}
//+++++++++++++++++++++++++++++++++
Result
[Person [name=Jan, age=23], Person [name=Dog, age=20], Person [name=sb, age=30]]
[Person [name=Jan, age=23], Person [name=Dog, age=20]]
true
值得一提的是,这里使用了remove()、contains()方法,必须要覆写equals方法,如果不覆写,上面的代码将会得到下列结果:
[Person [name=Jan, age=23], Person [name=Dog, age=20], Person [name=sb, age=30]]
[Person [name=Jan, age=23], Person [name=Dog, age=20], Person [name=sb, age=30]]
false
很容易理解,因为集合中所存放的对象都是在堆上开辟的新空间,如果不覆写equals(),仅仅比较的是地址,那么得到的结果一定是false。
古老的Vector,使用频率很低
在使用上与ArrayList并没有太大区别,将List<String> list = new ArrayList<>();
改成List<String> list = new Vector<>();
public class TestDemo {
public static void main(String[] args) {
// List<String> list = new ArrayList<>();
List<String> list = new Vector<>();
list.add("hello");//数据写入
list.add("hello");//测试重复数据
list.add("Jan");
System.out.println(list);//打印
System.out.println(list.get(2));//get测试,取Jan
System.out.println(list.set(0, "morning"));//修改0号元素
System.out.println(list.size());//长度获取
System.out.println(list);//再次打印
System.out.println(list.contains("Jan"));//数据查找
System.out.println(list.contains("jan"));//数据查找
list.clear();//清空
System.out.println(list);//打印结果
}
}
//+++++++++++++++++++++++++++++++
Result
[hello, hello, Jan]
Jan
hello
3
[morning, hello, Jan]
true
false
[]
ArrayList与Vector区别
- 产生时间:ArrayList:JDK1.2,Vector:JDK1.0。
- 处理形式:ArrayList是异步处理,性能更高;Vector是同步处理,性能较低。
- 数据安全:ArrayList是非线程安全;Vector是性能安全
- 输出形式:ArrayList支持Iterator、ListIterator、foreach;Vector支持Iterator、ListIterator、foreach、Enumeration
Vector比ArrayList多一个枚举输出Enumeration
尽管ArrayList是非线程安全,我们仍然优先考虑使用ArrayList,。如果需要考虑同步也可以使用concurrent包提供的工具将ArrayList变为线程安全的集。
linkedList子类
使用上与之前并无区别,将List<String> list = new ArrayList<>();
改成List<String> list = new LinkedList<>();
public class TestDemo {
public static void main(String[] args) {
// List<String> list = new ArrayList<>();
// List<String> list = new Vector<>();
List<String> list = new LinkedList<>();
list.add("hello");//数据写入
list.add("hello");//测试重复数据
list.add("Jan");
System.out.println(list);//打印
System.out.println(list.get(2));//get测试,取Jan
System.out.println(list.set(0, "morning"));//修改0号元素
System.out.println(list.size());//长度获取
System.out.println(list);//再次打印
System.out.println(list.contains("Jan"));//数据查找
System.out.println(list.contains("jan"));//数据查找
list.clear();//清空
System.out.println(list);//打印结果
}
}
//++++++++++++++++++++++++++++++++++++++
Result
[hello, hello, Jan]
Jan
hello
3
[morning, hello, Jan]
true
false
[]
输出结果也没有任何变化
ArrayList与LinkedList区别
ArrayList底层为数组,而LinkedList底层为链表,区别进而变为数组与链表的区别,性能,空间利用率等。
Set集合
Set接口与List的最大区别是不允许数据重复,以及没有get(),set()方法的扩充。
Set接口的两个常用子类HashSet(无序存储)、TreeSet(有序存储,升序)
public class TestDemo{
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Hello");
set.add("Hello");
set.add("Jan");
System.out.println(set);
}
}
//+++++++++++++++++++++++++++++
Result
[Hello, Jan]
当进行重复数据写入时,并没报错,但是从打印结果上可以发现,重复内容并没有被写入,而是被自动跳过了。
再来看一看顺序:
public class TestDemo{
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Jan");
set.add("J");
set.add("a");
set.add("n");
System.out.println(set);
}
}
//+++++++++++++++++++++++++++++
Result
[a, Jan, J, n]
如果按照数据写入顺序,打印结果因该是[Jan,J,a,n],然而结果却不是如此,这就是前面所说的无序。
而如果用TreeSet():
public class TestDemo{
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("J");
set.add("A");
set.add("N");
set.add("j");
set.add("a");
set.add("n");
System.out.println(set);
}
}
//+++++++++++++++++++++++++++++++++++++
Result
[A, J, N, a, j, n]
可以看出,这儿的输入内容已经被排序了。
TreeSet排序分析
和前面所提的类似,如果要排序对象,那么就要实现Comparable接口,并覆写compareTo()方法。
class Person implements Comparable<Person>{
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
if (this.age > o.age ) {
return 1 ;
}else if (this.age < o.age ){
return -1 ;
}else {
return this.name.compareTo(o.name) ;
}
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class TestDemo{
public static void main(String[] args) {
Set<Person> set = new TreeSet<>();
set.add(new Person("Jan", 23));
set.add(new Person("Dog", 20));
set.add(new Person("Dog", 20));
set.add(new Person("sb", 40));
System.out.println(set);
}
}
//+++++++++++++++++++++++++++++++++++++
Result
[Person [name=Dog, age=20], Person [name=Jan, age=23], Person [name=sb, age=40]]
从打印结果可以看到,结果被排序了,如果不实现接口Comparable,覆写compareTo()方法,结果就不一样。
重复元素判断
如果是HashSet子类,判断重复元素依靠的是Object 中的两个方法:
- hashCode()
- equals()
class Person implements Comparable<Person>{
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
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;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(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 int compareTo(Person o) {
if (this.age > o.age ) {
return 1 ;
}else if (this.age < o.age ){
return -1 ;
}else {
return this.name.compareTo(o.name) ;
}
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class TestDemo{
public static void main(String[] args) {
// Set<Person> set = new TreeSet<>();
Set<Person> set = new HashSet<>();
set.add(new Person("Jan", 23));
set.add(new Person("Dog", 20));
set.add(new Person("Dog", 20));
set.add(new Person("sb", 40));
System.out.println(set);
}
}
//+++++++++++++++++++++++++++++++++++++++
Result
[Person [name=Jan, age=23], Person [name=Dog, age=20], Person [name=sb, age=40]]
如果没有覆写或者只覆写了其中一个方法都是不行的,也就是说,必须哈hashCode()和equals()同时满足条件时才成立。
在使用时:
保存自定义对象时使用List接口;
保存系统数据时使用Set接口;
另外:
HashSet可以add()null,有且只能放一个,而TreeSet不能放null(java.lang.NullPointerException)。
集合输出
- Iterator
- ListIterator
- Enumeration
- foreach
迭代输出:Iterator(标准输出)
只要有Collection接口的子类对象,就一定有一个Iterator()取得Iterator实例化对象用于集合输出。
Iterator接口里有三个抽象方法:
- 判断是否有下一个元素: public boolean hasNext();
- 取得当前元素: public E next();
- 删除元素: public default void remove(); 此方法从JDK1.8开始变为default完整方法。
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Jan");
list.add("Dog");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {//判断下一个元素是否存在
String string = (String) iterator.next();//取得当前元素
System.out.println(string);
}
System.out.println("+++++++++++++++++++++++++++++++++++");
for (String string : list) {
System.out.println(string);
}
}
}
//++++++++++++++++++++++++++++++++++++
Result
Hello
Jan
Dog
+++++++++++++++++++++++++++++++++++
Hello
Jan
Dog
在遍历时删除元素,遍历时使用集合提供的remove()方法
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Jan");
list.add("Dog");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {//判断下一个元素是否存在
String string = (String) iterator.next();//取得当前元素
list.remove("Hello");
System.out.println(string);
}
}
}
//++++++++++++++++++++++++++++++
Result
java.util.ConcurrentModificationException
这个错误产生的原因为,在集合内部有一个ModCount记录修改次数(版本),在遍历时,修改了其中内容,ModCount与遍历之前的ModCount不一致,就会产生java.util.ConcurrentModificationException
异常。
将代码修改,使用Iterator提供的remove()
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Jan");
list.add("Dog");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {//判断下一个元素是否存在
String string = (String) iterator.next();//取得当前元素
// list.remove("Hello");
if(string.equals("Hello")) {
iterator.remove();
continue;
}
System.out.println(string);
}
}
}
//++++++++++++++++++++++++++++++++++++
Result
Jan
Dog
使用Iterator提供的remove()不会修改ModCount,所以不会产生java.util.ConcurrentModificationException
异常。
但是,仍然不建议在集合输出是进行数据修改,如果在多线程中,问题尤为明显。
双向迭代接口:ListIterator
接口提供了连个方法:
- 判断是否有上一个元素:public boolean hasPrevious();
- 取得上一个元素:public E previous();
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Jan");
list.add("Dog");
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
System.out.println("+++++++++++++++Divide+++++++++++++++++++++");
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
}
}
//+++++++++++++++++++++++++++++++++
Result
Hello
Jan
Dog
+++++++++++++++Divide+++++++++++++++++++++
Dog
Jan
Hello
双向迭代的特点就是即可以从前往后输出,又可以从后往前输出,但是值得注意的是,要想从后往前输出的前提是先要从前往后输出。,如果没有进行从前往后的输出就进行从后往前的输出:
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Jan");
list.add("Dog");
ListIterator<String> listIterator = list.listIterator();
// while (listIterator.hasNext()) {
// System.out.println(listIterator.next());
// }
System.out.println("+++++++++++++++Divide+++++++++++++++++++++");
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
}
}
//+++++++++++++++++++++++++++++++++++++++++++++
Result
+++++++++++++++Divide+++++++++++++++++++++
Hello
Jan
Dog
则从后往前输出不会执行。
Enumeration枚举输出
Enumeration接口依赖于Vector,Enumeration定义了两个个方法
- 判断是否有下一个元素:public boolean hasMoreElements();
- 取得元素:public E nextElement();
public class TestDemo{
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("Hello");
vector.add("Jan");
vector.add("Dog");
Enumeration<String> enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
// String string = (String) enumeration.nextElement();
// System.out.println(string);
System.out.println(enumeration.nextElement());
}
}
}
//+++++++++++++++++++++++++++++++++
Result
Hello
Jan
Dog
foreach输出
在前面其实就已经使用过了。
public class TestDemo{
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("Hello");
vector.add("Jan");
vector.add("Dog");
Enumeration<String> enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
// String string = (String) enumeration.nextElement();
// System.out.println(string);
System.out.println(enumeration.nextElement());
}
for (String string : vector) {
System.out.println(string);
}
}
}
//++++++++++++++++++++++++++++++++++++++++++++
Result
Hello
Jan
Dog
Hello
Jan
Dog
结果与前面的输出结果一致。
总结:
- Iterator是集合的标准输出,集合就用它输出。
Map集合
不同于Collection的每次单个对象的保存,Map每次保存的是一对对象,Key=Value的关系。
接口定义:
public interface Map<K,V>
常用方法:
public V put (K key,V value);//向map中追加数据
public V get (Object Key);//根据Key取value,没有返回null
public Set< K> KeySet();//取得所有Key信息、Key不能重复
public Collection < V> value();//取得所有value信息,可以重复
public Set < Map.Entry< K,V>> entrySet();//将Map集合转换成Set集合
Map本身也是接口,需要用子类进行实例化,Map常用的子类有四个:
- HashMap
- HansTable
- TreeMap
- ConcurrentHashMap
HashMap
HashMap是Map集合中最常用的子类。
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class TestDemo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "Jan");
map.put(2, "Dog");
map.put(10, "W");//是否有序
map.put(null, "n");//测key,value是否为null
map.put(null, "N");
map.put(null, null);
map.put(3, "Cat");//检测重复value
map.put(1, "Han");//检测重复Key
System.out.println(map);
System.out.println(map.get(10));//根据key取value
System.out.println(map.get(11));
Set<Integer> set =map.keySet();//取得所有Key
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer integer = (Integer) iterator.next();
System.out.println(integer);
}
Collection<String> collection = map.values();//取所有value
Iterator<String> iterator2 = collection.iterator();
while (iterator2.hasNext()) {
String string = (String) iterator2.next();
System.out.println(string);
}
Set<Map.Entry<Integer, String>> set2 = map.entrySet();
System.out.println(set2);
}
}
//+++++++++++++++++++++++++++++++++++++++++
{null=null, 1=Han, 2=Dog, 3=Cat, 10=W}
W
null
null
1
2
3
10
null
Han
Dog
Cat
W
[null=null, 1=Han, 2=Dog, 3=Cat, 10=W]
根据上面代码测试,可以知道HashMap的一些特性:
- 存入内容根据Key值排序(降序)
- Key值可以为null
- Value可以为null
- Key重复时旧的Key将被更新
Value可以重复
HashMap原理:
在数据量小时(JDK1.8后阀值为8)时HashMap是按照链表模式存储,而数据量变大之后就会转用红黑树(均衡二叉树)进行数据存储,用Hash码作为数据定位。
HashTable
基本操作:
public class TestDemo{
public static void main(String[] args) {
Map<Integer, String> map = new Hashtable<>();
map.put(1, "Jan");
map.put(2, "Dog");
map.put(1, "Han");//重复key
// map.put(3, null);//测value
// map.put(null, "Jan");//测key
System.out.println(map);
}
}
//++++++++++++++++++++++++++++++++++++++
{2=Dog, 1=Han}
与HashMap相比之,HashTable存入数据时按照降序排列的,但是对于Key、Value更为严格,都不允许null(java.lang.NullPointerException
),Key重复时仍然更新旧值。
ConcurrentHashMap
ConcurrentHashMap的特点 = HashTable的线程安全 + HashMap的高性能,在使用ConcurrentHashMap处理时,即可以保证即可以保证多个线程的同步,又可以保证高效的查询速度。ConcurrentHashMap不允许Key为null。
定义:
public class ConcurrentHashMap < K,V> extends AbstractMap < K,V> implements ConcurrentHashMap < K,V>,Serializable
基本操作:
public class TestDemo{
public static void main(String[] args) {
// Map<Integer, String> map = new Hashtable<>();
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "Jan");
map.put(3, "Pig");
map.put(2, "Dog");
map.put(0, "zero");
map.put(1, "Han");//重复key
// map.put(3, null);//测value
// map.put(null, "Jan");//测key
System.out.println(map);
}
}
//++++++++++++++++++++++++++++++++++++++
{0=zero, 1=Han, 2=Dog, 3=Pig}
其特性与HashMap基本一致。
工作原理:
如果采用一定的算法,将保存的大量数据平均分装不同的通(数据区域),这样查找数据就可以避免全局查找,从而提高效率。
Map集合使用Iterator输出
Map接口与Collection接口不同,Collection接口有Iterator()方法,可以很方便的取得Iterator对象来输出,而Map接口本身并没有此方法。
因此,在输出时,不能直接输出,那就借助方法实现,而Map提供了将Map集合转为Set集合的方法:
public Set < Map.Entry<K,V>> entry();
Set集合是Collection的子类,所以有Iterator。
public class TestDemo{
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "Jan");
map.put(3, "Pig");
map.put(2, "Dog");
// System.out.println(map);
//三步走
//1.转化
Set<Map.Entry<Integer, String>> set = map.entrySet();
//2.获取Iterator
Iterator<Map.Entry<Integer, String>> iterator = set.iterator();
//输出
while (iterator.hasNext()) {
Map.Entry<java.lang.Integer, java.lang.String> entry =
(Map.Entry<java.lang.Integer, java.lang.String>) iterator.next();
System.out.println(entry.getKey());
System.out.println(entry.getValue());
// System.out.println(entry.getKey()+"="+ entry.getValue());
}
}
}
//++++++++++++++++++++++++++++++++++++++++++++++
1
Jan
2
Dog
3
Pig
特别注意< Map.Entry< K,V>>的用法,以及输出时需要用get()方法取出。
自定义Key
Map中的Key可以由用户自定义,但是必须覆写hashCode()与equals()方法。
class Person {
private Integer age;
private String name;
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
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;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class TestDemo{
public static void main(String[] args) {
Map<Person, String> map = new HashMap<>();
map.put(new Person(20, "Jan"), "J");
System.out.println(map);
System.out.println(map.get(new Person(20,"Jan")));
}
}
//++++++++++++++++++++++++++++++++++++++++
{Person [age=20, name=Jan]=J}
J
TreeMap
基本操作:
public class TestDemo{
public static void main(String[] args) {
Map<Integer, String> map = new Hashtable<>();
map.put(2, "Jan");
map.put(2, "Han");//重复Key
map.put(1, "Dog");
map.put(4, "cat");
// map.put(null, "N");//Key为null
// map.put(0, null);//Value为null
System.out.println(map);
}
}
//+++++++++++++++++++++
{4=cat, 2=Han, 1=Dog}
和HashMap一样,Key、Value都不允许为null,会排序(降序),重复Key会更新。
小结:
- 有Comparable时就不再覆写hashCode()和equals()而覆写compareTo()
- Coll 保存数据的目的一般用于输出(Iterator),Map保存数据一般一般用于数据查找(无,返回null)
- Map使用Iterator时需要转换< Map.Entry< K,V>>
- HashMap数据结构、HashMap与HashTable的区别
栈与队列
栈Stack 是一种先进后出的数据结构,Java中,Stack是类,只Vector的子类,常用方法:
- public E push (E item)//入栈
- public synchronized E pop*()//出栈
- public synchronized E peek()//获取栈顶元素
public class TestDemo{
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("Han");
stack.push("Jan");
stack.push("Cat");
System.out.println(stack);
System.out.println(stack.size());
System.out.println(stack.peek());
}
}
//++++++++++++++++++++++++++++++++++++++++++
[Han, Jan, Cat]
3
Cat
队列Queue则是先进先出,需要注意的是,Queue是接口,子类是LinkedList。和List共用,到底如何执行取决于前面是Queue还是List。
常用方法:add()、poll()出队,peek()取队首
public class TestDemo{
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
queue.add("Han");
queue.add("Jan");
queue.add("Cat");
System.out.println(queue);
System.out.println(queue.peek());
queue.poll();
System.out.println(queue);
System.out.println(queue.size());
}
}
//
[Han, Jan, Cat]
Han
[Jan, Cat]
2
Properties属性文件操作
Java中有一只牛股属性文件(资源文件)的定义:*.Properties文件,在这种文件里面的内容保存形式为“Key=Value”,通过ResourceBundle类读取的时候只能读取内容,要想编辑其内容则需要通过Properties类来完成,这个类专门做属性处理。
Properties是HashTable的子类
public class Properties extends HashTable <Object,Object>
常用方法:
- 设置属性 : public synchronized Object setProperty(String key, String value)
- 取得属性 : public String getProperty(String key),如果没有指定的key则返回null
取得属性 : public String getProperty(String key, String defaultValue),如果没有指定的key则返回默认
public class TestDemo{
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty("mn", "Jan");
properties.setProperty("md", "Dog");
System.out.println(properties);
System.out.println(properties.getProperty("md"));
System.out.println(properties.getProperty("mm"));
System.out.println(properties.getProperty("mm", "Wrong"));
}
}
//++++++++++++++++++++++++++++++++++++++++++
{md=Dog, mn=Jan}
Dog
null
Wrong
Properties支持IO,store()保存,load()加载
//………..
Collections工具类
Collections是一个集合操作工具类,包含有集合反转、排序等。
public class TestDemo{
public static void main(String[] args) {
List<String> list = new ArrayList<>();
List<String> list2 = new ArrayList<>();
Collections.addAll(list, "C","B","A");//装入多个参数
Collections.addAll(list2, "Yellow","Country","Bad","And","Fuck","Beauty","Nice","Java");
System.out.println(list);
Collections.reverse(list);//反转
System.out.println(list);//查看结果
Collections.sort(list2, null);//排序
System.out.println(list2);//查看结果
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++
[C, B, A]
[A, B, C]
[And, Bad, Beauty, Country, Fuck, Java, Nice, Yellow]
如果没有实现Comparable接口,覆写compareTo()方法,则需要Collections.sort(list2, new PriceComparator()){…覆写compare()}