java基础【HashSet,ArrayList,TreeSet集合,泛型,iterator迭代器,HashMap,properteries,Collections工具类】
1、解决的问题实现批量对象的存储,集合比数组更加灵活。数组长度、类型都固定。可将集合看做一个可变长度的Object数组。2、Java集合框架框架一般意味着类,接口,抽象类等各种东西都很多。当学习一个框架时,要清楚有接口,接口下面有抽象类,抽象类下面有具体类。当面对一个框架时,首要任务是去学习这个框架的接口。3、Collection接口APICollection集合:保存一个一个的对象,特点是 无序
1、解决的问题
实现批量对象的存储,集合比数组更加灵活。数组长度、类型都固定。可将集合看做一个可变长度的Object数组。
2、Java集合框架
框架一般意味着类,接口,抽象类等各种东西都很多。当学习一个框架时,要清楚有接口,接口下面有抽象类,抽象类下面有具体类。当面对一个框架时,首要任务是去学习这个框架的接口。
3、Collection接口API
Collection集合:保存一个一个的对象,特点是 无序可重复
无序:不按照顺序存放元素,并不按照物理存储空间的连续存储,并且重复的元素也可以添加。一般不用,使用的是它的两个实现:
Set 子接口:无序 不可重复
HashSet :又称散列表,基于数组使用哈希算法实现的set集合,使用频率最高。每次添加元素时,使用哈希函数计算出哈希码,哈希码即为要插入的位置,当两个不同的数据哈希码相同时,称为冲突,当发生冲突时,解决冲突即可。底层实现就是HashMap。
优缺点:除了对内存要求高外,其余全是优点。插入、删除、遍历性能都为最优。
去重规则:两个对象的equals为true,并且两个对象的哈希码(hashcode)相同。
TreeSet : 使用二叉搜索树(平衡二叉树)结构实现的set集合,可以达到数字的自然排序。
去重规则:两个对象的比较结果(compareTo)等于0,即比较的部分相同,就去重。
优点:对内存要求低,和链表一样,只需要有一个节点(非线性)就足够了。检索性能很优秀。
缺点:插入删除速度慢。
List 子接口:有序可重复 有序(按照添加顺序依次存放)
ArrayList:使用数组实现的List集合,线程不安全,但是没关系,有其他方法保证其安全。
缺点:对内存要求高,内存必须是一片连续的存储空间,插入和删除的时间复杂度很高,有大量元素的移动。
适用场景:存档数据,很少进行插入和删除,主要用于查询检索。
Vector:和ArrayList一模一样,是一个古老的实现,线程安全。
LinkedList:使用链表实现的List集合,对于频繁的插入和删除元素操作,建议使用LinkedList,效率较高。
优点:对内存要求低,插入删除时间复杂度很低。
缺点:检索速度慢。
适用场景:频繁修改数据,很少进行检索。
泛型:类型安全问题,在集合中使用泛型的好处是约束集合中的元素数据类型,类型可以是确定的,不再是模糊的Object。
在运行的角度来讲是没有泛型的,底层只是一个ArrayList集合,加入泛型可以让编译器进行检查。
Map集合:保存一对一对的对象,用于保存一对映射关系的数据key-value(y = f(x))。通过指定的key可以找到唯一确定的value。可以简化的看做一个set集合,只不过其中存储的元素是Entry。其中key为一个set集合,无序不可重复。
常见的实现:
HashMap:
存放key的集合是HashSet。典型实现,使用哈希算法实现的Map集合。
LinkedHashMap:
是HashMap的子类,可以维护Map的迭代顺序,迭代顺序与key-value对的插入顺序一致
TreeMap:
存放key的集合是TreeSet。基于二叉树实现的Map集合,针对key可以进行排序。自然排序,定制排序。判断两个key相等的标准:compareTo()方法返回0。
HashTable:是古老的实现,和HashMap一样,他是线程安全,效率低,一般不用。
Properties是HashTable的子类,配置文件。
4、Iterator迭代器接口
遍历:增强for
for(元素数据类型 临时变量 : 集合){}
迭代器:Iterator对象称为迭代器(是一种设计模式),主要便利Collection集合中的元素。其中hasNext()方法用来检测当前游标后面是否有下一个元素,如有返回true,反之返回false,当返回true时,调用next()方法可以访问游标后面的下一个元素并且移动游标,如果调用next()方法前,没有使用hasNext()方法进行检测,会抛出异常。
必须从集合对象获取迭代器,不可以new。
@Test
public void test(){
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10; i++){
list.add((int)(Math.random() * 20));
}
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
System.out.print(next + " ");
}
}
注意:
(1)迭代器一旦获取到,就应该马上使用,如果中间出现了对象集合的修改,都会导致迭代器失效。
(2)在循环中只能调用一次next()方法。
(3)迭代器是一次性使用,使用完就作废。
迭代器逻辑性很强,增强for则不然,是为了统一数组和集合的遍历而出现,迭代器只用于对于集合的遍历。
5、Collection子接口:Set接口
无序不可重复
HashSet
创建HashSet集合,添加,删除,查找(是否包含),遍历操作
class Student{
private String name;
private int grade;
private double score;
public Student() {
}
public Student(String name, int grade, double score) {
this.name = name;
this.grade = grade;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "student{" +
"name='" + name + '\'' +
", grade=" + grade +
", score='" + score + '\'' +
'}';
}
}
@Test
public void test(){
HashSet hashSet = new HashSet();
hashSet.add("abc");
hashSet.add("zsd");
hashSet.add(new Integer(100));
hashSet.add(new Student("小明",4,73.0));
hashSet.add(200); //自动装箱,set.add(Integer.valueOf(100));
boolean b1 = hashSet.add(100); //添加失败,重复元素不能添加
System.out.println(b1);
boolean b2 = hashSet.add("abc"); //添加失败,重复元素不能添加
System.out.println(b2);
System.out.println(hashSet.size());
System.out.println(hashSet);
System.out.println(hashSet.contains("hfd"));
hashSet.remove(100); //删除
System.out.println(hashSet);
//增强for循环
for(Object i : hashSet){
System.out.println(i);
}
}
练习:创建set集合,添加10个20以内的随机整数。
@Test
public void exer(){
Set set = new HashSet();
while(set.size() < 10){
int rand = (int)(Math.random() * 20);
set.add(rand);
}
System.out.println(set);
}
注意:
HashSet去重时的依据是两个对象equals是否为true,并且两个对象的哈希码也相同。在没有重写equals()时,比较的是两个学生对象的地址。
@Test
public void test2(){
HashSet hashSet = new HashSet(); //无序不可重复
Student s1 = new Student("小明", 3, 88);
Student s2 = new Student("小明", 3, 88);
Student s3 = new Student("小王", 3, 98);
hashSet.add(s1);
hashSet.add(s2); //添加成功
hashSet.add(s3);
hashSet.add(s3); //添加失败
for(Object object : hashSet){
System.out.println(object);
}
}
此时若想保留去重功能,则需要重写equals()和hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return grade == student.grade &&
Double.compare(student.score, score) == 0 &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, grade, score);
}
}
LinkedHashSet
TreeSet(二叉树)
无序不可重复,其中无序指的是添加的顺序,并不是数字本身代表大小的顺序。使用此种数据结构,会在其内部实现自然排序。因为会实现排序,所以如果在添加的数据中包含两种不同的数据类型,则会抛出异常(类型转化异常)。
@Test
public void test3(){
Set set = new TreeSet();
set.add(50);
set.add(40);
set.add(60);
set.add(30);
set.add(90);
set.add(80);
set.add(10);
for(Object object : set){
System.out.println(object);
}
想要把数据放到TreeSet中,需要使数据具备可比较的能力。
去重规则:两个对象的compareTo返回0,即比较的部分相同,就去重。
//在Student类中实现Compareable接口,重写compareTo方法
@Override
public int compareTo(Object o) { //父类中此方法没有抛出异常,所以重写后也不能抛出受检异常
if(o instanceof Student){
return this.grade - ((Student) o).grade;
}
throw new RuntimeException("对象不可比"); //抛出非受检异常
}
@Test
public void test4(){
Set set = new TreeSet();
Student s1 = new Student("小明", 3, 88);
Student s2 = new Student("小明", 4, 88);
Student s3 = new Student("小王", 1, 98);
set.add(s1);
set.add(s2);
set.add(s3);
for(Object object : set){
System.out.println(object);
}
}
当对象内部无法自己比较大小,或者是谁大谁小有争议时,可以使用第三方机构,当Student类不实现Comparable接口,不能比较时,就可以请出第三方的比较机构,称为比较器Comparator,专门用来比较对象,里面的方法为int compare(T o1, T o2),o1和o2去比较。在jdk中没有现成的比较器,需要手工去写。
class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2){
if(o1 instanceof Student && o2 instanceof Student){
return ((Student) o1).getGrade() - ((Student) o2).getGrade();
}
throw new RuntimeException("对象不可比");
}
}
@Test
public void test5(){
MyComparator myComparator = new MyComparator();
//定制排序
Set set = new TreeSet(myComparator);//对象关联,大部分是通过构造器来关联
//TreeSet内部拥有了Comparator比较器
Student s1 = new Student("小明", 3, 88);
Student s2 = new Student("小明", 4, 88);
Student s3 = new Student("小王", 1, 98);
set.add(s1);
set.add(s2);
set.add(s3);
for(Object object : set){
System.out.println(object);
}
}
通过比较器进行排序(定制排序)更加灵活,可以根据任意规则进行排序。
当类内部拥有比较功能并且也有定制排序,则优先使用定制排序,因为定制排序更加高级。
因为MyComparator类只使用一次。所以更加常用的方式是使用匿名内部类。
//定制排序
Set set = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Student && o2 instanceof Student){
return ((Student) o1).getGrade() - ((Student) o2).getGrade();
}
throw new RuntimeException("对象不可比");
}
});//对象关联,大部分是通过构造器来关联,TreeSet内部拥有了Comparator比较器
6、Collection子接口:List接口
有序可重复
ArrayList
对ArrayList的增删改查,遍历
@Test
public void test1(){
List List = new ArrayList(); //有序可重复
List.add(199);
List.add(new Student("小明",5,43));
List.add(199);
List.add(new Integer(43));
System.out.println(List);
System.out.println(List.size());
List.add(4,"插入的元素"); //在指定位置插入元素
System.out.println(List);
Object o = List.get(4); //获取指定下标的元素
System.out.println(o);
List.remove(4); //删除指定下标的元素
System.out.println(List);
//遍历
for(int i = 0; i < List.size(); i++){
System.out.println(List.get(i));
}
}
创建List集合,存储10个20以内的随机整数,不要重复的
@Test
public void exer1(){
List list = new ArrayList();
for(int i = 0; i < 10; i++){
int rand = (int)(Math.random() * 20);
if(list.contains(rand)){
i--;
}else{
list.add(rand);
}
}
for(int i = 0; i < 10; i++){
System.out.print(list.get(i));
System.out.print(" ");
}
}
ArrayList非常灵活,可以存储任意数据类型的元素,那么当对ArrayList中的元素进行某一操作时,如整数求和,会非常麻烦。所以使用泛型技术,可以约束集合中能够保存的元素的类型,在类名后面加一对<>,<>内部填写元素数据类型。
泛型解决的是类型安全的问题,因为默认的Object类型太模糊了。一旦在集合中使用了泛型,简化了集合的使用,向数组靠拢,但又不是数组,不同数据类型的元素不能添加。
@Test
public void test6(){
List<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(5);
//list.add("444"); //添加失败
}
练习:创建一个List集合,保存随机的10个整数,对其进行排序。再将所有的元素保存在另一个HashSet中,找出最大值。
//创建List集合,保存随机的10个整数,并对其进行排序
//再将List中所有元素存储到HashSet中,找出最大值
@Test
public void work(){
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add((int)(Math.random() * 20));
}
System.out.println(list);
for(int i = 0; i < list.size() - 1; i++){
for(int j = 0; j < list.size() - 1 - i; j++){
if(list.get(j) > list.get(j + 1)){
Integer temp = list.get(j);
list.set(j,list.get(j+1));
list.set(j + 1,temp);
}
}
}
System.out.println(list);
Set<Integer> set = new HashSet<>();
for(int i = 0; i < list.size(); i++){
set.add(list.get(i));
}
System.out.println(set);
int max = 0x80000000;
for(Integer integer : set){
if(integer > max){
max = integer;
}
}
System.out.println("max:" + max);
}
7、Map接口
Map集合:保存的是一对一对的对象,是具有映射关系的健值对象,健值对象都可以是任意对象,健到值是单向一对一映射。
常用方法:
Object put(Object key,Object value);// 写入条目
Object remove(Object key);// 根据健删除一个条目
Object get(Object key);// 根据健查找值
Set keySet();// 获取一个保存所有健对象的Set子集合
Set entrySet();// 获取保存所有条目对象的Set集合
int size();// 条目个数
HashMap
HashMap集合的增删查
@Test
public void test1(){
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1,"one");
map.put(10,"ten");
map.put(0,"zero");
map.put(11,"eleven");
map.put(2,"two");
map.put(2,"TWO"); //当key重复时,会刷新value
map.put(3,"three");
map.put(1,"one");//key,value不可以重复,添加失败
System.out.println(map.size());
map.remove(1);
//System.out.println(map);
System.out.println(map.get(2));
//遍历一,获取所有健
Set<Integer> keySet = map.keySet();
Iterator<Integer> iterator = keySet.iterator();
while(iterator.hasNext()){
Integer key = iterator.next();
String value = map.get(key);
System.out.print(key + "=" + value + " ");
}
System.out.println();
//遍历二,获取所有条目
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
for(Map.Entry<Integer,String> entry : entrySet){
System.out.print(entry.getKey() + "=" + entry.getValue() + " ");
}
}
练习:创建Map集合,存放圆的半径和面积,将半径为1-50的面积保存在其中,将Map中的半径数据截取至Set集合中,遍历Set集合,逐一取出对应的value。
@Test
public void test2(){
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i = 1; i < 51; i++){
map.put(i, (int)(Math.PI * i * i));
}
Set<Integer> set = map.keySet();
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
Integer key = iterator.next();
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
}
HashMap判断两个key(value)相等的标准是两个key(value)的equals()方法返回true,hashCode相等。
TreeMap
Hashtable
Properties
是Hashtable的子类,专门用于处理配置文件(文本文件,内容是健=值),使用频率极高
创建配置文件test.properties.
url=http://www.baidu.com
user=root
password=123456
password=hello
@Test
public void test3() throws IOException {
Properties properties = new Properties();
properties.load(new FileInputStream("test.properties"));
System.out.println(properties);
String password = properties.getProperty("password");
System.out.println(password);
}
练习:将学生姓名与考试分数录入到map中,按照分数显示前三名的成绩与姓名。
public class HomeWork {
@Test
public void test(){
//将学生姓名与考试分数录入到map中,按照分数显示前三名的成绩与姓名
//创建HashMap存储学生信息,key为学生姓名,value为学生考试成绩
Map<String, Integer> map1 = new HashMap<>();
map1.put("张三",80);
map1.put("李四",100);
map1.put("王五",90);
map1.put("赵六",100);
map1.put("小明",99);
//创建比较器,并且不允许去重,修改compare内部代码
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int n = o2 - o1;
if(n == 0){
n = 1;
}
return n;
}
};
//创建TreeMap集合,将HashMap集合中的学生信息key,value调换位置进行存储,完成学生成绩的排序
Map<Integer, String> map2 = new TreeMap<>(comparator);
//将key value在HashMap中取出
Set<String> keySet = map1.keySet();
Iterator<String> iterator = keySet.iterator();
while(iterator.hasNext()){
String key = iterator.next();
Integer value = map1.get(key);
map2.put(value,key);
}
//将取出的数据,存入到TreeMap中
Set<Map.Entry<Integer, String>> entrySet = map2.entrySet();
Iterator<Map.Entry<Integer, String>> iterator1 = entrySet.iterator();
//取出成绩前三名的同学信息
int count = 0;
while(iterator1.hasNext()){
Map.Entry<Integer, String> entry = iterator1.next();
System.out.println(entry.getKey() + entry.getValue());
if(++count == 3){
break;
}
}
}
}
练习:给定一个字符串,统计每个字符出现的次数
思路一:使用HashMap
@Test
public void test1(){
//给定一个字符串,统计每个字符出现的次数
//字符作为key,出现的次数作为value
String s = "aaabbbcccdddeeefffshkgswl我是汉字烦死了这么长女女女女女女你妈妈可抵扣积分";
Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < s.length(); i++){
char ch = s.charAt(i); //获取到字符
Integer count = map.get(ch); //记录出现次数
if(count == null) { //之前没有put过,返回值是null,
count = 0;
}
map.put(ch, count + 1);
}
System.out.println(map);
}
思路二:使用数组
@Test
public void test2() {
//给定一个字符串,统计每个字符出现的次数
String s = "aaabbbcccdddeeefffshkgswl我是汉字烦死了这么长女女女女女女你妈妈可抵扣积分";
int[] arr = new int[65535];
for(int i = 0; i < s.length(); i++){
char ch = s.charAt(i);
arr[ch]++;
}
for(int i = 0; i < arr.length; i++){
if(arr[i] != 0){
System.out.println((char)i + ":" + arr[i]);
}
}
8、Collections工具类
是一个操作Set,List和Map等集合的工具类,内部均为静态方法。
对List集合的排序,翻转,洗牌。
@Test
public void test4(){
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10; i++){
list.add((int)(Math.random() * 20));
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
查找最大值最小值
Integer max = Collections.max(list);
System.out.println(max);
Set<Integer> set = new HashSet<Integer>(list);
Integer min = Collections.min(set);
System.out.println(min);
更多推荐
所有评论(0)