黑马程序员——Java之集合框架工具类Collections、Arrays以及Java新特性

时间:2023-02-24 23:25:35

内容提要:

        Collections

        Arrays

        Java新特性

        算法部分分析

Collections

        Collections是对集合框架的一个工具类,其包含的方法都是静态的,不需要创建对象,并未封装特有数据。

        在Collections工具类中大部分方法是用于对List集合进行的操作,如比较、二分查找、排序等等。

        常见操作:

        查找、替换、排序、反转、同步集合等等。

import java.util.*;

/*
* 集合框架的工具类:
* Collections:*/

public class CollectionsDemo {
public static void sop(Object obj) {
System.out.println(obj);
}

public static void main(String[] args) {
// 定义了一个List集合,存放String类型的元素
List<String> list = new ArrayList<String>();

list.add("zd");
//list.add("ay");
list.add("asc");
list.add("az");
list.add("a");
list.add("az");
sop(list); //打印原集合元素

// 使用Collections方法对List按照默认方式排序,调用String中的compareTo()方法
Collections.sort(list);
sop(list);
// 以默认方式排序后,输出最后的元素
String max1 = Collections.max(list);
sop("max1 = " + max1);

// 此外,还可以按照自定义方式排序
Collections.sort(list, new StrLenComparator());
sop(list);
// 以自定义方式排序后,输出最后的元素
String max2 = Collections.max(list, new StrLenComparator());
sop("max2 = " + max2);

//binarySearch()方法使用默认排序方式,前提是集合必须是有序的
int index1 = Collections.binarySearch(list, "ay");
//binarySearch()方法还可以使用自定义排序方式
//int index1 = Collections.binarySearch(list, "ay", new StrLenComparator());
int index2 = halfSearch(list, "ay"); // 自定义函数
//默认排序结果:[a,asc,az,az,zd];输出结果是-(2)-1
System.out.println("index1 = " + index1 + "; index2 = " + index2);
}

public static int halfSearch(List<String> list, String key) {
int min, mid, max;
max = list.size() - 1;
min = 0;

while (min <= max) {
mid = (min + max) >> 1;
String str = list.get(mid);

int num = str.compareTo(key);
if (num > 0)
max = mid - 1;
else if (num < 0)
min = mid + 1;
else
return mid;
}

return -min - 1;
}
}

class StrLenComparator implements Comparator<String> {
public int compare(String s1, String s2) {
if (s1.length() > s2.length())
return 1;
if (s1.length() < s2.length())
return -1;
return s1.compareTo(s2);
}
}

        代码分析:练习使用Collections工具类,以及常用方法。

/*
* 程序练习使用Collections上的方法
* */

import java.util.*;
public class CollectionsDemo2 {

public static void main(String[] args) {
List<String> list = new ArrayList<String>();

list.add("zd");
list.add("asc");
list.add("az");
list.add("a");
list.add("az");
sop(list);

//将集合的全部元素替换成指定内容:"az"
//Collections.fill(list, "az");
sop(list);

// 将集合的部分元素替换成指定内容:"az"-->"pp"
//Collections.replaceAll(list, "az", "pp");
sop(list);

//将集合元素反转
Collections.reverse(list);
sop(list);
}

public static void sop(Object obj) {
System.out.println(obj);
}
}

       Collections与Collection的区别:

        Collection是集合框架中的一个顶层接口,他里面定义了单列集合的共性方法。

import java.util.*;

public class CollectionsDemo3 {

public static void main(String[] args) {
reverseOrderDemo();
shuffleDemo();
}

public static void sop(Object obj) {
System.out.println(obj);
}

public static void reverseOrderDemo() {
//默认顺序
//TreeSet<String> ts = new TreeSet<String>(); //[a, asc, az, zd]

//默认顺序的反转
//TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder()); //[zd, az, asc, a]

//指定顺序的反转
TreeSet<String> ts = new TreeSet<String>(new SLComparator()); //[a, az, zd, asc]
//TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new SLComparator())); //[asc, zd, az, a]

//相当于是指定了排序的顺序,比如可以指定按照长度排序
//此外,还可以对自定义的比较器进行强行逆转,在其后增加参数即可
ts.add("zd");
ts.add("asc");
ts.add("az");
ts.add("a");
ts.add("az");
sop(ts);
}

public static void shuffleDemo() {
List<String> list = new ArrayList<String>();

list.add("zd");
list.add("asc");
list.add("az");
list.add("a");
list.add("az");

//随机地交换List集合的元素位置
Collections.shuffle(list);
sop(list);
}

}

class SLComparator implements Comparator<String>{
public int compare(String s1, String s2) //指定排序方式,字符串长度升序
{
if(s1.length() > s2.length())
return 1;
else if(s1.length() < s2.length())
return -1;
else
return s1.compareTo(s2);
}
}
        代码分析:Collections还可以对指定的顺序进行强行逆转。

Arrays

        Arrays是用于操作数组的工具类,他里面的方法也全部是静态的,不需要创建对象。

/*
* Arrays:用于操作数组的工具类
* 里面都是静态方法
* */

import java.util.Arrays;
import java.util.List;

public class ArraysDemo {

public static void sop(Object obj) {
System.out.println(obj);
}

public static void main(String[] args) {
// TODO Auto-generated method stub
String[] arr = {"abd","de","aa"};

//把数组变成List集合,优点在于:可以使用集合的思想和方法来操作数组中的元素
List<String> list = Arrays.asList(arr); //操作泛型的方法都是类对象
sop("contains(aa) = "+ list.contains("aa"));
//list.add("aa");
//注意:将数组变成集合后,不可以使用集合的增删方法。因为数组长度是固定的。
//如果进行了增删操作,那么会发生“不支持操作”异常
sop(list);

int[] nums = {1,2,3}; //将基本数据类型的数组转成集合
List<int[]> li = Arrays.asList(nums);
sop(li);

Integer[] num = {1,2,3}; //将引用类型的数组转成集合
List<Integer> l = Arrays.asList(num);
sop(l);
/*
* 如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素
* 如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在
* */

/*测试结果*/
/*contains(aa) = true
[abd, de, aa]
[[I@106d69c]
[1, 2, 3]
*/

}
}

        把数组变成List集合的好处:可以使用集合的思想和方法来操作数组中的元素。

        集合变数组

        使用Collection接口中的toArray方法。

/*
* 集合变数组
* Collection接口中的toArray方法
* 将集合元素转变成数组形式
* */

import java.util.*;

public class ToArrayDemo {

public static void sop(Object obj)
{
System.out.println(obj);
}

public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<String> al = new ArrayList<String>();

al.add("ascde");
al.add("ascde");
al.add("ascde");
/*
* 1、指定类型的数组到底要定义多长?
* 当指定类型的数组长度小于了集合size,那么该方法内部会创建一个新的数组
* 长度为集合的size;当指定类型的数组长度大于了集合的size,就不会新建数组,
* 而是使用传递进来的数组。所以创建一个刚刚好的数组是最优的。
* 2、为什么要将集合变成数组?
* 为了限定对元素的操作。
* 不需要进行增删操作,数组的size是不可变的*/
String[] st = al.toArray(new String[al.size()]);
sop(Arrays.toString(st)); //[ascde, ascde, ascde]
}

}
Java新特性

        高级for循环:

        格式:

        for(数据类型 变量:被遍历的集合或数组 ){执行语句}

        说明:

        其一、对集合进行遍历,只能获取集合元素,但是不能对集合进行操作,可以看做是迭代器的简写形式;

        其二、迭代器除了遍历,还可以进行remove集合中的元素动作,如果使用ListIterator,还可以在遍历过程中对集合进行增删改查。

        普通for循环和高级for循环的区别:

        高级for循环有一个局限性,必须有被遍历的目标(集合或数组);

        普通for循环遍历数组时有索引。建议在遍历数组的时候,还是希望使用传统for循环,因为可以定义脚标

import java.util.*;

/*
* 高级for循环
* */
public class ForDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<String> al = new ArrayList<String>();

al.add("ascde");
al.add("ascde");
al.add("ascde");
/*
Iterator<String> it = al.iterator();
while(it.hasNext())
System.out.println(it.next());
*/
for(String s : al)
{
s = "kk";
System.out.println(s);
}

System.out.println(al);

int[] aa = {1,2,3,4};
for(int a : aa) //for 循环除了遍历集合,还可以遍历基本数据类型的数组
{
System.out.println(a);
}

HashMap<Integer, String> hm = new HashMap<Integer,String>();
hm.put(1,"a");
hm.put(2,"a");
hm.put(3,"a");

Set<Integer> keySet = hm.keySet();
for(Integer i:keySet)
{
System.out.println(i+"-->"+hm.get(i));
}

for(Map.Entry<Integer,String> me : hm.entrySet())
{
System.out.println(me.getKey()+"--->"+me.getValue());
}
}

}
        方法的可变参数

        如果一个方法在参数列表中传入多个参数,但个数不确定时,就可以使用可变参数。

        可变参数,其实就是数组参数的简写,不用每一次都手动地建立数组对象,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。

/*
* 方法的可变参数使用时:
* 可变参数一定要定义在参数列表的最后面*/
public class VariableDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
show(2,3,4,4);
show();
}

public static void show(int ... a) //把[]变成了...
{
System.out.println(a.length);
}

/*
public static void show1(int[] a) //每次都有定义一个数组,作为参数传递
{

}
*/
}
        静态导入

        没加static导入的是类,加上static导入的全是某一个类中的静态成员,这样在调用该类的静态方法时可以不用再写类名。

        需要注意的是:当导入的两个类中有同名成员时,需要在成员前加上相应的类名;当类名重名时,需要制定具体的包名。

/*
* 静态导入:
* 当类名重名时,需要指定具体的包名
* 当方法重名时,需要指定所属的对象或者类
* */

import java.util.*;
import static java.util.Arrays.*; //导入的是Arrays这个类的所有静态成员
import static java.lang.System.*;

public class StaticDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {3,1,2};
//Arrays.sort(arr);
sort(arr);
//int index = Arrays.binarySearch(arr, 2);
int index = binarySearch(arr, 2);
out.println(Arrays.toString(arr)); //当方法重名时,需要用类名区分
out.println(index);
}

}
算法部分分析

        排序算法:选择排序、冒泡排序等等

/*
* 代码演示数组排序:各种排序算法实现 *
* 最优的排序方法是希尔排序,原因在于:希尔排序并不是真正地在堆内存中交换元素,而是记录交换的脚标
* 简而言之,在堆内存中交换元素,比较消耗资源
* (实践指导:)在实际开发中使用Arrays工具类
*
* */
public class Arraysort {

public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = new int[] { 0, 89, 24, 32, 11, 22, 0 }; // 新建数组对象
sopArray(array); // 输出数组内容
sortArray_bubble(array); // 冒泡排序过程
sopArray(array); // 输出数组内容

}

/*
* 代码演示数组排序:选择排序算法实现 思路: 1.一般情况下排序的结果是从小到大 2.比较方式:从0脚标位开始,依次和大于0脚标位元素比较
* 3.若符合条件,则交换;反之,不变;直到数组最后一个元素 4.再从1脚标开始,循环继续第二个步骤
*
* 选择排序的特点: 其一:从零脚标位开始,依次和之后元素比较;其二:内循环结束一次,最值出现在头脚标位置上;其三:最值出现后,不再参与比较
*/
public static void sortArray_choose(int[] array) {
for (int x = 0; x < array.length - 1; x++) {
for (int y = x + 1; y < array.length; y++) {
if (array[x] > array[y]) {
/*
* int tmp = array[x]; array[x] = array[y]; array[y] = tmp;
*/
swap(array, x, y);
} else
;
}
}
}

/*
* 代码演示数组排序:冒泡排序算法实现 思路: 1.一般情况下排序的结果是从小到大;2.比较方式:从0脚标位开始,1脚标位元素比较;
* 3.若如何条件,则交换;反之,不变; 4.将1脚标和第2脚标元素比较,依次比较相邻元素,直到最后元素 5.重复以上步骤,将相邻元素进行比较
*
* 冒泡排序的特点: 其一:相邻元素比较,如果符合条件则交换位置;其二:内循环结束一次,最值出现在最大脚标位置;其三:最值出现后,不再参与比较
*/
public static void sortArray_bubble(int[] array) { // [1,5,3,2,6]
for (int x = 0; x < array.length - 1; x++) { // 定义内层循环的次数
for (int y = 0; y < array.length - x - 1; y++) { // 定义哪些元素进行比较
if (array[y] > array[y + 1]) {
swap(array, y, y + 1);
}
}
}
}

/* 数组输出函数 */
public static void sopArray(int[] array) {
System.out.print("[");

for (int index = 0; index < array.length; index++) {
if (index != array.length - 1)
System.out.print(array[index] + ",");
else
System.out.println(array[index] + "]");
}
}

/* 排序算法的共性部分:都需要将数组元素交换位置,提取出交换位置的函数;提高代码复用性 */
public static void swap(int[] array, int a, int b) { // 方法定义中a,b的值为数组脚标
int tmp = array[a];
array[a] = array[b];
array[b] = tmp;
}
}

        查找:二分查找等等

/*
* 程序实现了折半查找方法
* */

public class searchDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[]{1,2,3,4,5,6,7};
System.out.println(halfSearch(arr,8));
}

/*折半查找方法二,可返回待插入元素的数组脚标*/
public static int halfSearchTwo(int[] arr, int key){
int min, mid, max;
min = 0;
max = arr.length-1;

while(min<=max){
mid = (min+max)/2; //将方法一种的mid = (min+max)/2语句进行整合
if(key>arr[mid])
min = mid + 1; //假如key不存在于数组中,可能最后min会大于max,即min>max成立
else if(key<arr[mid])
max = mid - 1; //假如key不存在于数组中,可能最后max会小于min,即min>max成立
else
return mid;
}

return -1; //如果想找到待插入的位置,返回min即可
}

/*折半查找方法一,提高效率*/
public static int halfSearch(int[] arr, int key){
int min, mid, max;
min = 0;
max = arr.length-1;
mid = (min+max)/2;

while(arr[mid]!=key){ //循环控制条件:是否找到key
if(key>arr[mid])
min = mid + 1; //假如key不存在于数组中,可能最后min会大于max,即min>max成立
else if(key<arr[mid])
max = mid - 1; //假如key不存在于数组中,可能最后max会小于min,即min>max成立
else
;

if(min>max)
return -1; //返回-1,表示数组中没有key值
//如果想找到待插入的位置,返回min即可

mid = (min+max)/2;
}

return mid;
}

/*常规数组查找法:循环比较数组中的每一个元素,直到找到为止*/
public static int getIndex(int[] arr, int key){
for(int index = 0; index<arr.length; index++){
if(arr[index] == key)
return index;
}
return -1; //若始终没有查找到元素,则返回-1
}
}
        进制转换:

/*
* 需求:
* 进制之间的转换
* */

public class ConversionDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
toHex(-16);
}

public static void toBin(int num) {
conversion(num, 1, 1);
}

public static void toOct(int num) {
conversion(num, 7, 3);
}

public static void toHex(int num) {
conversion(num, 15, 4);
}

public static void conversion(int num, int diwei, int yiwei) {
if (num == 0) {
System.out.println("num=" + 0);
return;
}
// 定义一个包含二进制、八进制、十六进制的表
char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

// 定义临时数组,用于装载结果
char[] arr = new char[32];

int pos = arr.length; // 数组长度 32
while (num != 0) {
arr[--pos] = chs[num & diwei]; // 末尾位置的坐标为31
num >>>= yiwei;
}

for (int x = pos; x < arr.length; x++)
System.out.print(arr[x]);

System.out.println();
}
}