集合 的体系:
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
--------------------| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
--------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
--------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。
1. HashSet
hashSet的实现原理:
往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,
然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。
情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。
使用 TreeSet完成。
思路: 1,将字符串切割。
2,可以将这些对象存入TreeSet集合。 因为TreeSet自身具备排序功能
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
--------------------| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
--------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
--------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。
---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。
无序: 添加元素 的顺序与元素出来的顺序是不一致 的。
1. HashSet
hashSet的实现原理:
往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,
然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。
情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。
情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,
如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行 添加。
hashCode
public class test_1{
public static void main(String args[]) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println("两个是同一个对象吗? " + (str1 == str2));
System.out.println("str1的hashCode: " + str1.hashCode());
System.out.println("str1的hashCode: " + str2.hashCode());
// hashCode默认情况下表示的是内存地址,string 类已经重写了object的hashCode方法
}
}
运行结果:
两个是同一个对象吗? false
str1的hashCode: 99162322
str1的hashCode: 99162322
hashCode 的源码是:
/* 源码 注意: 如果两个字符串的内容一致,那么返回的hashCode 码也会一致。
* public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}*/
实例: 接受键盘录入用户名与密码,如果用户名与密码已经存在集合中,那么就是视为重复元素,不允许添加到HashSet中。
使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)
import java.util.HashSet;
import java.util.Scanner;
class People{
String username;
String password;
public People(String username, String password) {
super();
this.username = username;
this.password = password;
}
@Override
public String toString() { // 重写 String
return "用户名: " + this.username + " 密码: " + this.password;
}
@Override
public boolean equals(Object obj) { // 重写 equals
People p1 = (People)obj;
return this.username.equals(p1.username) && this.password.equals(p1.password);
}
@Override
public int hashCode() { // 重写 hashCode
return username.hashCode() + password.hashCode();
}
}
public class test_1{
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
HashSet set = new HashSet();
while (true) {
System.out.println("请输入用户名");
String username = scanner.next();
System.out.println("请输入密码: ");
String password = scanner.next();
// 创建一个对象
People p1 = new People(username, password);
if(set.add(p1)) {
System.out.println("注册成功");
System.out.println(set);
}else {
System.out.println("注册失败");
}
}
}
}
运行结果:
请输入用户名
fzx
请输入密码:
000
注册成功
[用户名: fzx 密码: 000]
请输入用户名
fzx
请输入密码:
000
注册失败
请输入用户名
2. TreeSet
红黑树算法的规则: 左小右大。
既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。
1: 让存入的元素自定义比较规则。
2: 给TreeSet指定排序规则。
方式一:元素自身具备比较性
元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
1: 让存入的元素自定义比较规则。
2: 给TreeSet指定排序规则。
方式一:元素自身具备比较性
元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性,也就是自定义比较器。
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
/// 实例:
import java.util.Comparator;
import java.util.TreeSet;
class emp implements Comparable{
//class emp {
int id;
String name;
int salary;
public emp(int id, String name, int salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return " {编号: " + this.id + " 姓名: " + this.name + " 薪水: " + this.salary + "} ";
}
@Override
// 返回:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象
public int compareTo(Object obj) {
emp e = (emp) obj;
System.out.println(this.name + "比较" + e.name);
return this.salary - e.salary;
}
}
class Mycomparator implements Comparator{
@Override
public int compare(Object obj1, Object obj2) {
emp e1 = (emp)obj1;
emp e2 = (emp)obj2;
return e1.id-e2.id;
}
}
public class test_1{
public static void main(String args[]) {
Mycomparator compare = new Mycomparator();
// 创建TreeSet对象,传入比较器;
TreeSet tree = new TreeSet(compare);
// TreeSet tree = new TreeSet();
/* tree.add(1);
tree.add(7);
tree.add(4);*/
/*tree.add('b');
tree.add('a');
tree.add('c');*/
tree.add(new emp(3, "付祖贤", 10000));
tree.add(new emp(1, "女侠", 15000));
tree.add(new emp(2, "仙女", 20000));
tree.add(new emp(4, "女神经", 20000));
System.out.println(tree);
}
}
让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo 方法。运行结果:
女神经比较女侠
女神经比较仙女
[ {编号: 3 姓名: 付祖贤 薪水: 10000} , {编号: 1 姓名: 女侠 薪水: 15000} , {编号: 2 姓名: 仙女 薪水: 20000} ]
容器自身具备比较性,定义一个类实现Comparator 接口,覆盖compare方法。使用自定义的比较器:
[ {编号: 1 姓名: 女侠 薪水: 15000} , {编号: 2 姓名: 仙女 薪水: 20000} , {编号: 3 姓名: 付祖贤 薪水: 10000} , {编号: 4 姓名: 女神经 薪水: 20000} ]
// TreeSet练习一:
import java.util.TreeSet;
/* *
* TreeSet 是可以对字符串进行排序的,因为字符串已经实现了Comparable接口
*
* 字符串比较规则:
* 1. 找到对应不同的字符,比较的就是对应位置上的字符;
* 2. 找不到对应不同的字符,比较字符串的长度;
*/
public class test_1{
public static void main(String args[]) {
TreeSet tree = new TreeSet();
tree.add("aacccccccc");
tree.add("ab");
tree.add("aw");
System.out.println(tree);
}
}
运行结果:
[aacccccccc, ab, aw]
TreeSet练习二 : 将字符串中的数值进行排序。
例如String str="8 10 15 5 2 7"; 2,5,7,8,10,15使用 TreeSet完成。
思路: 1,将字符串切割。
2,可以将这些对象存入TreeSet集合。 因为TreeSet自身具备排序功能
public class test_1{
public static void main(String args[]) {
String num = "10 12 8 3 16 20 42";
String[] num2 = num.split(" ");
TreeSet tree = new TreeSet();
for(int i=0; i<num2.length; i++) {
// tree.add(num2[i]);
// 字符串转int类型数据是需要使用 Integer.parseInt
tree.add(Integer.parseInt(num2[i]));
}
System.out.println(tree);
}
}
运行结果:
[3, 8, 10, 12, 16, 20, 42]