一、了解一下数据结构
- java中的集合,不同种类的集合内部元素的存储和组织方式是不一样的,集合元素采用什么方式进行存储往往决定了该集合具有什么样的特征,比如有的集合查询快,有的集合增删快,以及集合元素是否能够重复等。
- 所谓的数据结构就是数据如何存储,数据之间的关系,数据的表现形式,以及在特定的存储类型之上所提供的特定的算法。
二、了解常用的数据结构
三、List集合
-
凡是实现了List接口的集合都称为List集合。实现List接口的集合的基本特征:
- 属于列表
- 元素带有索引,可以根据索引来操作元素
- 集合中的元素可以重复(同一个对象可以在集合中存在多份),集合中也可以出现空值(null)。
-
List 接口继承了 Collection 接口,因此 Collection 接口的方法都被 List 所拥有,而 List 本身也具有自己的方法,List 自己的方法多半使用了元素的索引。
-
List 集合有两个当下需要了解的实现类:
- ArrayList 类,内部就是一个数组,它又称为可变长度的数组,有序的。查询快,增删慢,后面使用的集合多半要求查询速度快,ArrayList 要更常用些。
- LinkedList 类,内部是一个链表,还是双向的。它也有索引,它与 ArrayList 的很多方法都是相同的(同样接口的实现)。也有一些方法属于它自身的方法,这些自身的方法与链表的特定结构有关系。链表多半都被当做堆栈或队列使用,因为它查询效率低,增删效率高,而堆栈和队列的主要操作就是增删。
package com.zhong.test_3; import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); /*//第一次压栈 list.push("e1"); //第二次压栈 list.push("e2"); //第三次压栈 list.push("e3"); System.out.println(list.pop()); System.out.println(list.getFirst());*/ list.addFirst("e1"); list.addFirst("e2"); list.addFirst("e3"); System.out.println(list.getFirst()); } }
四、Set 集合
-
凡是实现了 Set 接口的集合都称为 Set 集合。Set 集合的基本特征:
- 元素无序
- 元素无索引
- 不能存放重复的元素,最多允许有一个空元素
-
Set 接口继承了 Collection 接口,所以 Collection 的方法 Set 都有。Set 接口也有自己的方法,这些方法反应出 Set 的基本特征。
-
Set 接口的实现类
-
HashSet 类,它内部元素的数据结构属于散列的结构,所谓散列就是元素在集合中的位置由元素自身的 Hash 值决定,Object 中有一个 hashCode 方法,返回对象的哈希值,它的值决定了元素在 HashSet 集合中的位置。这也就是我们认为哈希值就是对象的地址的原因。一个 HashSet 集合内部划分为多个桶,各元素的哈希值就决定了该元素放在哪个桶里。它可以把元素均匀的放在集合的内部。
- HashSet 的元素是通过 hash 值类寻址,大多数对象的 hashCode 方法没有被重写,不同的对象 hash 值一定不同。
- 有时候,我们并不会按照java默认的规则来判断两个对象是否是同一个对象,最常见的就是通过对象的属性值来判断两个对象是否是同一个对象,这种情况下就必须要重写 equals 和 hashCode 方法,此时对象的判断标准就发生了变化。在 HashSet 中,判断两个元素是重复元素的标准是两个元素 equals 比较的值返回 true ,如果是 false 则表示两个元素不重复。
package com.zhong.test_3; import java.util.HashSet; import java.util.Iterator; import java.util.Objects; import java.util.Set; public class SetDemo { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("e1"); set.add("e2"); set.add("e3"); set.add("e3"); System.out.println(set.size()); set.remove("e2"); //迭代集合 for (String s : set) { System.out.println(s); } //1.5之前 Iterator<String> iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } Dog d1 = new Dog("哈哈",2); Dog d2 = new Dog("哈哈",2); Dog d3 = new Dog("嘻嘻",2); System.out.println(d1 == d2); System.out.println(d1.equals(d2)); System.out.println(d1.equals(d3)); Set<Dog> set1 = new HashSet<>(); set1.add(d1); set1.add(d2); set1.add(d3); System.out.println(set1.size()); } } class Dog{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Dog dog = (Dog) o; return age == dog.age && Objects.equals(name, dog.name); } @Override public int hashCode() { return Objects.hash(name, age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
-
五、可变参数
- 方法的形参可以是基本类型也可以是引用类型,参数的个数可以没有,也可以有多个。
- 如果方法的参数是数组类型,那么需要针对该参数传递数组对象。可是有时候需要传递数组但是又不确定数组中元素的个数是多少,jdk1.5就出现了可变参数。
- 所谓可变参数指的是参数的个数可多可少,甚至为0。
- 声明语法:(可变参数类型… 形参)
- 使用中注意:方法中如果有可变参数,还可以有其他的参数;一个方法中可变参数只能有一个;可变参数必须放在所有参数的后面(除非无其他参数)。
package com.zhong.test_2;
public class ChangedParamDemo {
private static void sum(int... nums){
//可变参数可以当做数组来用。可变参数只能有一个
int sum = 0;
/*for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}*/
for (int num : nums) {
sum += num;
}
System.out.println(sum);
}
public static void main(String[] args) {
int[] nums = {1,2,3,4};
sum();
sum(1);
sum(1,2);
sum(1,2,3);
sum(nums);
}
}
六、集合工具类
-
jdk中针对数组提供了数组的工具类 Arrays。针对集合也提供了工具类 Collections,也在工具包中。Collections 类中都是静态方法,这些方法可以针对集合进行各种操作。
-
集合的排序:
- 针对 String 元素的集合进行排序 sort(list),结构是所有元素按照以字典的升序进行排列。String 类实现了 Comparable< String > 接口,该接口在lang包中,接口中的 int compareTo(T o) 方法传入的是需要与当前元素进行比较的另一个元素对象,如果返回值为1就表示当前元素大于传入的元素,为-1则相反,为0则相等。以上规则是jvm的比较规范,使用时一定要按照此规范返回结果。
- 在执行 sort() 方法时,compareTo 方法会被调用,该方法的返回值就决定了两个字符串的大小。如果我们需要针对自己所定义的类的对象进行大小比较,就可以让本对象实现 Comparable 接口,通过int compareTo(T o) 来给出比较规则。
- 以上方式要求类实现接口,jdk 中有一些固有的类如果需要比较它们对象的大小都会实现该接口,但是实现接口会对类造成侵入。
package com.zhong.test_2; import java.util.*; public class CollectionsDemo { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("e1"); set.add("e2"); set.add("e3"); Collections.addAll(set,"e4","e5","e6"); System.out.println(set.size()); List<String> list = new ArrayList<>(); Collections.addAll(list,"yi","ho","x1","ml","ab","x2"); System.out.println(list); //排序 Collections.sort(list); System.out.println(list); Dog d1 = new Dog("嘻嘻",2); Dog d2 = new Dog("哈哈",4); Dog d3 = new Dog("呵呵",3); Dog d4 = new Dog("啦啦",1); ArrayList<Dog> arrayList = new ArrayList<>(); Collections.addAll(arrayList,d1,d2,d3,d4); System.out.println(arrayList); Collections.sort(arrayList); System.out.println(arrayList); } } class Dog implements Comparable<Dog>{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Dog o) { return -(this.age - o.age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return this.name + "->" + this.age; } }
-
在工具包中提供了 Comparator< T > 接口,它称为比较器接口,使用该接口作为比较器,需比较的类上并不需要实现该接口,这种方式更灵活。如果我们的自定义类需要实现大小比较,使用该接口是比较好的选择。
Collections.sort(arrayList, new Comparator<Dog>() {
@Override
public int compare(Dog o1, Dog o2) {
return -(o1.getAge() - o2.getAge());
}
});