黑马程序员——Java基础_集合工具类Collections及常见API

时间:2022-01-21 12:20:54

 ----------------------Android培训Java培训、期待与您交流! ----------------------

1 集合框架的工具类Collections

          Collections:集合框架的工具类。里面定义的都是静态方法。

Collections和Collection有什么区别?

          Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有两个常用的子接口:

                    List:对元素都有定义索引。有序的。可以重复元素。

                    Set:不可以重复元素。无序。

          而Collections则是集合框架中的一个工具类。该类中的方法都是静态的。提供的方法中有可以对list集合进行排序,二分查找等方法。

          通常常用的集合都是线程不安全的。因为要提高效率。

          如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

import java.util.*;
class CollectionsDemo
{
public static void main(String[] args)
{
sortDemo();

}
public static void binarySearchDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list,new StrLenComparator());
sop(list);
//int index = Collections.binarySearch(list,"aaaa");
//int index = halfSearch(list,"cc");
int index = halfSearch2(list,"aaaa",new StrLenComparator());
sop("index="+index);
}

public static int halfSearch(List<String> list,String key)
{
int max,min,mid;
max = list.size()-1;
min = 0;
while(min<=max)
{
mid = (max+min)>>1;// /2;
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;
}

public static int halfSearch2(List<String> list,String key,Comparator<String> cmp)
{
int max,min,mid;
max = list.size()-1;
min = 0;
while(min<=max)
{
mid = (max+min)>>1;// /2;
String str = list.get(mid);
int num = cmp.compare(str,key);
if(num>0)
max = mid -1;
else if(num<0)
min = mid + 1;
else
return mid;
}
return -min-1;
}

public static void maxDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list);
sop(list);
String max = Collections.max(list/*,new StrLenComparator()*/);
sop("max="+max);
}

public static void sortDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
sop(list);
//Collections.sort(list);
Collections.sort(list,new StrLenComparator());
//Collections.swap(list,1,2);
sop(list);
}

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


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);
}
}

-----------------------------分割线-----------------------------

Arrays:

     用于操作数组的工具类,里面都是静态方法。

把数组变成list集合有什么好处?
     可以使用集合的思想和方法来操作数组中的元素。
注意:将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定。(可以remove)

原理:Arrays.asList()会返回一个ArrayList对象,该ArrayList类是Arrays的一个私有静态类,而不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、get()、contains()方法,但是没有增加元素的方法,所以它的大小是固定的。为了能够增删,可以将其装到一个ArrayList中去

public static void main(String[] args) {
String[] arr = {"a","b","c","d"};
List<String> list = new ArrayList<String>(Arrays.asList(arr));
list.add("e");
System.out.println(list);
}

contains()、get()
indexOf()、subList();
如果进行增删,那么会发生UnsupportedOperationException异常。

PS:

     如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
     如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

数组变集合代码示例:

import java.util.*;
class ArraysDemo
{
public static void main(String[] args)
{
int[] arr = {2,4,5};
System.out.println(Arrays.toString(arr));
String[] arr = {"abc","cc","kkkk"};
sop(li);
}
public static boolean myContains(String[] arr,String key)
{
for(int x=0;x<arr.length; x++)
{
if(arr[x].equals(key))
return true;
}
return false;
}

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

}

-----------------------------分割线-----------------------------

3 集合变数组

这里用到了Collection接口中的toArray方法。

指定类型的数组到底要定义多长呢?

          当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size

          当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。

          所以创建一个刚刚好的数组最优,使用size()

为什么要将集合变数组?

          为了限定对元素的操作。不需要进行增删了。

import java.util.*;
class CollectionToArray
{
public static void main(String[] args)
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
String[] arr = al.toArray(new String[al.size()]);
System.out.println(Arrays.toString(arr));
}
}

-----------------------------分割线-----------------------------

4 Runtime对象

每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过getRuntime方法获取当前运行时。应用程序不能创建自己的Runtime类实例。该方式即:static Runtime getRuntime();

该类并没有提供构造函数。

说明不可以new对象。那么会直接想到该类中的方法都是静态的。

发现该类中还有非静态方法。

说明该类肯定会提供了方法获取本类对象。而且该方法是静态的,并返回值类型是本类类型。

由这个特点可以看出该类使用了单例设计模式完成。

class  RuntimeDemo
{
public static void main(String[] args) throws Exception
{
Runtime r = Runtime.getRuntime();
Process p = r.exec("notepad.exe SystemDemo.java");
//Thread.sleep(4000);
//p.destroy();
}
}

-----------------------------分割线-----------------------------

5 System对象

System:类中的方法和属性都是静态的。

out:标准输出,默认是控制台。

in:标准输入,默认是键盘。

它描述了系统一些信息,获取系统属性信息:Properties getProperties();

代码示例:

import java.util.*;
class SystemDemo
{
public static void main(String[] args)
{
Properties prop = System.getProperties();
//因为Properties是Hashtable的子类,也就是Map集合的一个子类对象。
//那么可以通过map的方法取出该集合中的元素。
//该集合中存储都是字符串。没有泛型定义。
//如何在系统中自定义一些特有信息呢?
System.setProperty("mykey","myvalue");
//获取指定属性信息。
String value = System.getProperty("os.name");
System.out.println("value="+value);
//可不可以在jvm启动时,动态加载一些属性信息呢?
String v = System.getProperty("haha");
System.out.println("v="+v);
/*//获取所有属性信息。
for(Object obj : prop.keySet())
{
String value = (String)prop.get(obj);
System.out.println(obj+"::"+value);
}*/
}
}

-----------------------------分割线-----------------------------

6 Math对象

ceil()方法

返回最接近指定

double d=Math.ceil(16.34); //返回大于指定数据的最小整数

double d2=Math.floor(16.34) //返回小于指定数据的最大整数

long l=Math.round(16.34) //四舍五入

int i=Math.pow(3,3) //33次方

-----------------------------分割线-----------------------------

7 Date对象与Calendar对象

Date:在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理。

① 使用Date类代表当前系统时间,如:

          Date d = new Date();

          System.out.println(d);

使用Date类的默认构造方法创建出的对象就代表当前时间,由于Date类覆盖了toString方法,所以可以直接输出Date类型的对象,显示的结果如下:

          Sun Mar 08 16:35:58 CST 2009

在该格式中,Sun代表Sunday(周日)Mar代表March(三月)08代表8号,CST代表China Standard Time(中国标准时间,也就是北京时间(东八区))

② 使用Date类代表指定的时间,如:

          Date d1 = new Date(2009-1900,3-1,9);

          System.out.println(d1);

使用带参数的构造方法,可以构造指定日期的Date类对象,Date类中年份的参数应该是实际需要代表的年份减去1900,实际需要代表的月份减去1以后的值。

例如上面的示例代码代表就是200939号。实际代表具体的年月日时分秒的日期对象,和这个类似。

③ 获得Date对象中的信息

          使用Date类中对应的get方法,可以获得Date类对象中相关的信息,需要注意的是使用getYear获得是Date对象中年份减去1900以后的值,所以需要显示对应的年份则需要在返回值的基础上加上1900,月份类似。在Date类中还提供了getDay方法,用于获得Date对象代表的时间是星期几,Date类规定周日是0,周一是1,周二是2,后续的依次类推。

(贴代码)

④ Date对象和相对时间之间的互转

          使用Date对象中的getTime方法,可以将Date类的对象转换为相对时间,使用Date类的构造方法,可以将相对时间转换为Date类的对象。经过转换以后,既方便了时间的计算,也使时间显示比较直观了。

 Date d3 = new Date(2014-1900,8-1,10);
long time = 1290876532190L;
//将Date类的对象转换为相对时间
long t = d3.getTime();
System.out.println(t);
//将相对时间转换为Date类的对象
Date d4 = new Date(time);
System.out.println(d4);

Calendar

          从JDK1.1版本开始,在处理日期和时间时,系统推荐使用Calendar类进行实现。在设计上,Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些,下面就介绍一下Calendar类的使用。

          Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可(单例模式)。

① 使用Calendar类代表当前时间

          Calendar c = Calendar.getInstance();

          由于Calendar类是抽象类,且Calendar类的构造方法是protected的,所以无法使用Calendar类的构造方法来创建对象,API中提供了getInstance方法用来创建对象。

使用该方法获得的Calendar对象就代表当前的系统时间,由于CalendartoString实现的没有Date类那么直观,所以直接输出Calendar类的对象意义不大。

② 使用Calendar类代表指定的时间

          Calendar c1 = Calendar.getInstance();

          c1.set(2009, 3 - 1, 9);

          使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。

          set方法的声明为:public final void set(int year,int month,int date)

          以上示例代码设置的时间为200939日,其参数的结构和Date类不一样。Calendar类中年份的数值直接书写,月份的值为实际的月份值减1,日期的值就是实际的日期值。

          如果只设定某个字段,例如日期的值,则可以使用如下set方法:public void set(int field,int value)

          在该方法中,参数field代表要设置的字段的类型,常见类型如下:

         Calendar.YEAR——年份

         Calendar.MONTH——月份

         Calendar.DATE——日期

         Calendar.DAY_OF_MONTH——日期,和上面的字段完全相同

         Calendar.HOUR——12小时制的小时数

         Calendar.HOUR_OF_DAY——24小时制的小时数

         Calendar.MINUTE——分钟

         Calendar.SECOND——秒

         Calendar.DAY_OF_WEEK——星期几

后续的参数value代表,设置成的值。例如:

         c1.set(Calendar.DATE,10);

该代码的作用是将c1对象代表的时间中日期设置为10号,其它所有的数值会被重新计算,例如星期几以及对应的相对时间数值等。

③ 获得Calendar类中的信息

          使用Calendar类中的get方法可以获得Calendar对象中对应的信息,get方法的声明如下:public int get(int field)

          其中参数field代表需要获得的字段的值,字段说明和上面的set方法保持一致。需要说明的是,获得的月份为实际的月份值减1,获得的星期的值和Date类不一样。在Calendar类中,周日是1,周一是2,周二是3,依次类推。

public static void main(String[] args) {
// TODO Auto-generated method stub
Calendar c2 = Calendar.getInstance();
int year = c2.get(Calendar.YEAR);
int month = c2.get(Calendar.MONTH) + 1;
int date = c2.get(Calendar.DATE);
int hour = c2.get(Calendar.HOUR_OF_DAY);
int minute = c2.get(Calendar.MINUTE);
int second = c2.get(Calendar.SECOND);
int day = c2.get(Calendar.DAY_OF_WEEK);
System.out.println("年份:" + year);
System.out.println("月份:" + month);
System.out.println("日期:" + date);
System.out.println("小时:" + hour);
System.out.println("分钟:" + minute);
System.out.println("秒:" + second);
System.out.println("星期:" + day);
}

④ 其它方法说明

其实Calendar类中还提供了很多其它有用的方法,下面简单的介绍几个常见方法的使用。

          add方法

          如:public abstract void add(int field,int amount)

该方法的作用是在Calendar对象中的某个字段上增加或减少一定的数值,增加是amount的值为正,减少时amount的值为负。

例如在计算一下当前时间100天以后的日期,代码如下:          

 Calendar c3 = Calendar.getInstance();
c3.add(Calendar.DATE, 100);
int year1 = c3.get(Calendar.YEAR);
//月份
int month1 = c3.get(Calendar.MONTH) + 1;
//日期
int date1 = c3.get(Calendar.DATE);
System.out.println(year1 + "年" + month1 + "月" + date1 + "日");

这里add方法是指在c3对象的Calendar.DATE,也就是日期字段上增加100,类内部会重新计算该日期对象中其它各字段的值,从而获得100天以后的日期。

          after方法

          如:public boolean after(Object when)

该方法的作用是判断当前日期对象是否在when对象的后面,如果在when对象的后面则返回true,否则返回false。例如:

                   Calendar c4 = Calendar.getInstance();

                   c4.set(2009, 10 - 1, 10);

                   Calendar c5 = Calendar.getInstance();

                   c5.set(2010, 10 - 1, 10);

                   boolean b = c5.after(c4);

                   System.out.println(b);

          在该示例代码中对象c4代表的时间是20091010号,对象c5代表的时间是20101010号,则对象c5代表的日期在c4代表的日期之后,所以after方法的返回值是true

          另外一个类似的方法是before,该方法是判断当前日期对象是否位于另外一个日期对象之前。

          getTime方法

          如:public final Date getTime()

          该方法的作用是将Calendar类型的对象转换为对应的Date类对象,两者代表相同的时间点。

          类似的方法是setTime,该方法的作用是将Date对象转换为对应的Calendar对象,该方法的声明如下: public final void setTime(Date date)

转换的示例代码如下:

                  Date d = new Date();

                   Calendar c6 = Calendar.getInstance();

                   //Calendar类型的对象转换为Date对象

                   Date d1 = c6.getTime();

                   //Date类型的对象转换为Calendar对象

                   Calendar c7 = Calendar.getInstance();

                   c7.setTime(d);

应用示例

下面以两个简单的示例介绍时间和日期处理的基本使用。

① 计算两个日期之间相差的天数

例如:计算2014614号和2010914号之间相差的天数,则可以使用时间和日期处理进行计算。

          该程序实现的原理为:首先代表两个特定的时间点,这里使用Calendar的对象进行代表,然后将两个时间点转换为对应的相对时间,求两个时间点相对时间的差值,然后除以1天的毫秒数(24小时X60分钟X60X1000毫秒)即可获得对应的天数。实现该示例的完整代码如下:

public static void main(String[] args) {
//设置两个日期
Calendar c1 = Calendar.getInstance();
c1.set(2014, 6 - 1, 14);
Calendar c2 = Calendar.getInstance();
c2.set(2010, 9 - 1, 14);
//转换为相对时间
long t1 = c1.getTimeInMillis();
long t2 = c2.getTimeInMillis();
//计算天数
long days = (t1 - t2) / (24 * 60 * 60 * 1000);
System.out.println(days);
}

② 输出当前月的月历

          该示例的功能是输出当前系统时间所在月的日历,例如当前系统时间是2014810日,则输出20143月的日历。

          该程序实现的原理为:首先获得该月1号是星期几,然后获得该月的天数,最后使用流程控制实现按照日历的格式进行输出即可。即如果1号是星期一,则打印一个单位的空格,如果1号是星期二,则打印两个单位的空格,依次类推。打印完星期六的日期以后,进行换行。实现该示例的完整代码如下:

public static void main(String[] args) {
//获得当前时间
Calendar c = Calendar.getInstance();
//设置代表的日期为1号
c.set(Calendar.DATE, 1);
//获得1号是星期几
int start = c.get(Calendar.DAY_OF_WEEK);
//获得当前月的最大日期数
int maxDay = c.getActualMaximum(Calendar.DATE);
//输出标题
System.out.println("星期日 星期一 星期二 星期三 星期四 星期五 星期六");
//输出开始的空格
for (int i = 1; i < start; i++) {
System.out.print(" ");
}
//输出该月中的所有日期
for (int i = 1; i <= maxDay; i++) {
//输出日期数字
System.out.print(" " + i);
//输出分隔空格
System.out.print(" ");
if (i < 10) {
System.out.print(' ');
}
//判断是否换行
if ((start + i - 1) % 7 == 0) {
System.out.println();
}
}
//换行
System.out.println();
}

 

----------------------Android培训Java培训、期待与您交流! ----------------------