黑马程序员--java基础复习集合框架工具类及其他对象

时间:2023-02-24 23:07:15
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
    前面一章,讲到了集合,这里大略回忆下,最上级Collection接口下的基本方法,如add(),remove(),equals(),contains(),hashCode(),isEmpty(),iterator()等基本方法,即其下面的子接口或实现类都能使用或复写的功能。接着是List集合,其特点是有序的,可以重复的,因为它带有索引。另一个就是Set集合,特点是无序的,不可重复的。 List集合是带有索引的,所以凡是可以操作角标的方法都是该体系中的特有方法。Collection的实现类都可以使用Iterator  迭代器  ,在使用迭代器迭代的过程中,我们可以对元素进行判断(hasNext()),获取(next()),以及删除(remove)。而在List集合下,却又比Set集合多了个功能:列表迭代器(ListIterator),其在迭代的过程中,我们可以对元素进行增删改查功能。 List下面三员大将。分别是Arraylist、LinkedList,还有老将Vector。ArrayList和Vector的底层都是数组数据结构。Vector这个老将获取集合的方式除了for循环,iterator以外,还有就是通过枚举。不过因为老迈(因为枚举的名称及方法的名称都过长,所以被迭代器取代了),渐渐退出了战争舞台。ArrayList底层是数组结构,所以方法大都是可以操作角标的,查询起来很快,但是增删操作略慢。而LinkedList底层是链表结构。特点是查询略慢,但是增删效率高。其特有方法如addFirst(),getFirst(),getLast(),removeFirst()等。 其中,ArrayList和LinkedList对元素的删除remove和判断contains依赖的都是元素对象的equals方法。 Set集合的左膀右臂分别是HashSet 和TreeSet。HashSet 的底层数据结构是哈希表。因为Set集合中元素是不重复的,那么HashSet 和TreeSet是如何保证元素的唯一性呢?hashSet保证元素唯一的依赖就是hashCode()和equals()。先判断两个元素的哈希值是否相同,若不同,则不是同一对象,若相同,再通过equals比较,为true,则为同一对象,否则反之。而TreeSet保证唯一的则是compareTo() 方法 return 0 则表示相同。因为TreeSet底层是二叉树数组,所以会对元素进行排序。排序方式有两种。 一、实现comparable接口,然后复写compareTo() 方法。返回比较结果。 二、创建一个比较器(类实现Comparator接口),复写compare() 方法,然后将这个比较器的对象作为参数传递给集合的构造方法。
还有一个集合就是Map,它是键值映射关系的集合。就是说里面的元素都是成对出现的。每一个元素都有唯一的键。它下面有三个实现类,分别是HashTable,HashMap,TreeMap,其中,HashTable底层是哈希表数据结构,不可以存入null 键和null值。线程是同步的,效率较低,所以失宠了。。。。所以后期用到的主要是hashMap,TreeMap。看到这两个名字,我一楞,这不是和Set集合里的HashSet 和TreeSet 很像么,怎么没有ArrayMap和LinkedMap呢?再一看Set集合和Map集合的特点,我隐约有点明白了。。。Set集合中元素是不重复的,而Map集合中key是唯一的,也就是说元素也是唯一性的。那么hashMap和HashSet ,TreeSet和TreeMap有什么相同点呢? HashMap和HashSet都是哈希表数据结构,那么,HashMap保证元素唯一的依赖自然也是hashCode和equals了,而TreeSet 和TreeMap都是二叉树结果,那么,二都都可以通过实现Comparable接口和创建比较器来对集合中的元素进行排序了。
另外有一点,Map集合中没有iterator迭代器,如果要取出集合中的元素,需要将Map集合转换成Set 集合,然后再通过Iterator来获取元素列表。而将Map集合转换成Set集合也有两种方式:keySet  和 entrySet keySet 方式是将Map集合中的键存入Set集合中,再通过迭代器,在迭代过程中,通过Map集合的get方法获取与键对应的Value值。 entrySet方式是将Map集合中的键值映射关系存入到Set集合中,而这种映射关系的类型是Map.Entry<K,V>,然后再通过迭代器,在迭代过程中,使用Map集合中的方法getKey()和getValue()分别获取每一个键值对的键和值。
好了,上面是回忆了上一章的大概内容,这一次要说的是集合框架中的工具类Collections和Arrays了。

Collections
Collections  专门用于对集合进行操作的工具类
常用方法: 1、 sort()  排序  对集合中的元素进行排序 max()  获取元素中的最大值(默认按自然顺序中的最大值) 根据元素的自然顺序,返回给定collection的最大元素。collection中的所有元素都必须实现Comparable接口。
并且collection中的所有元素都必须是可相互比较的
import java.util.*;
class CollectionsDemo
{
public static void main(String[] args)
{
sortDemo();
}
public static void sortDemo()
{
List<String> list=new ArrayList<String>();
list.add("kdl");
list.add("bcw");
list.add("adf");
list.add("qwdd");
list.add("ww");

//使用Collections类中的sort方法进行自然排序
Collections.sort(list);
sop(list);

//获取最大值
sop(Collections.max(list));
//使用比较器按字符串长度排序
Collections.sort(list,new StringLenComparator());
//打印集合
sop(list);
//按字符串长度排序后的最大值
sop(Collections.max(list,new StringLenComparator()));
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

//创建一个比较器,按字符串长度排序
class StringLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}

结果:黑马程序员--java基础复习集合框架工具类及其他对象



2、二分查找: binarySearch(List<? extends Comparable<? super T>> list, T key)
binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
使用比较器进行二分查找
使用二分搜索法搜索指定列表,以获得指定对象。
import java.util.*;
class CollectionsTest
{
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("kdl");
list.add("bcw");
list.add("adf");
list.add("qwdd");
list.add("ww");

Collections.sort(list);
sop(list);
//二分查找(折半查找)
int index=Collections.binarySearch(list,"ww");
sop(index);
}

//折半查找原理
public static int halfSearch(List<String> list,String key)
{
int max,min,mid;
min=0;max=list.size()-1;
while(min<=max)
{
mid=(min+max)/2;
String str=list.get(mid);
int num=str.compartTo(key);
if(num>0)
{
max=min-1;
}
else if(num<0)
min=min+1;
else return mid;
}
return -1;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}


3、fillfill(List<? super T> list,T obj) :使用指定元素替换指定列表中的所有元素

public static void fillDemo()
{
List<String> list=new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");

Collections.fill(list,"qq");

Iterator<String> it=list.iterator();
while(it.hasNext())
{
String str=it.next();
//打印元素
sop(str);
}
}


4、replaceAll
replaceAll:使用另一个值替换列表中出现的所有某一指定值 reverse:反转指定列表中元素的顺序
如下代码:
public static void replaceAllDemo()
{
List<String> list=new ArrayList<String>();
list.add("abc");
list.add("bdfs");
list.add("sab");
list.add("cdf");
//替换
Collections.replaceAll(list,"sab","w");
sop(list);
Collections.reverse(list);
sop(list);
}

结果:黑马程序员--java基础复习集合框架工具类及其他对象  从结果里可以看出,replaceAll() 方法将集合中的"sab"替换成了"w",而reverse将替换后的集合按原顺序反转了。


5、reverseOrder()
reverseOrder()返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。
reverseOrder(Comparator<T> cmp)    返回一个比较器,它强行逆转指定比较器的顺序。

如下例:
import java.util.*;
class CollectionsDemo2
{
public static void main(String[] args)
{
reverseOrderDemo();
}

public static void reverseOrderDemo()
{
//在当集合的构造函数中传递Collections.reverseOrder()后,排序顺序就之前的排序的倒序
//返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。
//TreeSet<String> ts=new TreeSet<String>(Collections.reverseOrder());

//当有比较器时,则将比较器强行逆转
TreeSet<String> ts=new TreeSet<String>(Collections.reverseOrder(new StringLenComparator()));

ts.add("adsf");
ts.add("bc");
ts.add("asdfklasdf");
ts.add("ddf");
ts.add("qq");

Iterator<String> it=ts.iterator();
while(it.hasNext())
{
String str=it.next();
sop(str);
}
}

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

//根据字符串长度排序的比较器
class StringLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
int num=(new Integer(s1.length())).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}

结果:黑马程序员--java基础复习集合框架工具类及其他对象


6、swap,shuffle
swap(List<?> list, int i, int j)  :     在指定列表的指定位置处交换元素。
shuffle(List<?> list)       使用默认随机源对指定列表进行置换。
shuffle() 置换后每次的结果都不一样
看代码演示:
import java.util.*;
class CollectionsSwap
{
public static void main(String[] args)
{
List<String> list =new ArrayList<String>();
list.add("abc01");
list.add("abc02");
list.add("abc03");
list.add("abc04");
list.add("abc05");
sop(list);
//对指定位置的两个元素进行互换
Collections.swap(list,1,3);
sop(list);
//对指定列表进行元素随机置换
Collections.shuffle(list);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

输出:黑马程序员--java基础复习集合框架工具类及其他对象



集合框架中的另一个工具类:Arrays
Arrays :用于操作数组的工具类(里面都是静态方法。)
常见方法: asList:将数组变成List集合

把数组变成List集合有什么好处?
可以使用集合的思想和方法来操作数组中的元素。
注意:将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定的
contains,get,indexOf,subList均可用,但是如果用了增删,会发生UnsupportedOperationException

如下:
import java.util.*;
class ArraysDemo
{
public static void main(String[] args)
{
asListDemo();
}
public static void asListDemo()
{
String[] arr={"dd","abc","df","www","er"};

List<String> list=Arrays.asList(arr);
//判断数组中是否包含某元素(需要通过循环来判断)
boolean arrcontains=myContains(arr,"www");
sop(arrcontains);
//判断集合中是否包含某元素(直接通过contains判断)
boolean listcontains=list.contains("www");
sop(listcontains);
sop(list);

/*****************************/
//将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定的
//contains,get,indexOf,subList均可用,但是如果用了增删,会发生UnsupportedOperationExce
//list.add("ads");

/********特殊之处(打印结果不一样)*******/
int[] nums={2,4,5,6};
List li=Arrays.asList(nums);

//将数组变成List集合
List<int[]> lii=Arrays.asList(nums);
sop(li);
sop(lii);

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

//判断数组中是否包含某元素
public static boolean myContains(String[] arr,String key)
{
for(int i=0;i<arr.length;i++)
{
if(arr[i].equals(key))
return true;
}
return false;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

集合变数组
Collection接口中的toArray() 1、指定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的Size,那么该方法内部会创建一个新的数组,长度为集合的size
当指定类型的数组长度大于了集合的size,就不会创建新的数组,而是使用传递进来的数组。
所以创建一个刚刚好的数组最优
2、为什么要将集合变数组?
是为了限定对元素的操作。

看使用示例:
import java.util.*;
class CollectionToArrayDemo
{
public static void main(String[] args)
{
CollectionToArray();
}

public static void CollectionToArray()
{
ArrayList<String> al=new ArrayList<String>();
al.add("askl");
al.add("aww");
al.add("adf");
al.add("asdf");


String[] arr=al.toArray(new String[0]); //打印出的数组长度为3
String[] arr1=al.toArray(new String[10]); //打印出的数组长度为10
//正确方法
String[] arr2=al.toArray(new String[al.size()]);

System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
}
}

输出:黑马程序员--java基础复习集合框架工具类及其他对象





高级for循环


格式:
for(数据类型 变量名:被遍历的集合(Collection)或者数组)
{

}
对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。

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


传统for和高级for有什么区别?
高级for有一个局限性,必须有被遍历的目标。
建议在遍历数组的时候,还是希望使用传统for。因为传统for可以定义角标。



看高级for在实际中的应用例子:
import java.util.*;
class ForEachDemo
{
public static void main(String[] args)
{
ForEach();
}

public static void ForEach()
{
HashMap<Integer,String> hm=new HashMap<Integer,String>();
hm.put(1,"a");
hm.put(2,"b");
hm.put(3,"c");
hm.put(4,"d");

/*************keySet***************/
Set<Integer> keyset=hm.keySet();
//高级for循环
for(Integer i:keyset)
{
System.out.println(i+"::"+hm.get(i));
}

sop("********************************");
/*************entrySet*******************/
Set<Map.Entry<Integer,String>> entryset=hm.entrySet();
//高级for循环
for(Map.Entry<Integer,String> me:entryset)
{
Integer key=me.getKey();
String value=me.getValue();
System.out.println(key+"::"+value);
}
}

public static void ForEach0()
{
ArrayList<String> al=new ArrayList<String>();
al.add("askl");
al.add("aww");
al.add("adf");
al.add("asdf");

//使用迭代器
Iterator<String> it=al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}

//使用for增强
for(String s:al)
{
System.out.println(s);
}

}
}




可变参数和静态导入

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

使用注意事项:可变参数一定要放在参数列表的最后面

二、静态导入
当类名重名时,需要指定具体的包名。
当方法重名时,指定具体所属的对象或类


如下例:
import java.util.*;
import static java.util.Arrays.*;
import static java.lang.System.*;//导入了System类中所有静态成员
class ParamMethodDemo
{
public static void main(String[] args)
{
method("asdf",3,4,5,6);
method_StaticImport();
}

public static void method_StaticImport()
{
int[] arr={3,2,8};
Arrays.sort(arr);
//int index=Arrays.binarySearch(arr,1);
int index=binarySearch(arr,1);

//下面这个Arrays为什么没有省去呢?因为Object类下也有toString()
System.out.println(Arrays.toString(arr));

out.println("Index="+index);
}

//可变参数
public static void method(String a,int... arr)
{
System.out.println(arr.length);
}
}


其他对象
一、System System:类中的方法和属性都是静态的。
out:标准输出,默认是控制台
in:标准输入,默认是键盘。

Properties:描述系统的一些信息。
Properties  getProperties()

因为Properties是Hashtable的子类,也就是MAP集合的一个子类对象。那么可以通过map的方法取出该集合中的元素
该集合中存储都是字符串,没有泛型定义。


看下例:
import java.util.*;
class SystemDemo
{
public static void main(String[] args)
{
Properties prop=System.getProperties();
//因为Properties是Hashtable的子类,也就是MAP集合的一个子类对象。
//那么可以通过map的方法取出该集合中的元素
//该集合中存储都是字符串,没有泛型定义。

for(Object obj :prop.keySet())
{
String s=(String)obj;
String value=(String)prop.get(s);
sop(s+":"+value);
}

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

}

结果:黑马程序员--java基础复习集合框架工具类及其他对象


自定义系统属性:
//如何在系统中自定义一些特有信息呢?
System.setProperty("meng","hanshi");

//获取指定属性信息
String value=System.getProperty("meng");
sop(value);

结果如图:黑马程序员--java基础复习集合框架工具类及其他对象

或者如下方式:
//能否在JVM启动时,动态加载一些属性信息?
String v=System.getProperty("haha");
sop(v);//结果为null,因为系统属性中没有haha这个属性
//在控制台上执行:java
//然后再执行:java -Dhaha=qqqqq SystemDemo
//可得到结果

如下:黑马程序员--java基础复习集合框架工具类及其他对象


黑马程序员--java基础复习集合框架工具类及其他对象黑马程序员--java基础复习集合框架工具类及其他对象






二、Runtime Runtime 对象
该类并没有提供构造函数,说明不可以new对象。那么会直接想到该类中的方法都是静态的。
发现该类中还有有非静态函数。说明该类中肯定提供了方法获取本类对象。
而且该方法是静态的,并且返回值类型是本类类型。由这个特点可以看出该类使用了单例设计模式


常用方法:
Process exec(String command)   在单独的进程中执行指定的字符串命令  destroy()    杀掉子进程。是抽象类Process中的方法

看使用方式:
class RuntimeDemo
{
public static void main(String[] args) throws Exception
{
Runtime rt=Runtime.getRuntime();
Process p=rt.exec("winmine.exe");//单独的进程中执行指定的字符串命令
Process p1=rt.exec("notepad SystemDemo.java");

Thread.sleep(4000);
p.destroy();//杀死子进程
}
}

注意:exec() 执行的命令中常带有路径,当这个路径不存在的时候,会报IoException异常
三、Date  Date 类表示特定的瞬间,精确到毫秒。
日期和时间模式: 字母  日期或时间元素  表示  示例  
G  Era 标志符  Text  AD  
y  年  Year  1996; 96  
M  年中的月份  Month  July; Jul; 07  
w  年中的周数  Number  27  
W  月份中的周数  Number  2  
D  年中的天数  Number  189  
d  月份中的天数  Number  10  
F  月份中的星期  Number  2  
E  星期中的天数  Text  Tuesday; Tue  
a  Am/pm 标记  Text  PM  
H  一天中的小时数(0-23)  Number  0  
k  一天中的小时数(1-24)  Number  24  
K  am/pm 中的小时数(0-11)  Number  0  
h  am/pm 中的小时数(1-12)  Number  12  
m  小时中的分钟数  Number  30  
s  分钟中的秒数  Number  55  
S  毫秒数  Number  978  
z  时区  General time zone  Pacific Standard Time; PST; GMT-08:00  
Z  时区  RFC 822 time zone  -0800  
直接看使用方式:
import java.util.*;
import java.text.*;
class DateDemo
{
public static void main(String[] args)
{
Date d=new Date();
sop(d); //打印的时间格式不符合人们的习惯

//将模式封装到SimpleDateformat对象中。
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 E hh:mm:ss");

//调用format方法让模式格式化指定对象
String time=sdf.format(d);

sop(time);
}


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

输出:黑马程序员--java基础复习集合框架工具类及其他对象


四、Calendar   日历类 Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法

常用方法: add(int field, int amount)    根据日历的规则,为给定的日历字段添加或减去指定的时间量

get(int field)  返回给定日历字段的值

set(int year, int month, int date)     设置日历字段 YEAR、MONTH 和 DAY_OF_MONTH 的值

如下:
import java.util.*;
import java.text.*;
class CalendarDemo
{
public static void main(String[] args)
{
Calendar c=Calendar.getInstance();
printDate(c);

sop("*************Set日历字段**************");
//设置日历字段
c.set(2025,5,15);
printDate(c);


/* //获取年(老方法)
Date date=new Date();

SimpleDateFormat sdf=new SimpleDateFormat("yyyy");
String s=sdf.format(date);
sop(s);
*/
}

public static void printDate(Calendar c)
{
//获取年份
int year=c.get(Calendar.YEAR);
sop(year);
/*查表法*/
String[] mons={"一月","二月","三月","四月",
"五月","六月","七月","八月",
"九月","十月","十一月","十二月",};
String[] weeks={"","星期日","星期一","星期二","星期三","星期四","星期五","星期六"};

//获取月份(从0开始,0表示一月,依次类推)
int month=c.get(Calendar.MONTH);
//通过查表法获取实际月份
sop(mons[month]);

//获取当天日期
int day=c.get(Calendar.DAY_OF_MONTH);
sop(day);

//通过查表法获取当天所属星期
int week=c.get(Calendar.DAY_OF_WEEK);
sop(weeks[week]);
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出:黑马程序员--java基础复习集合框架工具类及其他对象

看一个练习题:
/*
1、获取任意年的二月有多少天?
2、获取昨天的现在这个时刻
*/

import java.util.*;
import java.text.*;
class CalendarTest
{
public static void main(String[] args)
{
getDateNum(2013,2);
getYestodayNow();
}

//获取昨天的现在这个时刻
public static void getYestodayNow()
{
Calendar c=Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH,-1);
printDate(c);
}

//获取任意年的任意月有多少天
public static void getDateNum(int Year,int Month)
{
Calendar c=Calendar.getInstance();
c.set(Year,Month,1);
c.add(Calendar.DAY_OF_MONTH,-1);

sop(c.get(Calendar.DAY_OF_MONTH));

}

//打印日期
public static void printDate(Calendar c)
{
//获取年份
sop(c.get(Calendar.YEAR));
/*查表法*/
String[] mons={"一月","二月","三月","四月",
"五月","六月","七月","八月",
"九月","十月","十一月","十二月",};
String[] weeks={"","星期日","星期一","星期二","星期三","星期四","星期五","星期六"};

//获取月份
sop(mons[c.get(Calendar.MONTH)]);
//获取日期
sop(c.get(Calendar.DAY_OF_MONTH));
//获取星期
sop(weeks[c.get(Calendar.DAY_OF_WEEK)]);
}
public static void sop(Object obj)
{
System.out.println(obj);
}

}




Math类 Math 类包含用于执行基本数学运算的方法

常用方法 double ceil() 返回大于指定数据的最小整数
double floor() 返回小于指定数据的最大整数
double round()  四舍五入
double pow(double a, double b)   返回第一个参数的第二个参数次幂的值
random()    返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。

如下例:
public static void methods()
{
double d=Math.ceil(16.23); //ceil 返回大于指定数据的最小整数
sop(d);

double d1=Math.floor(12.45);// floor 返回小于指定数据的最大整数
sop(d1);

long l=Math.round(12.54);//四舍五入
sop(l);

double p=Math.pow(2,3);//2的3次方
sop(p);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
输出:黑马程序员--java基础复习集合框架工具类及其他对象

random()    返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。如下:

public static void method_Random()
{
/******使用Math.random*/
for(int i=0;i<10;i++)
{
int d=(int)(Math.random()*10+1);
sop(d);
}
sop("***********使用Random类*****************");
/**********使用Random类**********/
Random r=new Random();
for(int i=0;i<10;i++)
{
int d=r.nextInt(10)+1;
sop(d);
}
}
结果:黑马程序员--java基础复习集合框架工具类及其他对象