Java学习——Java常用常见工具类API

一. Java API

        Java API(Java Application Programming Interface)是Java应用程序编程接口的缩写,Java中的API,就是JDK提供的具有各种功能的Java类,由于Java类库非常庞大,而且在不断壮大,本文不可能一一介绍所有类的使用方法,读者应该养成查阅Java API文档的习惯,就像查询字典一样,在需要用到某个类的时候,可以从Java API文档中获得这个类的详细信息。

        Java API的帮助文档可到 http://docs.oracle.com/javase/8/docs/api/ 下载,灵活使用Java API能够提高使用Java语言编写程序的效率,下面对Java中提供的最常用的包进行介绍。

  • java.lang:Java语言包, 该包中提供了利用Java语言进行程序设计的基础类,比如String、Math、System类,在任何类中,该包中的类不需要使用import语句进行导入,都会被自动导入。
  • java.util:该包中主要包含一些实用的工具类,比如集合框架类、日期处理类、字符串解析类、随机数生成类等。
  • java.awt:该包中主要包含处理用户界面和绘制图形图像的各种类。
  • java.io:该包中主要包含处理输入、输出编程的各种类。
  • java.net:该包中主要包含处理网络编程的各种类。
  • java.sql:该包中主要包含处理数据库编程的各种类。
  • java.lang包中常用的类如下所示。

Boolean

Object

Error

Byte

String

Throwable

Character

StringBuffer

Exception

Double

StringBuilder

ClassNotFoundException

Float

System

NullPointerException

Integer

Math

NumberFormatException

Long

Runnable(接口)

RuntimeException

Short

Thread

ArithmeticException

java.util包中常用的类如下所示。

Collection(接口)

Arrays

Calendar

Iterator(接口)

Set(接口)

Date

ListIterator(接口)

HashSet

Random

List(接口)

TreeSet

Scanner

ArrayList

Map(接口)

Collections

LinkedList

HashMap

Vector

Hashtable

Stack

TreeMap

java.io包中的常用类:

BufferedInputStream

FileReader

PrintWriter

BufferedOutputStream

FileWriter

Reader

BufferedReader

InputStream

Writer

BufferedWriter

InputStreamReader

Serializable(接口)

DataInputStream

OutputStream

Externalizable接口)

DataOutputStream

OutputStreamWriter

IOException

File

ObjectInputStream

FileNotFoundException

FileInputStream

ObjectOutputStream

InvalidClassException

FileOutputStream

PrintStream

java.net包中的常用类:

ServerSocket

Socket

UnknownHostException


二. Object类

        在Java中,有这样一个类,它是所有类的祖先类,也就是说,任何类都是其子孙类,它就是java.lang.Object。如果一个类没有显式地指明其父类,那么它的父类就是Object,也就是说,下面两条语句的作用是一样的:

public class ClassName{…} 等价于 public class ClassName extends Object{…}

        如同我们称自己为炎黄子孙一样,所有的类都可以称为Object子孙类,所以,在Object类中定义的方法,在所有类中都可以使用。同时,Object类也是Java语言中唯一一个没有父类的类。

        做为一个超级祖先类,Object类为子类提供了一些public修饰的方法,便于子类覆盖来实现子类自己特定的功能,下面我们要详细介绍其中的equals()方法、hashCode()方法和toString()方法。

2.1 public boolean equals(Object obj)

        该方法在Object类中的作用是:比较两个引用所指向的对象是否是同一个对象,即两个引用所指向对象的地址是否相等。

        注意,通常情况下,Object的任何子类均可以按照自己的需要对equals()方法进行覆盖,以改变此方法的含义,所以有的类中equals()方法是比较地址,有的类中该方法不是比较地址,具体的,就看子类中该方法是如何实现的。

【例】 定义公民类Citizen,覆盖该类的equals()方法,该方法的定义为:如果两个公民的身份id相同,则为同一个公民。

public class Citizen{
    private int id;
    private String name;
    public Citizen(int id, String name) {
        this.id = id;
        this.name = name;
    }
    //覆盖父类的equals()方法
    public boolean equals(Object o) {
        Citizen c = (Citizen) o;
        if (c.id == this.id) {
            return true;
        } else {
            return false;
        }
    }
	//主方法,测试equals()方法
    public static void main(String args[]) {
        Citizen xiaoming = new Citizen(21000, "xiaoming");
        Citizen mingming = new Citizen(21000, "mingming");
        System.out.println(xiaoming.equals(mingming));
    }
}
//程序运行结果:true

程序分析:上例定义了一个Citizen类,此类包含了公民的两个属性id和name,同时覆盖了equals()方法,该方法实现为:当传入对象的id和当前对象的id相等时,返回true,否则返回false。所以在main()方法最后一行调用equals()方法时,调用的实际上是Citizen类的equals()方法,xiaoming和mingming对象的id都为21000,所以程序运行结果为true。而假设如果Citizen类没有覆盖equals()方法,则在最后一行调用equals()方法时,实际调用的Object类的equals()方法,该方法比较两个对象是否指向同一块地址,所以肯定返回false,读者可自行验证。

        接下来说一下"=="运算符和equals()方法的区别。"=="是比较运算符,既能用于比较两个基本数据类型,也能用于比较两个引用数据类型,当比较基本数据类型时,判断两个基本数据类型的字面量是否相等,当比较两个引用数据类型时,判断两个"引用"的值是否相等,也就是两个"引用"是否指向同一个对象。而equals()方法只能用于比较引用数据类型,Object类的equals()方法比较两个对象引用的值是否相等,但equals()方法通常都会被子类覆盖,所以子类中equals()方法的含义,就要看子类中的具体实现了。

【例】 == 和 equals()方法在String类中的区别

String str1 = "hello"; 
String str2 = new String("hello"); 
System.out.println(str1==str2); 
System.out.println(str1.equals(str2));

程序运行结果:
false
true

程序分析:因为String是引用数据类型,使用"=="运算符比较两个引用地址是否相同,第二行使用关键字new重新生成了一个String对象,所以第三行输出为false。在String类中,覆盖了Object的equals()方法,该方法判断两个String对象的内容是否相等,所以第4行输出为true。

2.2 public int hashCode()

        该方法返回对象的哈希码,哈希码是一个代表对象的十六进制整数,好比对象的身份证号。在程序运行期间,每次调用同一个对象的hashCode()方法,返回的哈希码必定相同,但是多次执行同一个程序,程序的一次执行和下一次执行期间,同一个对象的哈希码不一定相同。实际上默认的哈希码是将对象的内存地址通过某种转换得到的,所以不同对象会有不同的哈希码。

        在Java中有个规定:如果equals()方法返回两个对象是相等的,那这两个对象上调用hashCode()返回的整数必须相等,否则在使用Hash类型集合时就会产生错误,所以在我们覆盖equals()方法同时,还要记得覆盖hashCode()方法。需要说明,如果equals()返回两个对象不等,它们的hashCode()也可以返回相同的整数,但是最好让它们的hashCode()返回不同的整数,这有利于提高Hash类型集合的性能。

        那么重写equals()方法时,一定要重写hashcode()方法吗?

        先说说hashcode()方法调用的条件,如果你想往map里面放一个类作为map的键值,这个类又是你自己设计的,或者这个类不是你写的但是你修改了这个类的equals()方法,这个时候,你就要重写hashcode()方法,这样当你往map里放值的时候,系统会调用这个对象的hashcode()方法来生成相应的hash值,来映射相应的对象。

        如果同一个类的两个对象的属性值相等,那么他们的hashcode()一定相等吗?这个要看你具体如何实现你的hashcode()方法,如果你希望他们的值一样hashcode()也一样,你就可以这样实现。但是hashcode的实现,一般要满足几个特征,比如自反性,传递性什么的。自反性,即对任意一个非空的指引值x,x.equals(x)永远返回true,传递性,当x.equals(y)返回true并且y.equals(z)返回true时,x.equals(z)也返回true。

3)public String toString()

        该方法返回对象的字符串表示,形如:类名@hashcode,toString()方法是一个从字面上就容易理解的方法,它的功能是得到一个能够代表该对象的一个字符串:类名+"@"+代表该对象的一个唯一的16进制数,例如下面这个例子:

【例1-3】 查看Object类和String类的toString()方法返回值。

public class ObjectSample {
            public static void main(String args[]){
                Object o = new Object();
                System.out.println(o);
                System.out.println(o.toString());
                String s = new String("hello");
                System.out.println(s);        
            }    
}

程序运行结果:
java.lang.Object@1db9742
java.lang.Object@1db9742
hello

程序分析:前两个输出结果表示对象o在内存中的地址,事实上返回这样的字符串没有什么实际的意义。一般子类都会覆盖该方法,让它返回有意义的文本。例如上例中的对象s的输出为"hello",这是因为字符串String类对toString()进行了覆盖,让它返回此String的本身内容。

下面通过实例来看一下如何在自己编写的类中覆盖equals()方法和toString()方法。

【例】 equals()方法和toString()的覆盖

//圆类
public class MyCircle {
    private int radius;//半径
    public MyCircle(int r) {
        radius = r;
    }
    public int getRadius() {
        return radius;
    }
    public void setRadius(int r) {
        radius = r;
    }
    //覆盖Object中的equals()方法
    public boolean equals(Object obj) {
        MyCircle o = (MyCircle) obj;
        if (o.getRadius() == this.radius)
            return true;
        else
            return false;
    }
    //覆盖Object中toString方法
    public String toString() {
        return "radius = " + radius;
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        MyCircle obj1 = new MyCircle(3);
        System.out.println("obj1:" + obj1.toString());
        MyCircle obj2 = new MyCircle(3);
        System.out.println("obj2:" + obj2.toString());
        if (obj1.equals(obj2))
            System.out.println("the two objects are equal");
        else
            System.out.println("the two objects are not equal");
    }
}

程序运行结果:
obj1:radius = 3
obj2:radius = 3
the two objects are equal

程序分析:从程序的运行结果来看,我们创建的两个MyCircle对象是相等的,因为MyCircle类中覆盖的equals()方法规定,当两个MyCircle对象的半径相等时,认为这两个对象相等。而我们在调用MyCircle类的构造方法创建对象时设定这两个MyCircle对象的半径均为3,所以obj1.equals(obj2)返回true。


三. 包装类

        出于对性能的考虑,Java编程语言不把基本数据类型看作对象。因为处理对象需要额外的系统开销,所以,如果将基本数据类型当作对象,就会给语言性能带来负面影响。然而,许多Java中的方法需要将对象作为参数,为了让基本数据类型的这些数据也具有面向对象的特性,Java 编程语言提供了包装类来将基本数据类型看作对象,基本类型和包装类型之间能够互相转换。

3.1包装类简介

        包装类型和基本数据类型的名字基本相同,首字母变成了大写,但是int和char的包装类型为Integer和Character。基本数据类型不是对象层次结构的组成部分。有时需要像处理对象一样处理这些基本数据类型,可通过相应的“包装类”来将其“包装”。表1-5列出了基本数据类型及其包装类型。

基本数据类型及其包装类型:

基本类型

包装

boolean

Boolean

byte

Byte

char

Character

double

Double

float

Float

int

Integer

long

Long

short

Short

八种基本类型都有对应的包装类,图1-1是它们的继承层次结构。

        基本数据类型的变量没有默认值,而包装类型的变量默认值是null。在这八个包装类中,除了Integer和Character类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写即可。对于包装类说,这些类的用途主要包含两种:

  • 作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。
  • 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。

3.2 基本类型与包装类之间的转换

        包装类有什么作用呢?包装类能够完成数据类型之间(除boolean)的相互转换,尤其是基本数据类型和String类型的转换。包装类中包含了对应基本数据类型的值,封装了String和基本数据类型之间相互转换的方法,还有一些处理这些基本数据类型时非常有用的属性和方法。

由于八个包装类的使用比较类似,下面以最常用的Integer类为例子介绍包装类的实际使用。

1)实现int和Integer类之间的转换

        在实际转换时,使用Integer类的构造方法和Integer类内部的intValue()方法实现int和Interger类型之间的相互转换,实现的代码如下:

int n = 10;
//将int类型转换为Integer类型
Integer in = new Integer(n);
//将Integer类型的对象转换为int类型
int m = in.intValue();

2)Integer类内部的常用方法

在Integer类内部包含了一些和int操作有关的方法,下面介绍一些比较常用的方法:

a、parseInt方法

public static int parseInt(String s)

        该方法的作用是将数字字符串转换为int数值。在界面编程中,将字符串转换为对应的int数字是一种比较常见的操作。使用示例如下:

String s = "123";
int n = Integer.parseInt(s);

        则int变量n的值是123,该方法实际上实现了字符串和int之间的转换,如果字符串包含非数字字符,则程序执行将出现异常。

另外一个parseInt方法:

public static int parseInt(String s, int radix)

则实现将字符串按照参数radix指定的进制转换为int,使用示例如下:

int n = Integer.parseInt("120",10);
//将字符串"120"按照十进制转换为int,则结果为120
int n = Integer.parseInt("12",16);
//将字符串"12"按照十六进制转换为int,则结果为18
int n = Integer.parseInt("ff",16);
//将字符串"ff"按照十六进制转换为int,则结果为255

这样可以实现更灵活的转换。

b、toString方法

public static String toString(int i)

该方法的作用是将int类型转换为对应的String类型。

使用示例代码如下:

int m = 1000;
String s = Integer.toString(m);
则字符串s的值是"1000"。

3.3 字符串与基本数据类型、包装类型转换

1)包装类转换成字符串

        几乎java.lang.Object类派生的所有类提供了toString()方法,即将该类转换为字符串。例如:Characrer、Integer、Float、Double、Boolean、Short等类的toString()方法分别用于将字符型、整型、浮点型、双精度浮点型、短整型等类转换为字符串。举例如下所示:

int i1=10;
float f1=3.14f;
double d1=3.1415926;
Integer i1 = new Integer(i1);//生成Integer类
Float f1 = new Float(f1); //生成Float类
Double d1 = new Double(d1); //生成Double类
//分别调用包装类的toString() 方法转换为字符串
String si1 = i1.toString();
String sf1 = f1.toString();
String sd1 = d1.toString();
Sysytem.out.println("si1"+si1);
Sysytem.out.println("sf1"+sf1);
Sysytem.out.println("sd1"+sd1);

整数转换成字符串也可以采用如下方法:

int myInt = 1234;
String myString = "" + myInt;

其它数据类型可以利用同样的方法转换成字符串

2)字符串转换为基本数据类型 

字符串转换成整数:

String myNumber ="1234";
int myInt = Integer.parseInt(myNumber);

        字符串转换成byte、shor、int、float、double、long 等数据类型,可以分别参考Byte、Short、Integer、Float、Double、Long 类的parseXXX() 方法。

        其实,JDK自从5.0版本以后,就引入了自动拆装箱的语法,也就是在进行基本数据类型和对应的包装类转换时,系统将自动进行,这将大大方便程序员的代码书写。使用示例代码如下:

//int类型会自动转换为Integer类型
int m = 12;
Integer in = m;
//Integer类型会自动转换为int类型
int n = in;

        所以在实际使用时的类型转换将变得很简单,系统将自动实现对应的转换。Java允许基本类型和包装类型之间进行自动转换。例如可以自动装箱将一个基本数据类型转换为对象。

Integer intObject=new Integer(2);等价于 Integer intObject=2; //自动装箱

        将基本类型转换为包装类对象的过程称为装箱,相反的过程称为拆箱。如果一个基本类型出现在需要对象的环境中,编译器会将基本类型值进行自动装箱;如果一个对象出现在需要基本类型的环境中,编辑器将对象进行自动拆箱。考虑下面的例子:

  • Integer [] intArray ={1,2,3};
  • System.out.printLn(intArray[0] +  intArray [1] + intArray[2]);

        在第一行中,基本类型1、2、3被自动装箱成对象new Integer(1)、new Integer(2)、new Integer(3) ,在第二行中,对象intArray[0]、intArray[0]、intArray[0]被自动转换为int值,然后进行相加。

【例】包装类、基本数据类型和字符串之间转换的综合案例。

public class TestWrapper {
    public static void main(String ars[]){
        Double obj_d = new  Double(3.14);        //基本数据类型转换为包装类
        double d = obj_d.doubleValue();            //包装类转换为基本数据类型
        Integer obj_i = new Integer("5");        //字符串转换为包装类
        String s = obj_i.toString();                //包装类转换为字符串转换
        double n = Double.parseDouble("5");        //字符串类转换为基本数据类型
        String s = obj_j.toString();                //基本数据类型转换为字符串类型
        Integer aa = 9;                         //自动装箱
        int bb = aa;                            //自动拆箱
    }
}

程序分析:通过以上案例可以看出,基本数据类型和字符串类型转换为包装类,使用包装类的构造器来完成;包装类转换为基本数据类型,调用包装类的xxxValue()方法来完成;包装类转换为字符串类型,调用包装类的toString()方法;字符串转换为基本数据类型,调用包装类的parseXXX()方法;基本数据类型转换为字符串类型,先把基本数据类型转换为包装类型,然后再调用包装类的toString()方法;装箱就是把基本类型用它们相应的包装类型包装起来,使其具有对象的性质。int包装成Integer、float包装成Float,拆箱和装箱相反,将包装类型的对象转化成基本类型类型的数据。

1.4 字符串类

        字符串是我们在编程中最常使用的一种数据类型,Java中用类来描述字符串,其中最常用的字符串处理类是String,此外还有StringBuffer和StringBuilder。在本节,我们会了解每种字符串的特点,以便能在应用时选择合适的字符串类型。字符串不属于8种基本数据类型,而是一种引用类型。String对象代表一组不可改变的Unicode字符序列,对它的任何修改实际上又产生一个新的字符串,String类是final类型的类,所以String类对象的内容一旦被初始化就不能再改变。StringBuffer对象代表一组可改变的Unicode字符序列,StringBuilder是JDK5.0版本后引入的字符串处理类,其中的方法与StringBuffer类的相同。

1.4.1 String对象的创建

        String是比较特殊的数据类型,它不属于基本数据类型,但是可以和使用基本数据类型一样直接赋值,也可以像引用数据类型一样,使用关键字new进行实例化。

        String类型对象的实例化有两种方式: 

  • 静态方式(常用):直接给变量赋值,如:String s1 = "abc";  String s2 = "abc"; 
  • 动态方式:使用new运算符动态的给变量赋值,如:String s3 = new String("abc"); String s4 = new String("abc");

        那么这两种方式创建的字符串是同一个字符串对象吗?答案是否定的,这两种方式创建的字符串对象是有区别的。

区别在于:使用静态方式创建的字符串,如果前后两次创建的字符串内容相同,则在堆区的常量池中只会产生一个字符串对象,即两个引用指向同一块地址。而使用动态方式创建的字符串,不管前后两次创建的字符串内容是否相同,每创建一次,都会在堆内存中会产生出不同的对象,即两个引用指向不同的地址。

        对于上面采用静态方式创建的字符串s1、s2与采用动态方式创建字符串s3和s4其内存空间分配方式示意如下所示。

动态创建String对象时需要用到构造方法,String类的常用的构造方法如下,更多构造方法请直接查阅Java API。

  • 初始化一个新创建的String 对象,它表示一个空字符序列。

String 变量名 = new String() ;

初始化一个新创建的String对象,表示一个空字符串(" ");注意空字符串与null的区别,空字符串表示String对象的内容为空,而null表示String类的变量不指向任何的String对象。

  • 初始化一个新创建的 String对象,表示一个与该参数相同的字符序列。

String 变量名 = new String (String value) ;

  • String(char chars[]) 使用一个字符数组创建一个String对象。

另外String在使用的时候不需要用import语句导入。

注意,当使用"+"运算符进行运算时,如果参与运算的有字符串,则"+"的含义为进行字符串连接,当参与运算的没有字符串时,则"+"的含义为算术运算符加号。例如:

String str1 = "hello ";

String str2 = "world"; 

System.out.println (str1 + str2);  //输出结果为"hello world"

System.out.println(5 + 6 + 'A');  //输出结果为76

System.out.println(5 + 6 + "A");  //输出结果为11A

System.out.println(5 + "A" +6);  //输出结果为5A6

1.4.2 String 对象的不可变性

任何一个String对象在创建之后都不能对它的内容作出任何改变。对于连接、获得子串和改变大小写等操作,如果返回值同原字符串不同,实际上是产生了一个新的String对象,在程序的任何地方,相同的字符串字面常量都是同一个对象,下面的代码会改变字符串s的内容吗?

String s = "Java";

s = "HTML";

答案是不会。第一条语句创建了一个内容为"Java"的String对象,并将其引用赋值给s。第二条语句创建了一个内容为"HTML"的新String对象,并将其引用赋值给s。赋值后第一个String对象仍然存在,但是不能再访问它,因为变量s现在指向了新的对象HTML,如图1-4所示。

图1-4字符串是不可改变的,一旦创建,它们的内容不能修改

因为字符串在程序设计中是不可改变的,但同时又会被频繁地使用,所以Java虚拟机为了提高效率并节省内存,对具有相同字符串序列的字符串直接使用同一个实例。例如下面的语句:

String str1 = "hello"; 

String str2 = new String("hello");

String str3 = "hello";

System.out.println(str1==str2); 

System.out.println(str1==str3);

程序运行结果:

false

true

1.4.3 字符串的比较

String类提供了多种对字符串比较的方法,具体如表1-6所示。

表1-6 字符串比较方法

方法

含义

boolean equals(String)

判断两个字符串对象的内容是否相等

boolean equalsIgnoreCase(String)

比较两个字符串的内容是否相等,忽略大小

int compareTo(s1:String)

返回一个大于0、等于0或者小于0的整数以表明这个字符串是大于、等于还是小于s1

int compareToIgnoreCase(String)

除了不区分大小写外,其他都和compareTo是一样的

boolean regionMatchs(int, String, int, int)

如果这个字符串指定的子域精确匹配字符串s1中指定的子域则返回true

boolean startsWith(String prefix)

测试此字符串是否以指定的前缀开始

boolean endsWith(String suffix)

测试此字符串是否以指定的后缀结束

例如,下面的语句先显示true,然后显示false.
String s1 = new String("welcome to Java");
String s2 = "welcome to Java";
String s3 = "welcome to C++";
System.out.println(s1.equals(s2)); //true
System.out.println(s1.equals(s3));//false
【例1-5】字符串equals方法练习
String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("abc");
String s4 = "abc";
System.out.println(s1.equals(s2));   //true
System.out.println(s1.equals(s4));   // true
System.out.println(s2.equals(s3));   //true
程序分析:equals方法用来比较两个字符串是否相等。
【例1-6】重写equals()方法,判断不同的点,是否是坐标系上的同一点。
//点类
public class Point {
    private int x; //x坐标
    private int y;//y坐标
    public Point(int x,int y){
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    @Override
    public String toString() {
        return "("+x+","+y+")";
    }    
        //如果x,y的值相同,就认为是坐标上的同一点
    public boolean equals(Object obj) {
          if(obj == null){
              return false;
          }
          if(this == obj){
              return true;
          }
          if(!(obj instanceof Point)){
              return false;
          } else {
              Point p = (Point)obj;
              if(p.x==x&&p.y==y){
                  return true;
              } else {
                  return false;
              }
          }
        }
}
//测试类
public class TestPoint {
        public static void main(String[] args) {
            Point p1 = new Point(55,66);
            Point p2 = new Point(55,66);
            Point p3 = new Point(22,33);
            System.out.println(p1.equals(p2));
            System.out.println(p1==p2);
            System.out.println(p1.equals(p3));
            System.out.println(p1==p3);
        }
}
程序运行结果:
true
false
false
false

程序分析:上例测试中main()方法中实例化了3个点,分别使用equals方法与==进行比较,因为Point类覆盖了父类的equals()方法,该方法判断如果两个Point对象的x坐标和y坐标相等,则返回true,所以第1行输出为true,"=="运算符比较引用数据类型时,判断两个引用是否指向同一个对象,p1,p2,p3都分别是不同的对象,所以第2行和第4行输出为false。

compareTo方法也可以用来对字符串进行比较。方法如下:

s1.compareTo(s2)

如果s1与s2相等,那么该方法返回值为0;如果按字典序(即以统一码的顺序)s1小于s2,那么方法返回值小于0;如果按字典序s1大于s2,方法返回值大于0。

方法compareTo返回的实际值是依据s1和s2从左到右数第一个不同字符之间的距离得出的,例如,假设s1为“abc”,s2为“abg”,那么s1.compareTo(s2)返回-4。首先比较的是s1与s2中第一个位置的字符(a与a)。因为它们相等,所以比较第二个位置的两个字符(b与b)。因为它们也相等,所以比较第三个位置的两个字符(c与g)。由于字符c比字符g小4,所以比较之后返回-4。如果使用像>、>=、<或<=这样的比较运算符比较两个字符串,就会发生错误,替代的方法就是使用s1.compareTo(s2)来进行比较。

如果两个字符串相等,equals方法返回true;如果不相等,方法返回false。compareTo方法会根据一个字符串是否等于、大于或小于另一个字符串,分别返回0、正整数或负整数。

1.4.4字符串与数组之间的转换

字符串不是数组,但是字符串可以转换成数组,反之亦然。

(1)与字符数组之间的转换

为了将字符串转换成一个字符数组,可以使用toCharArray方法。例如,下述语句将字符串"Java "转换成一个字符数组:

Char[] chars= "Java".toCharArray();

因此chars[0]是'J',chars[1]是'a',chars[2]是'v',chars[3]是'a'。

还可以使用方法getChars(int srcBegin,int srcEnd,char[]dst,int dstBegin)将下标从srcBegin到srcEnd-1的子串复制到字符数组dst中下标从dstBegin开始的位置。例如,下面的代码功能是把字符串"CS3720"中下标从2到6-1的子串"3720"复制到字符数组dst中,赋值时下标从4开始的位置:

Char[] dst={'j','a','v','a','1','3','0','1'};

"CS3720".getChars(2,6,dst,4);

这样,dst就变成了{'j','a','v','a','3','7','2','0'}。

为了将一个字符数组转换成字符串,应该使用构造方法String(char[])或者方法valueOf(char[])。例如,下面的语句使用String构造方法把一个字符数组构造成一个字符串:

String str = new String(new char[]{'j','a','v','a'});

下面的语句使用valueOf方法把一个字符数组构造成一个字符串:

String str = String.valueOf(new char[]{'j','a','v','a'});

(2)与字节数组之间的转换

Java中能够把字符串转换为字节数组,有3种形式。

形式1:public byte[] getBytes()

方法定义:以默认编码把字符串转换为字节数组

形式2:public byte[] getBytes(Charset charset)

方法定义:按照指定的字符集把字符串转换为字节数组

形式3:public byte[] getBytes(String charsetName)

方法定义:按照指定的字符集把字符串转换为字节数组

【例1-7】 使用平台的默认字符集,统计一个字符串所占用的字节数。
public class TestStringByte{ 
    public static void main(String[] args) {
        String str = "Java语言程序设计";
        byte bytes[] = str.getBytes();
        System.out.println(bytes.length);
    } 
}
程序运行结果:
16

程序分析:通过getBytes()方法把字符串转换成字节数组,字节数组的长度就是字符串所占的字节数。

【例1-8】通过字节数组创建字符串对象
public class TestStringCharset { 
    public static void main(String[] args) {
        byte[] bName = new byte[10]; 
        String name1 = "张三"; 
        try{ 
            bName = name1.getBytes("utf-8"); //这种编码方式一个中文占三个字节
          String name2 = new String(bName,"utf-8"); 
          System.out.println("name2="+name2); 
        for(int i = 0;i< bName.length;i++){ 
              System.out.print(bname[i]); 
            } 
        }catch (UnsupportedEncodingException e){ 
            e.printStackTrace(); 
        } 
    } 
}
程序运行结果:
name2=张三
-27-68-96-28-72-119

程序分析:getBytes()是将一个字符串转化为一个字节数组。String的getBytes()方法是得到一个系统默认的编码格式的字节数组。将一个String类型的字符串中包含的字符转换成byte类型并且存入一个byte数组中。在Java中的所有数据底层都是字节,字节数据可以存入到byte数组。存储字符数据时(字符串就是字符数据),会先进行查表,然后将查询的结果写入设备,读取时也是先查表,把查到的内容打印到显示设备上,getBytes()是使用默认的字符集进行转换,getBytes(“utf-8”)是使用UTF-8编码表进行转换。例如: byte [] b_Uf8 = "中国".getBytes("UTF-8");//获得字节数组 String s_Utf8 = new String(b_utf8,"UTF-8");//使用指定的UTF-8编码来将byte[]解析成字符串。

(3)String类与数组的转换示意图

字符串可以和字节数组与字符数组之间互相转换,

其转换过程如图1-5所示

1.4.5 String中的常用的方法

String的一些常用方法如表1-7所示。

表1-7 String类的常用方法

方法

含义

byte[] getBytes(Charset charset)

使用给定的 charset将此String 编码到byte 序列,并将结果存储到新的byte 数组

String[] split(String regex)

根据给定正则表达式的匹配拆分此字符串。

String replace(char oldChar, char newChar)

返回一个新的字符串,它是通过用newChar 替换此字符串中出现的所有oldChar 得到的

String toUpperCase()

将String对象中的所有字符都转换为大写

String toLowerCase()

将String对象中的所有字符都转换为小写

char charAt(int)

返回指定索引处的 char 值

String substring(int begin)

返回一个新字符串,该字符串是从begin开始的字符串的内容

String substring(int begin,int end)

返回一个新字符串,该字符串是从begin开始到end-1结束的字符串的内容

int indexOf/lastIndexOf(char)

返回指定字符在此字符串中第一次/最后一次出现处的索引。

int indexOf/lastIndexOf(char,int)

从指定的索引开始搜索,返回在此字符串中第一次/最后一次出现指定字符处的索引

int indexOf/lastIndexOf(String)

返回第一次出现的指定子字符串在此字符串中的索引

int indexOf/lastIndexOf(String,int)

从指定的索引开始搜索,返回在此字符串中第一次/最后一次出现指定字符串处的索引

String trim()

返回新的字符串,忽略前导空白和尾部空白

int length()

返回此字符串的长度

String concat(String str)

将指定字符串连接到此字符串的结尾

byte[] getBytes()

使用平台的默认字符集将此String 编码为byte 序列,并将结果存储到一个新的byte 数组中

下面对常用的一些方法进行详细说明,为了便于说明,方法中使用的示例字符串为:str="this is a test!";

(1)求长度

方法定义:public int length() 。

方法描述:获取字符串中的字符的个数。

例如:

str.length()

结果:

15

(2)获取字符串中的字符

方法定义:public char charAt(int index)。

方法描述:获取字符串中的第index个字符,从0开始。

例如:

str.charAt(3)

结果:

s

注意:是第4个字符。

【例1-9】 统计一个字符串中字符e出现的次数。
public class TestString {
    public static void main(String[] args) {
        String s = "abecedkjkacedjkdseddklj";
        int num = 0;
        for(int i=0; i<s.length(); i++){
            char c = s.charAt(i);
            if(c == 'e'){
                num++;
            }
        }
        System.out.println("该字符串中字符e出现"+num+"次");
      }
}

程序分析:程序中num的作用是用来记录字符'e'出现的次数

(3)取子串

有两种形式:

形式1如下:

方法定义:public String substring(int beginIndex,int endIndex)。

方法描述:获取从beginIndex 开始到endIndex 结束的子串,包括beginIndex,不包括endIndex。

例如:

str.substring(1,4)

结果:

his

形式2如下:

方法定义:public String substring(int beginIndex)

方法描述:获取从beginIndex开始到结束的子串

例如:

str.substring(5)

结果:

is a test!

(4)定位字符或者字符串

有4种形式:

形式1如下:

方法定义:public int indexOf(int ch)

方法描述:定位参数所指定的字符。

例如:

str.indexOf('i')

结果:

2

形式2如下:

方法定义:public int indexOf(int ch,int index)

方法描述:从index开始定位参数所指定的字符。

例如:

str.indexOf('i',4)

结果:

5

形式3如下:

方法定义:public int indexOf(String str)

方法描述:定位参数所指定的字符串。

例如:

str.indexOf("is")

结果:

2

形式4如下:

方法定义:public int indexOf(String str,int index)

方法描述:从index开始定位str所指定的字符串。

例如:

str.indexOf("is",6)

结果:

-1表示没有找到

(5)替换字符和字符串

有3种形式:

形式1如下:

方法定义:public String replace(char c1,char c2) 

方法描述:把字符串中的字符c1替换成字符c2 

例如:

str.replace('i','I')

结果:

thIs Is a test!

形式2如下:

方法定义:public String replaceAll(String s1,String s2)

方法描述:把字符串中出现的所有的s1替换成s2

例如:

replaceAll("is","IS")

结果:

thIS IS a test!

形式3如下:

方法定义:public String replaceFirst(String s1,String s2)

方法描述:把字符串中的第一个s1替换成s2

例如:

replaceFirst("is","IS")

结果:

thIS is a test!

(6)比较字符串内容

两种形式:

形式1如下:

方法定义:public boolean equals(Object o)

方法描述:比较字符串内容是否与参数相同,区分大小写。

例如:

str.equals("this")

结果:

false

形式2如下:

方法定义:public boolean equalsIgnoreCase(Object o)

方法描述:比较是否与参数相同,不区分大写小。

例如:

str.equalsIgnoreCase("this")

结果:

false

(7)大小写转换

转换成大写或者转换成小写。

转换成大写:

方法定义:public String toUpperCase()

方法描述:把字符串中的所有字符都转换成大写。

例如:

str.toUpperCase() 

结果:

THIS IS A TEST!

转换成小写:

方法定义:public String toLowerCase()

方法描述:把字符串中的所有字符都转换成小写。

例如:

str.toLowerCase() 

结果:

this is a test!

(8)前缀和后缀

判断字符串是否以指定的参数开始或者结尾。

判断前缀:

方法定义:public boolean startsWith(String prefix)

方法描述:字符串是否以参数指定的子串为前缀。

例如:

str.startsWith("this")  

结果:

true

判断后缀:

方法定义:public boolean endsWith(String suffix)

方法描述:字符串是否以参数指定的子串为后缀。

例如:

str.endsWith("this")

结果:

false

import java.io.DataInputStream;
public class StringTest {
    public static void main(String args[]){
        System.out.println("计算第一个字符串在第二个字符串中出现的次数");        
// 通过如下语句,实例化一个从控制台读取输入内容的对象din 
    DataInputStream din = new DataInputStream(System.in);
        try{
            System.out.println("请输入第一个字符串");
            String str1 = din.readLine();//读入一行数据
            System.out.println("请输入第二个字符串");
            String str2 = din.readLine();
            String str3 = str2.replace(str1,"");//把str2中的str1用空串替换,并赋给str3
            int count = str2.length() - str3.length();//str2的长度减去str3的长度
            System.out.println(str1+"在"+str2+"中出现的次数为:"+count);
        }catch(Exception e){
            System.out.println(e.toString());
        }
    }
}

程序运行结果:

计算第一个字符串在第二个字符串中出现的次数

请输入第一个字符串

ab

请输入第二个字符串

abcedabsdabajab

ab在abcedabsdabajab中出现的次数为:4

需要注意的是String本身是一个常量,一旦一个字符串创建了,它的内容是不能改变的,那么如何解释下面的代码:

s1+=s2;

这里并不是把字符串s2的内容添加到字符串s1的后面,而是新创建了一个字符串,内容是s1和s2的连接,然后把s1指向了新创建的这个字符串。如果一个字符串的内容经常需要变动,不应该使用String,因为在变化的过程中实际上是不断创建对象的过程,这时候应该使用StringBuffer。

【例1-11】使用字符串中的常用方法实现Email格式的判断。
public class EmailCheckException extends Exception {
    public EmailCheckException(String msg) {
        super(msg);
    }
public class StringExercise {
    public static void checkEmail(String email) throws EmailCheckException {
        int len = email.length();         //email的长度
        int begin = email.indexOf('@');   //从开始检索字符@在email中的位置
        int end = email.lastIndexOf('@'); //从结尾检索字符@在email中的位置
        int dot = email.indexOf('.', begin);//检索.是否在@后存在
        //判断长度是否不超过20
        if (email.length() > 20)
            throw new EmailCheckException("Email长度不能大于20");
        //判断是否唯一包含@
        else if (begin != end)
            throw new EmailCheckException("Email中含有多个@");
        //判断@是否存在或在开头或在结尾
        else if (begin == -1 || begin == 0 || begin == (len - 1))
            throw new EmailCheckException("Email中没有@或@位置错误");
        //判断@后是否有.
        else if (dot == -1)
            throw new EmailCheckException("@后缺少域分隔符");
        //判断@是否在末尾
        else if (dot == (len - 1))
            throw new EmailCheckException("分隔符错误");
    }
    public static void main(String args[]) {
            String email = args[0];
        try {
            checkEmail(email);
            } catch (EmailCheckException e) {
            e.printStackTrace();
        }
    }
}
}

程序分析:自定义了一个EmailCheckException异常类,当Email格式不符合要求时将抛出一个异常对象。程序中使用字符串的length()方法判断Email长度是否正确。通过indexOf()和lastIndexOf()分别从头和从尾查找@的位置,若从头查找和从尾查找到的@位置相等,说明字符串中只有一个@字符,否则存在多个@字符,则不是合法的Email格式。最后查找字符“.”的位置。若其位置在@字符后,且字符串中含有这个字符则是合法的Email格式。

1.5Date类中常用方法

表1-10列出了Date类的常用方法。

表1-10 Date类的常用方法

方法

含义

boolean after(Date when)

测试此日期是否在指定日期之后

boolean before(Date when)

测试此日期是否在指定日期之前

int compareTo(Date anotherDate)

比较两个日期的顺序。如果参数 Date 等于此 Date,则返回值 0;如果此 Date 在 Date 参数之前,则返回小于 0 的值;如果此 Date 在 Date 参数之后,则返回大于 0 的值。

boolean equals(Object obj)

比较两个日期的相等性。

Date类不支持国际化。现在我们更应该多使用Calendar类来实现日期和时间字段之间转换,使用DateFormat类来格式化和分析日期字符串,Date中的相应方法已废弃。

【例1-17】Date类常用方法练习
public class TestDate {
    public static void main(String[] args) {
        Date now = new Date();//获取当前系统时间
        System.out.println(now); //获取1970年1月1日1000毫秒之后的时间
        Date d1 = new Date(1000);
        System.out.println(now.after(d1));
        System.out.println(now.before(d1));
        System.out.println(now.compareTo(d1));
    }
}
程序运行结果:
true
false
1
程序分析:本程序主要练习日期类的几个常用方法,这几个方法的详细说明请参见表1-10。

1.5.3 Calender类

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

java.util.Calendar是一个抽象的基类,可以提取详细的日历信息,例如年、月、日、小时、分和秒,Calendar的子类可以实现特定的日历系统。在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance()方法创建即可。

1、使用Calendar类代表当前时间

Calendar c = Calendar.getInstance();

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

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

2、使用Calendar类代表指定的时间

Calendar c1 = Calendar.getInstance();

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

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

set()方法的声明为:

 public final void set(int year,int month,int date)

以上示例代码设置的时间为2009年3月9日,其参数的结构和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号,其它所有的数值会被重新计算,例如星期几以及对应的相对时间数值等。

3、获得Calendar类中的信息

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类中的get()方法可以获得Calendar对象中对应的信息,get()方法的声明如下:

public int get(int field)

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

4、其它方法说明

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

a、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天以后的日期,例如若当前时间为2015年8月7日,则程序的输出结果为:2015年11月15日

b、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代表的时间是2009年10月10号,对象c5代表的时间是2010年10月10号,则对象c5代表的日期在c4代表的日期之后,所以after()方法的返回值是true。

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

c、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);

5、Calendar对象和相对时间之间的互转

  Calendar c8 = Calendar.getInstance();

  long t = 1252785271098L;

  //将Calendar对象转换为相对时间

  long t1 = c8.getTimeInMillis();

  //将相对时间转换为Calendar对象

  Calendar c9 = Calendar.getInstance();

  c9.setTimeInMillis(t1);

在转换时,使用Calendar类中的getTimeInMillis()方法可以将Calendar对象转换为相对时间。在将相对时间转换为Calendar对象时,首先创建一个Calendar对象,然后再使用Calendar类的setTimeInMillis()方法设置时间即可。

1.5.4 Calendar 类常用属性

表1-11列出了Calendar类的属性。

表1-11 Calendar类的常用属性

属性

含义

static int HOUR

小时时间

static int MINUTE

分时间

static int SECOND

秒时间

static int DATE

日期的Date部分

static int MONTH

日期的Month部分

static int YEAR

日期的年部分

【例1-18】Calendar类使用练习
public class TestCalendar {
    public static void main(String[] args) {
        //获取Calendar类的实例
        Calendar c = Calendar.getInstance();
      System.out.println(c.get(Calendar.YEAR)+"年"+
                           (c.get(Calendar.MONTH)+1)+"月"+
                           c.get(Calendar.DAY_OF_MONTH)+"日");        
        //设置指定时间
        c.set(2011,10,11);
        System.out.println(c.get(Calendar.YEAR)+"年"+ (c.get(Calendar.MONTH)+1)+"月"+           c.get(Calendar.DAY_OF_MONTH)+"日");
      Calendar c1 = Calendar.getInstance();
      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 + "日");
    }
}

程序分析:本例使用时间和日期处理方法进行计算。该程序实现的原理为:首先代表两个特定的时间点,这里使用Calendar的对象进行代表,然后将两个时间点转换为对应的相对时间,求两个时间点相对时间的差值,然后除以1天的毫秒数(24小时X60分钟X60秒X1000毫秒)即可获得对应的天数。

【例】输出当前月的月历,该示例的功能是输出当前系统时间所在月的日历,例如当前系统时间是

2009年3月10日,则输出2009年3月的日历。
import java.util.Calendar;
public class DateExample2{
  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();       
  }       
}

程序运行结果:
星期日   星期一   星期二  星期三  星期四  星期五   星期六
1      2
3              4        5         6         7      8     9
10           11     12        13    14          15     16
17           18     19        20    21          22     23
24           25     26        27    28        29     30

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

1.5.5 SimpleDateFormat类的使用

        java.text.SimpleDateFormat是一个以与语言环境相关的方式来格式化和分析日期的具体类,是抽象类java.text.DateFormat类的子类,SimpleDateFormat使得可以选择任何用户定义的日期-时间格式的模式,获取SimpleDateFormat的实例如下:

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

        上面代码确立了转换的格式,yyyy是完整的西元年,MM是月份,dd是日期,HH:mm:ss分别是小时、分和秒。至于为什么有的格式大写,有的格式小写,那是怕避免混淆,例如MM是月份,mm是分;HH是24小时制,而hh是12小时制,表1-12列出了SimpleDateFormat类中的模式字母。

字母

日期或时间元素

y

M

年中的月份

d

月份中的天数

E

星期中的天数

a

Am/pm 标记

H

一天中的小时数(0-23)

h

am/pm 中的小时数(1-12)

m

小时中的分钟数

s

分钟中的秒数

S

毫秒数

1)字符串转日期:

        2002-10-8 15:30:22要把它转成日期,可以用 Date date=sdf.parse("2002-10-8 15:30:22"); 

2)日期转字符串:

        假如把今天的日期转成字符串可用 String datestr=sdf.format(new Date()); 

        这个字符串的内容便类似2002-10-08 14:55:38

        透过这个API我们便可以随心所欲的将日期转成我们想要的字符串格式,例如希望将日期输出成2002年10月08日,可以这么写:

  • SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日"); 
  • String dateStr=sdf.format(new Date()); 

dateStr便会依照我们设定的格式输出。

【例】SimpleDateFormat的使用。

public class TestDateFormat {
   public static void main(String[] args) {
       //获取指定日期格式的SimpleFormat实例 1999年09月09日 12:12:12
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");           //获取指定日期的格式化字符串
String nowStr = sdf.format(new Date());
       System.out.println(nowStr);    
       //将格式化的字符串转换成日期
       try {
             Date d = sdf.parse("2011-11-11 11:11:11");
             System.out.println(d);
         } catch (ParseException e) {
            System.out.println("输入的字符串不符合日期的格式");
            e.printStackTrace();
}    
  }
}

程序分析:SimpleDateFormat 是Java中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出。

1.6DecimalFormat和NumberFormat

        在很多时候需要对输出的内容进行格式化,尤其是当输入的内容为数字的时候,需要按照特定的格式进行输出。另外,对运行的结果可能需要特殊的处理,例如结果只保留小数点后2位。对数字进行格式化需要使用下面的两个类:

  • java.text.DecimalFormat
  • java.text.NumberFormat 

        DecimalFormat是NumberFormat的一个具体子类,通常使用DecimalFormat的构造方法来生成格式,例如:

NumberFormat nf=new DecimalFormat("0.00");

        "0.00"表示数字的格式为小数点后保留两位,如果整数部分为0,0不能省略,小数点后如果是0也不能省略。下面是3个转换的例子:

  • 10.374-----10.37
  • 10.301-----10.30
  • 0.301------0.30

        在格式中另外还有一个“#”,表示一个数字,如果是0不显示,下面的例子使用了“#”号,并且整数部分每3位中间用“,”号隔开。

NumberFormat nf2=new DecimalFormat("###.###.###.##");

【例】DecimalFormat类的使用

import java.text.DecimalFormat;
import java.util.Random;
import java.util.Locale;
public class TestNumberFormat {
 public static void main(String[] args) {
  double pi = 3.1415927;//圆周率
  //取一位整数
  System.out.println(new DecimalFormat("0").format(pi)); //3
  //取一位整数和两位小数
  System.out.println(new DecimalFormat("0.00").format(pi)); //3.14        
  //取两位整数和三位小数,整数不足部分以0填补。
  System.out.println(new DecimalFormat("00.000").format(pi)); //03.142
  //取所有整数部分
  System.out.println(new DecimalFormat("#").format(pi)); //3
  //以百分比方式计数,并取两位小数
  System.out.println(new DecimalFormat("#.##%").format(pi)); //314.16%
  long c = 299792458;//光速
  //显示为科学计数法,并取五位小数
  System.out.println(new DecimalFormat("#.#####E0").format(c)); //2.99792E8
  //显示为两位整数的科学计数法,并取四位小数
  System.out.println(new DecimalFormat("00.####E0").format(c)); //29.9792E7
  //每三位以逗号进行分隔。
  System.out.println(new DecimalFormat(",###").format(c)); //299,792,458
  //将格式嵌入文本
  System.out.println(new DecimalFormat("光速大小为每秒,###米。").format(c));//光速大小为每秒299,792,458米。
  //直接截取
  System.out.println(Math.floor(24.335*100)/100);  //24.33        
  System.out.println((int)Math.floor(23.45));   //截取整数 23
  System.out.println((int)Math.ceil(23.2));    //凑整 24
  System.out.println((int)Math.rint(23.567));   //四舍五入取整 24
  System.out.println(new DecimalFormat("0").format(25.5)); //四舍五入取整 26
  System.out.println(Math.random());   //随机double 0.9786833725139645
  System.out.println(new Random().nextFloat());  //随机浮点数 0.5196178
  System.out.println(new Random().nextBoolean()); //随机boolean
  }
}

程序分析:DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hulake_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值