Java私塾跟我学系列——JAVA篇 第六章 常见类的使用

教学目标:

i理解和掌握Object

i理解和掌握String

i理解和掌握StringBuffer

i理解和掌握StringBuilder

i掌握Math的使用

i掌握日期相关类的使用

i掌握System类的使用


一、Object                                                   

java.lang包中定义的Object类是所有Java类的根父类,其中定义了一些实现和支持面向对象机制的重要方法。任何Java对象,如果没有父类,就默认它继承了Object类。因此,实际上,以前的定义是下面的简略:

public class Employee extends Object 和

public class Manager extends Employee

    Object类定义许多有用的方法,包括toString(),它就是为什么Java软件中每样东西都能转换成字符串表示法的原因。(即使这仅具有有限的用途)。 

1.equals方法                                                                           

Object类定义的equals方法用于判别某个指定的对象与当前对象(调用equals方法的对象)是否等价。在Java语言中数据等价的基本含义是指两个数据的值相等。

”==”进行比较的时候,引用类型数据比较的是引用,即内存地址,基本数据类型比较的是值。

1.1  equals方法与“==”运算符的关系

equals()方法只能比较引用类型,"=="可以比较引用类型及基本类型;

特例:当用equals()方法进行比较时,对类File、String、Date及包装类来说,是比较类型及内容而不考虑引用的是否是同一个实例,因为这些类中已经重写了equals方法,实现了比较内容的功能。源码可参看JDK目录下的src.zip中的相应部分。

用"=="进行比较时,符号两边的数据类型必须一致(可自动转换的数据类型除外),否则编译出错,而用equals方法比较的两个数据只要都是引用类型即可。

示例如下:

class MyDate {

    private int day, month, year;

    public MyDate(int day, int month, int year) {

       this.day = day;

       this.month = month;

       this.year = year;

    }

}

public class Test {

    public static void main(String[] args) {

       MyDate m1 = new MyDate(8, 8, 2008);

       MyDate m2 = new MyDate(8, 8, 2008);

 

       if (m1 == m2) {

           System.out.println("m1==m2");

       } else {

           System.out.println("m1!=m2");

       }

       if (m1.equals(m2)) {

           System.out.println("m1 is equal to m2");

       } else {

           System.out.println("m1 is not equal to m2");

       }

 

       m2 = m1;

       if (m1 == m2) {

           System.out.println("m1==m2");

       } else {

           System.out.println("m1!=m2");

       }

    }

}

程序运行结果为:

m1!=m2

m1 is not equal to m2

m1==m2

 小结一下:

在引用类型的比较上,Object里面的equals方法默认的比较方式,基本上等同于“==”,都是比较内存地址,只有那几个特殊的是比较的对象的内容(属性值)。自己写的类也可以做这样的覆盖工作。下面介绍详细的做法。

1.2  覆盖equals方法

对于程序员来说,如果一个对象需要调用equals方法,应该在类中覆盖equals方法。如果覆盖了equals方法,那么具体的比较就按照你的实现进行比较了。

一般来讲:为了比较两个分离的对象(也就是内存地址不同的两个对象),自行覆盖的equals方法里面都是检查类型和值是否相同。上面那几个特殊的情况就是这样,比如String类,它覆盖了equals方法,然后在里面进行值的比较。

覆盖equals方法的一般步骤如下:

(1)用==检查是否参数就是这个对象的引用

(2)判断要比较的对象是否为null,如果是null,返回false

(3)用instanceof判断参数的类型是否正确

(4)把参数转换成合适的类型

(5)比较对象属性值是不是匹配 

示例如下:

覆盖前equals==比较的都是内存地址:

public class Test{

    public static void main(String[] args) {

       A a1 = new A();

       a1.age = 3;

       A a2 = new A();

       a2.age = 3;

       System.out.println("a1 == a2 test ="+(a1==a2));

       System.out.println("a1 equals a2 test ="+a1.equals(a2));

    }

}

class A{

    public int age = 0;

}

运行结果是:

a1 == a2 test =false

a1 equals a2 test =false 

覆盖后equals比较的是值,==比较的是内存地址

public class Test{

    public static void main(String[] args) {

       Test t = new Test();

       A a1 = new A();

       a1.age = 3;

       A a2 = new A();

       a2.age = 3;

       System.out.println("a1 == a2 test ="+(a1==a2));     

       System.out.println("a1 equals a2 test ="+a1.equals(a2));

    }

}

class A{

    public int age = 0;

    public boolean equals(Object obj){

       //第一步先判断是否同一个实例

       if(this==obj){

           return true;

       }

//第二步判断要比较的对象是否为null

       if (obj == null){

           return false;

       }

       //第三步判断是否同一个类型

       if(obj instanceof A){

           //第四步类型相同,先转换成为同一个类型

           A a = (A)obj;

           //第五步然后进行对象属性值的比较

           if(this.age == a.age){

              return true;

           }else{

              return false;

           }

       }else{

           //类型不同,直接返回false

           return false;

       }

    }

} 

说明:如果对象的属性又是一个引用类型的话,会继续调用该引用类型的equals方法,直到最后得出相同还是不同的结果。示例如下:

public class Test{

    public static void main(String[] args) {

       Test t = new Test();

       A a1 = new A();

       a1.age = 3;

       A a2 = new A();

       a2.age = 3;

       System.out.println("a1 == a2 test ="+(a1==a2));     

       System.out.println("a1 equals a2 test ="+a1.equals(a2));

    }

}

class A{

    public int age = 0;

    public String name = "Java私塾";

    public boolean equals(Object obj){

       //第一步先判断是否同一个实例

       if(this==obj){

           return true;

       }

//第二步判断要比较的对象是否为null

       if (obj == null){

           return false;

       }

       //第三步判断是否同一个类型

       if(obj instanceof A){

           //第四步类型相同,先转换成为同一个类型

           A a = (A)obj;

           //第五步然后进行对象属性值的比较

           if(this.age == a.age && this.name.equals(a.name)){

              return true;

           }else{

              return false;

           }

       }else{

           //类型不同,直接返回false

           return false;

       } 

最后重要的一点规则:覆盖equals方法应该连带覆盖hashCode方法。 

2.hashCode方法                                                                  

hashCode是按照一定的算法得到的一个数值,是对象的散列码值。主要用来在集合(后面会学到)中实现快速查找等操作,也可以用于对象的比较。

在Java中,对hashCode的规定如下:

(1)在同一个应用程序执行期间,对同一个对象调用hashCode(),必须返回相同的整数结果——前提是equals()所比较的信息都不曾被改动过。至于同一个应用程序在不同执行期所得的调用结果,无需一致。

(2)如果两个对象被equals(Object)方法视为相等,那么对这两个对象调用hashCode()必须获得相同的整数结果。

(3) 如果两个对象被equals(Object) 方法视为不相等,那么对这两个对象调用hashCode()不必产生不同的整数结果。然而程序员应该意识到,对不同对象产生不同的整数结果,有可能提升hashTable(后面会学到,集合框架中的一个类)的效率。

简单地说:如果两个对象相同,那么它们的hashCode值一定要相同;如果两个对象的hashCode相同,它们并不一定相同。

在Java规范里面规定,覆盖equals方法应该连带覆盖hashCode方法,这就涉及到一个如何实现hashCode方法的问题了。 

实现一:偷懒的做法:对同一对象始终返回相同的hashCode,如下:

public int hashCode(){

      return 1;

}

它是合法的,但是不好,因为每个对象具有相同的hashCode,会使得很多使用hashCode的类的运行效率大大降低,甚至发生错误。

 

实现二:采用一定的算法来保证

在高效Java编程这本书里面,给大家介绍了一个算法,现在eclipse自动生成equals方法和hashCode方法就是用的这个算法,下面介绍一下这个算法:

(1) 将一个非0常数,例如31,储存于int result变量

(2)对对象中的每个有意义的属性f(更确切的说是被equals()所考虑的每一个属性)进行如下处理:

 A. 对这个属性计算出类型为int的hash 码 c:

    i. 如果属性是个boolean,计算(f ? 0 : 1)。

    ii. 如果属性是个byte,char,short或int,计算(int)f。

    iii. 如果属性是个long,计算(int)(f^(f >>> 32))。

    iv. 如果属性是个float,计算Float.floatToIntBits(f)。

    v. 如果属性是个double,计算Double.doubleToLongBits(f),然后将计算结果按步骤2.A.iii处理。

    vi. 如果属性是个对象引用,而且class 的equals()通过递归调用equals()的方式来比较这一属性,那么就同样也对该属性递归调用hashCode()。如果需要更复杂的比较,请对该属性运算一个范式(canonical representation),并对该范式调用hashCode()。如果属性值是null,就返回0(或其它常数;返回0 是传统做法)。

    vii. 如果属性是个数组,请将每个元素视为独立属性。也就是说对每一个有意义的元素施行上述规则,用以计算出hash 码,然后再依步骤2.B将这些数值组合起来。

B. 将步骤A计算出来的hash码 c按下列公式组合到变量result中:

result = 31*result + c;

(3) 返回result。 

示例如下:这个就是用eclipse自动生成的

public class Test{     

    private byte byteValue;

    private char charValue;

    private short shortValue;

    private int intValue;

    private long longValue;

    private boolean booleanValue;

    private float floatValue;

    private double doubleValue;

    private String uuid;

    private int[] intArray = new int[3]   

    public int hashCode() {

        final int prime = 31;

        int result = 1;

        result = prime * result + (booleanValue ? 1231 : 1237);

        result = prime * result + charValue;

        long temp;

        temp = Double.doubleToLongBits(doubleValue);

        result = prime * result + (int) (temp ^ (temp >>> 32));

        result = prime * result + Float.floatToIntBits(floatValue);

        result = prime * result + Arrays.hashCode(intArray);

        result = prime * result + intValue;

        result = prime * result + (int) (longValue ^ (longValue >>> 32));

        result = prime * result + shortValue;

        result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());

        return result;

    }

}

3.toString方法                                                                  

toString()方法是Object类中定义的另一个重要方法,其格式为:

public String toString() {  

}

方法的返回值是String类型,用于描述当前对象的有关信息。Object类中实现的toString()方法是返回当前对象的类型和内存地址信息,但在一些子类(如String, Date等)中进行了重写,也可以根据需要在用户自定义类型中重写toString()方法,以返回更适用的信息。

除显式调用对象的toString()方法外,在进行String与其它类型数据的连接操作时,会自动调用toString()方法,其中又分为两种情况:

(1)引用类型数据直接调用其toString()方法转换为String类型;

(2)基本类型数据先转换为对应的包装类型,再调用该包装类的toString()方法转换为String类型。

另外,在System.out.println()方法输出引用类型的数据时,也先自动调用了该对象的toString()方法,然后再将返回的字符串输出。

示例如下:

class MyDate{

    private int day,month,year;

    public MyDate(int d, int m, int y){

       day = d;  month = m;  year = y;

    }

class YourDate{

    private int day,month,year;

    public YourDate(int d, int m, int y){

       day = d;   month = m;    year = y;

    }

    public String toString(){

       return  day + "-" + month + "-" + year;   

    }     

}

 public class Test{

    public static void main(String args[]){

       MyDate m = new MyDate(8,8,2008);

       System.out.println(m);

       System.out.println(m.toString());

       YourDate y = new YourDate(8,8,2008);

       System.out.println(y);  

    }  

运行结果:

    cn.javass.java6.test.MyDate@1fb8ee3

cn.javass.java6.test.MyDate@1fb8ee3

8-8-2008 

toString方法被用来将一个对象转换成String表达式。当自动字符串转换发生时,它被用作编译程序的参照。System.out.println()调用下述代码:

      Date now = new Date()

      System.out.println(now)

    将被翻译成:

          System.out.println(now.toString());

对象类定义缺省的toString()方法,它返回类名称和它的引用的地址(通常情况下不是很有用)。许多类覆盖toString()以提供更有用的信息。例如,所有的包装类覆盖toString()以提供它们所代表的值的字符串格式。甚至没有字符串格式的类为了调试目的常常实现toString()来返回对象状态信息。 

二、String                                                 

1.String的直接量(或称为字面量)                                                                  

双引号括起来的字符序列就是String的直接量。实例: “John” 或 "111222333"

字符串赋值,可以在声明时赋值

String color = "blue";

color 是String类型的引用。

“blue” 是String直接量。 

String直接量是存放在栈内存里,所以一旦定义就不能改变值了,只能是让变量指向新的内存空间。比如:

color = “red”; 

如果采用new的方法定义String,那么是需要分配堆内存空间的,如下:

String str = new String(“Hello”);

一共有两个对象,在栈和堆内存中各有一个对象,内容都是“Hello”。 

2.String的常用方法                                                               

2.1  String 方法:length(),charAt(),getBytes()和 getChars()

方法 length()

–返回 String 的长度,是按照char返回的长度

–与数组不同之处: String类不含有 length成员域(属性)

方法charAt(int index)

–获得字符串指定位置的字符

方法getBytes()

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

方法getChars(int srcBegin, int srcEnd,

               char[ ] dst, int dstBegin)

–拷贝字符串的部分字符序列到指定的字符数组的指定位置

注意:对于字符串中的汉字,是按照char来计算的,一个中文汉字占两个字节,也就是说,通过length()得到的是字符串char的长度,而不是字节数,利用这个特点,就可以进行中文判断了。

例如:如何判断一个字符串里面有没有中文呢?如果字符串对应的byte[]和char[]的长度是不一样的,那就说明包含中文,其实还可以顺带计算出有几个汉字。

public class Test{  

    public static void main(String[] args) {

       String str = "这里是Java私塾";

       int charLen = str.length();

       int byteLen = str.getBytes().length;

       if(byteLen > charLen){

           int chineseNum = byteLen - charLen;

           System.out.println("str包含汉字,汉字共"+chineseNum+"个");

       }else{

           System.out.println("str没有包含汉字");

       }

    }

}

运行结果是:

str包含汉字,汉字共5个

2.2 字符串比较 

       –字符类型的数据也是数值类型数据

–比较字符串大小,实际上就是依次比较其所包含的字符的数值大小

–小写字母与大小字母是不相同的,Java是区分大小写 

方法compareTo(String s)

比较两个字符串的大小。返回0表示相等,返回大于0的数表示前面的字符串大于后面的字符串,返回小于0表示前面的字符串小于后面的字符串,区分大小写的。如下:

public class Test{  

       public static void main(String[] args) {

              String str = "这里是JAVA私塾";

              String str2 = "这里是java私塾";

              if(str.compareTo(str2)==0){

                     System.out.println("the str 等于 str2");

              }else if(str.compareTo(str2) > 0){

                     System.out.println("the str 大于 str2");

              }else if(str.compareTo(str2) < 0){

                     System.out.println("the str 小于 str2");

              }

       }

}

运行结果:the str 小于 str2 

方法compareToIgnoreCase(String s):忽略大小写,比较两个字符串的大小。返回0表示相等,返回大于0的数表示前面的字符串大于后面的字符串,返回小于0表示前面的字符串小于后面的字符串。如下:

public class Test{  

       public static void main(String[] args) {

              String str = "这里是JAVA私塾";

              String str2 = "这里是java私塾";

              if(str.compareToIgnoreCase(str2)==0){

                     System.out.println("the str 等于 str2");

              }else if(str.compareToIgnoreCase(str2) > 0){

                     System.out.println("the str 大于 str2");

              }else if(str.compareToIgnoreCase(str2) < 0){

                     System.out.println("the str 小于 str2");

              }

       }

}

运行结果:the str 等于 str2 

方法equals(Object s):比较两个String对象的值是否相等,这个是区分大小写的

方法equalsIgnoreCase(String  s):比较两个String对象的值是否相等,忽略大小写

     String的比较要使用equals()方法,不能使用”==” 

2.3 查找字符串中的字符或子串

    查找字符串(String)中的字符或子串

方法indexOf

四种重载方法 indexOf()

返回第一次找到时的起始下标

如果没有找到,则返回-1

。实例:

String name = "CoolTools";

System.out.println (name.indexOf("oo"));

方法 lastIndexOf

–public int lastIndexOf(int ch, int fromIndex)

–从指定位置往回查找,返回找到的最大的字符下标位置

–即返回满足下面条件的最大值:

(this.charAt(k) == ch) && (k <= fromIndex)

–返回-1: 如果当前字符串不含该字符

方法startsWith(Stirng prefix):测试此字符串是否以指定的前缀开始,如下:

public class Test{ 

    public static void main(String[] args) {

        String str = "这里是Java私塾";

        String str2 = "Java";       

        System.out.println(str.startsWith(str2));

    }

}

运行结果:false

方法startsWith(String prefix,int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始。

public class Test{ 

    public static void main(String[] args) {

        String str = "这里是Java私塾";

        String str2 = "Java";       

        System.out.println(str.startsWith(str2,3));

    }

}

运行结果:true

方法endsWith(String suffix):测试此字符串是否以指定的后缀结束 

2.4 从当前字符串中抽取子字符串 

方法 substring

–substring(int beginIndex)

返回新的字符串: 当前字符串的子串

该子串从指定的位置开始,并一直到当前字符串结束为止

–substring(int beginIndex, int endIndex)

返回新的字符串: 当前字符串的子串

该子串从指定的位置(beginIndex )开始, 到指定的位置(endIndex - 1)结束 

       例如:

            “unhappy”.substring(2) 返回      "happy"

“Harbison“.substring(3)返回      "bison"

“emptiness”.substring(9)返回     "" (空串)

“emptiness“.substring(10)返回     StringIndexOutOfBoundsException 

“hamburger“.substring(4, 8)返回  "urge" 

“smiles“.substring(1, 5)返回  "mile" 

2.5 字符串拼接

方法 concat

–拼接两个字符串,并返回一个新字符串

–源字符串不会被修改

–s1.concat( s2 )

返回字符串s1和s2拼接的结果

实例:

String s1 = "ABC";

String s2 = "XYZ";

s1 = s1.concat(s2);  // 等同于 s1 = s1 + s2; 

2.6 类String的成员方法valueOf 

      静态(static)成员方法valueOf

–将参数的值转化成相应的字符串

–valueOf(char[] data)

返回 new String(data);

–valueOf(char[] data, int offset, int count)

返回 new String(data, offset, count);

–其它valueOf方法的参数的类型: boolean、char、int、long、float、double和Object

对象还可以通过方法toString转化成字符串 

2.7 字符串分解 

方法split(String regex)

          根据给定正则表达式的匹配拆分此字符串,得到拆分好的字符串数组,示例如下:

public class Test{ 

    public static void main(String[] args) {

        String str = "这里,是Java,私塾";

        String tempS[] = str.split(",");//按照“,”对字符串进行拆分

        for(int i=0;i

            System.out.println("tempS["+i+"]==="+tempS[i]);

        }      

    }

}

运行结果:

tempS[0]===这里

tempS[1]===是Java

tempS[2]===私塾

注意

(1)如果用“.”作为分隔的话,必须是如下写法:String.split("\\."),这样才能正确的分隔开,不能用String.split(".");

public class Test{

    public static void main(String[] args) {

       String str = "这里.是Java.私塾";

       String tempS[] = str.split("\\.");//按照"."对字符串进行拆分

       for(int i=0;i

           System.out.println("tempS["+i+"]==="+tempS[i]);

       }     

    }

}

(2)如果用“|”作为分隔的话,必须是如下写法:String.split("\\|"),这样才能正确的分隔开,不能用String.split("|");

因为“.”和“|”都是转义字符,必须得加"\\";

public class Test{

    public static void main(String[] args) {

       String str = "这里|是Java|私塾";

       String tempS[] = str.split("\\|");//按照"|"对字符串进行拆分

       for(int i=0;i

           System.out.println("tempS["+i+"]==="+tempS[i]);

       }     

    }

StringTokenizer

与String的split方法功能类似,也是用来分解字符串,StringTokenizer 是出于兼容性的原因而被保留的遗留类(在新代码中并不鼓励使用它)。建议所有寻求此功能的人使用 Stringsplit 方法或 java.util.regex 包。所以这里就不多说了。

2.8 其它String方法 

方法replace( char1, char2 )

–返回一个新的字符串,它是将s1中的所有char1替换成的结果char2

–源字符串没有发生变化

–如果s1不含char1, 则返回源字符串的引用,即s1

实例:

–“mesquite in your cellar”.replace(‘e’, ‘o’) 结果返回 "mosquito in your collar"

–“JonL”.replace(‘q’, ‘x’)结果返回“JonL” (没有发生变化)

方法toUpperCase

–返回对应的新字符串,所有小写字母都变为大写的,其它的不变

–如果没有字符被修改,则返回源字符串的引用

–类似方法s1.toLowerCase (所有大写字母都变为小写字母)

方法trim( )

–返回新字符串,截去了源字符串最前面和最后面的的空白符

–如果字符串没有被改变,则返回源字符串的引用

方法toString( )

–由于s1本身就是字符串了,所以返回s1本身

–其它引用类型也可以通过方法toString,生成相应的字符串 

方法toCharArray( )

–将字符串转换成字符数组

方法

intern

–返回具有相同内容的字符串的引用

–如果字符串池含有该内容的字符串,则返回字符串池中具有该内容的字符串的引用

–如果字符串池没有字符串的内容与其相同,则在字符串池中创建具有该内容的字符串,再返回新创建的字符串的引用

字符串池   

–组成: 字符串直接量  以及  由方法intern产生的字符串

–字符串池中的字符串s与t : s与t具有相同内容(s.equals(t))当且仅当指向s与t的同一个字符串(s.intern() == t.intern())

–可以采用这个机制加速字符串是否相等的判定 

三、StringBuffer类和StringBuilder                          

前面学到过String类有一个重要的特点,那就是String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。那么对于经常要改变值的字符串应该怎样操作呢?

答案就是使用StringBuffer和StringBuilder类,这两个类功能基本相似,区别主要在于StringBuffer类的方法是多线程安全的(多线程的课程在后面会学习到),而StringBuilder不是线程安全的,相比而言StringBuilder类会略微快一点。 

1.StringBuffer                                                                        

类 String

–字符串(String)对象一旦创建,其内容不能再被修改 (read-only)

类 StringBuffer

–StringBuffer 对象的内容是可以被修改的

–除了字符的长度之外,还有容量的概念

–通过动态改变容量的大小,加速字符管理 

       1.1 StringBuffer的构造方法 

        buf1 = new StringBuffer();

–创建空的StringBuffer对象,初始容量为16字符

buf2 = new StringBuffer( 容量 );

–创建空的StringBuffer对象,指定容量大小

buf3 = new StringBuffer( myString );

–创建含有相应字符序列的StringBuffer对象,容量为myString.length() + 16

–实例:

                StringBuffer b = new StringBuffer("hello");      

1.2 StringBuffer的常用方法

        •方法 length()

–返回 StringBuffer 的长度

•方法 capacity()

–返回StringBuffer 的容量

•方法setLength(int newLength)

–增加或减小 StringBuffer 的长度 

•方法 charAt(int index)

–返回StringBuffer 对象中指定位置的字符

•方法setCharAt(int index, char ch)

–设置 StringBuffer对象中指定位置的字符

•方法 getChars(int srcBegin, int srcEnd,

                                   Char[] dst, int dstBegin)

–将StringBuffer对象中指定的字符子序列,拷贝到指定的字符数组(dst)

•方法 reverse()

–将StringBuffer 对象中的字符序列按逆序方式排列,可用作字符串倒序 

•11种append(…) 方法

–允许数值类型的值添加到StringBuffer对象中 

•10 种 insert 方法

–允许将各种数据插到StringBuffer对象的指定位置

•方法 delete(int start, int end)  和 deleteCharAt(int index)

–允许删除StringBuffer对象中的指定字符 

其中最常用的恐怕就要算append方法和toString方法了,如下示例:

public class Test{  

    public static void main(String[] args) {

       StringBuffer buffer = new StringBuffer();

       buffer.append("这里");

       buffer.append("是");

       buffer.append("Java");

       buffer.append("私塾");

       System.out.println("buffer=="+buffer.toString());

    }

}

运行结果:buffer==这里是Java私塾 

2.StringBuilder                                                              

StringBuilder类是一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

它的功能基本等同于StringBuffer类,就不再赘述了。

public class Test{  

    public static void main(String[] args) {

       StringBuilder builder = new StringBuilder();

       builder.append("这里");

       builder.append("是");

       builder.append("Java");

       builder.append("私塾");

       System.out.println("buffer=="+builder.toString());

    }

}

运行结果:builder==这里是Java私塾 

四、Math                                                    

    Java中的数学(Math)类是final类,不可继承。

其中包含一组静态方法和两个常数  

       1常数 

        PI :double,圆周率

E  :double,自然对数 

    2截取(注意方法的返回类型)

        double ceil(double d)  

-返回不小于d的最小整数

double floor(double d)

-返回不大于d的最大整数

int round(float f)         

-返回四舍五入后的整数

long round(double d) 

-返回四舍五入后的整数  

    3变换(int long float各种类型相似) 

double abs(double d)  

-返回绝对值

double min(double d1, double d2)

    -返回两个值中较小的值

double max(double d1, double d2)

    -返回两个值中较大的值

    4对数

        double log(double d)    

-自然对数

double exp(double d)   

-E的指数 

    5其它

        double sqrt(double d)  

-返回平方根

double random()

    -返回随机数  

还有三角函数的运算等,请参考JDK文档 

示例如下:问题:请问有101条记录,按照每组10条记录进行分组,应该分多少组?

public class Test{     

    public static void main(String[] args) {

        int records = 101;//共有101条记录

        final int GROUP_NUM = 10;//每组10条       

        int groups = (int)Math.ceil(1.0*records/GROUP_NUM);//注意这里的1.0,目的是要把类型变成double型的,而不是int/int,结果还是int,就错了。

        System.out.println("应该分的组数为="+groups);

    }  

}

运行结果:应该分的组数为=11 

五、Java日期操作的类                                              

1.Date类                                                                      

java.util包里面的Date类,是Java里面进行日期操作常用类。Date类用来表示特定的瞬间,精确到毫秒。

1.1 如何初始化Date

构造方法:Date()

          分配 Date 对象并初始化此对象,以表示分配它的时候的当前时间(精确到毫秒)。使用Date类得到当前的时间。 

构造方法:Date(long date)

          分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 格林威治时间)以来的指定毫秒数。

2.2 常用方法

      方法:after(Date when)

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

方法:before(Date when)

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

方法:getTime()

          返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 

2.3 示例:简单的性能测试——监控一段代码运行所需要的时间

public class Test {

    public static void main(String args[]) {

       long d1 = new Date().getTime();//得到此时的时间

       int sum = 0;

       for(int i=1;i<=1000000;i++){//看清楚了,可是一百万次

           sum +=i;

       }

       System.out.println("从1加到1000000的和="+sum);

       long d2 = new Date().getTime();//得到此时的时间

       System.out.println("从1加到1000000所耗费的时间是="+(d2-d1)+"毫秒");

    }

}

运行结果:

从1加到1000000的和=1784293664

从1加到1000000所耗费的时间是=20毫秒

2.DateFormat类和SimpleDateFormat类                                            

在java.text包中的DateFormat类,是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期——>文本)、解析(文本——> 日期)和标准化。

由于DateFormat是个抽象类,SimpleDateFormat类是它的子类,所以下面就主要按照SimpleDateFormat类来讲解。 

2.1 如何初始化

这里只讲述最常用到的构造方法,更多的请参看JDK文档。

构造方法:SimpleDateFormat(String pattern)

          用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat

2.2日期和时间模式

日期和时间格式由日期和时间模式 字符串指定。在日期和时间模式字符串中,未加引号的字母 'A''Z''a''z' 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''" 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在解析时与输入字符串进行匹配。

定义了以下模式字母(所有其他字符 'A''Z''a''z' 都被保留): 

 

字母

日期或时间元素

表示

示例

G

Era

标志符

Text

y

Year

1996;

M

年中的月份

Month

July;

w

年中的周数

Number

27

W

月份中的周数

Number

2

D

年中的天数

Number

189

d

月份中的天数

Number

10

F

月份中的星期

Number

2

E

星期中的天数

Text

Tuesday;

a

Am/pm

标记

Text

H

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

Number

0

k

一天中的小时数(1-24)

Number

24

K

am/pm

中的小时数(0-11)

Number

h

am/pm

中的小时数(1-12)

Number

m

小时中的分钟数

Number

30

s

分钟中的秒数

Number

55

S

毫秒数

Number

978

z

时区

General

time

Z

时区

RFC

822

 

2.3 常用方法

方法:parse(String source)

      从给定字符串的开始解析文本,以生成一个日期

方法:format(Date date)

          将一个 Date 格式化为日期/时间字符串

这里只讲述最常用的方法,更多的方法请参看JDK文档。

2.4 示例

import java.util.*;

import java.text.*;

public class Test {

    public static void main(String args[]) {

       DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");      

       Date d = new Date();

       //把当前时间转换成为我们熟悉的时间表达格式

       String str = df.format(d);      

       System.out.println("当前时间是:"+str);

       //然后再把字符串格式的日期转换成为一个Date类

       try {

           Date d2 = df.parse("2008-08-08 08:08:08 888");

           System.out.println("北京奥运会开幕时间是:"+d2.getTime());

       } catch (ParseException e) {

           e.printStackTrace();

       }     

    }

}

运行结果:

当前时间是:2008-07-22 00:57:45 612

北京奥运会开幕时间是:1218154088888

2.5 说明

虽然JDK文档上说Date的毫秒值,是相对于格林威治时间1970年1月1号的0点,但实际测试,这个Date是跟时区相关的,也就是说在中国测试这个基准值应该是1970年1月1日的8点,不过这个不影响我们的处理,因为只要是同一个基准时间就可以了,而不用关心具体是多少,见下面的示例:

public class Test {

    public static void main(String args[]) {

       DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

      

       Date d = new Date(0L);//把时间设为0,表示到基准时间

       //然后转换成为字符串看看是什么时候

       String str = df.format(d);

      

       System.out.println("基准时间是:"+str);           

    }

}

运行结果:

基准时间是:1970-01-01 08:00:00 000 

3.Calendar类                                                                    

java.util包中的Calendar类是Java里面另外一个常用的日期处理的类。Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEARMONTHDAY_OF_MONTHHOUR日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。

3.1 如何初始化

Calendar类是通过一个静态方法getInstance()来获取Calendar实例。返回的 Calendar 基于当前时间,使用了默认时区和默认语言环境

如下:Calendar c = Calendar.getInstance();

3.2 使用Calendar对日期进行部分析取

Calendar类一个重要的功能就是能够从日期里面按照要求析取出数据,如:年、月、日、星期等等。

方法:get(int field)

          返回给定日历字段的值

示例如下:

Import java.util.Calendar;

public class Test {

    public static void main(String args[]) {

       Calendar c = Calendar.getInstance();

       int year = c.get(Calendar.YEAR);

       int month = c.get(Calendar.MONTH);//注意:month特殊,是从0开始的,也就是0表示1月

       int day = c.get(Calendar.DAY_OF_MONTH);

      

       System.out.println("现在是"+year+"年"+(month+1)+"月"+day+"日");

    }

}

运行结果:

现在是2008年7月22日 

3.3 使用Calendar进行日期运算

这是Calendar另外一个常用的功能,也就是对日期进行加加减减的运算。

    方法:add(int field, int amount)

          根据日历的规则,为给定的日历字段添加或减去指定的时间量 

示例如下:

public class Test {

    public static void main(String args[]) {

       Calendar c = Calendar.getInstance();

       c.add(Calendar.DATE, 12);//当前日期加12天,如果是-12就表示当前日期减去12天

      

       int year = c.get(Calendar.YEAR);

       int month = c.get(Calendar.MONTH);//注意:month特殊,是从0开始的,也就是0表示1月

       int day = c.get(Calendar.DAY_OF_MONTH);

      

       System.out.println("在当前日期加12天是"+year+"年"+(month+1)+"月"+day+"日");

    }

}

运行结果:在当前日期加12天是2008年8月3日 

3.4 为Calendar设置初始值

方法setTime(Date date)

          使用给定的 Date 设置此 Calendar 的当前时间

方法setTimeInMillis(long millis)

      用给定的 long 值设置此 Calendar 的当前时间值

public class Test {

    public static void main(String args[]) {

       Calendar c = Calendar.getInstance();

      

        c.setTimeInMillis(1234567890123L);

      

       int year = c.get(Calendar.YEAR);

       int month = c.get(Calendar.MONTH);//注意:month特殊,是从0开始的,也就是0表示1月

       int day = c.get(Calendar.DAY_OF_MONTH);

      

       System.out.println("设置的时间是"+year+"年"+(month+1)+"月"+day+"日");

    }

}

运行结果:设置的时间是2009年2月14日 

六、System                                                 

1.系统属性 

    (1)系统属性(System Properties)是Java提供的另外一种运行时给程序提供参数的方法。属性(Property)是名字和值之间的映射,这里名字和值都只能是String。

(2) Java有一个类Properties描述了名字和值之间的映射。

System.getProperties方法返回系统的Properties对象。

System.getProperty(String propertyName)方法返回对应名字属性的值。

System.getProperty(String name,String value)重载方法当没有name指定的属性时,返回value指定的缺省值。

(3)每一个JVM提供了一组缺省属性,可以通过System.getProperties方法的帮助文档了解到。基本类型的包装类中包含静态方法,用于将属性值转换成对应类型的值。如Boolean.getBoolean(String); Long.getLong(String)。String参数这里是属性名字,如果属性不存在,那么返回false或null。

(4) Properties类的对象包含两个主要方法:

getProperty(String Name)和getProperty(String Name, String value)方法返回对应名字属性的值。

properNames()列举系统的一组对象名字,进而可以列举系统的属性值。

例如:

import java.util.Properties;

import java.util.Enumeration;

public class TestProperties{

  public static void main(String args[]){

    Properties props = System.getProperties();

    Enumeration prop_names = props.propertyNames();//这是个早期的集合类

    while(prop_names.hasMoreElements()){

      String prop_name = (String) prop_names.nextElement();

      String property = props.getProperty(prop_name);

      System.out.println("Property '" + prop_name + "' is '" +property+"'");

    }

  }

prop_names是Enumeration是枚举类型的对象,包含一组属性名,允许程序循环列出。 hasMoreElements方法检测是否还有其它元素, nextElement返回程序的下一个元素。

运行:java -DMyProp=theValue TestProperties

注意:严格的格式 –D后没有空格

运行结果:很多的Java系统级属性,下面列出部分,太多了,你可以把程序运行一下:

Property 'java.runtime.name' is 'Java(TM) SE Runtime Environment'

Property 'sun.boot.library.path' is 'c:\jdk1.6.0_01\jre\bin'

Property 'java.vm.version' is '1.6.0_01-b06'

Property 'java.vm.vendor' is 'Sun Microsystems Inc.'

Property 'java.vendor.url' is 'http://java.sun.com/'

。。。。。。 

2.控制台输入输出

许多应用程序要与用户进行文本I/O(输入/输出)交互,标准输入是键盘;标准输出是终端窗口。Java SDK支持控制台I/O使用三个java.lang.System类中定义的变量:

System.out是一个PrintStream对象,初始引用启动Java的终端窗口。

Syste.in是一个InputStream对象,初始指向用户键盘。

System.err是一个PrintStream对象,初始引用启动Java的终端窗口。

这三个对象都可以重新定向(如文件):System.setOut\setIn\setErr。

往标准输出写东西使用PrintStream对象的println或print方法。print方法输出参数;但println方法输出参数并追加一个换行符。

println或print方法都对原始类型进行重载,同时还重载了char[]和Object,String。参数是Object时,调用参数的toString方法。

输出例子

public class Test {

    public static void main(String args[]) {

       char c[] = { 'a', 'b', 'c' };

       System.out.println(c);

    }

}

运行结果:abc 

输入例子:

import java.io.*;

public class Test {

    public static void main(String args[]) {

       String s = "";

       InputStreamReader ir = new InputStreamReader(System.in);

       BufferedReader in = new BufferedReader(ir);

       System.out.println("Ctrl+z to exit");

       try {

           s = in.readLine();

           while (s != null) {

              System.out.println("Read:" + s);

              s = in.readLine();

           }

           in.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

    }

}

运行的时候从控制台输入数据,然后回车,就看到具体读入的值的输出了。

这里先看看,涉及到后面要学习的I/O的知识。

3.格式化输出printf

从JDK5.0开始,Java里面提供了C风格的格式化输出方法 —— printf,

比如输出一个加法算式,JDK5.0版本以前的写法是:

public class Test { 

    public static void main(String[] args) {

       int x = 5;

       int y = 7;

       int nSum = x + y;

      System.out.println(x + " + " + y + " = " + nSum);

    }

}

运行结果:5 + 7 = 12

而在JDK5.0以后版本中可以写为:
public class Test { 

    public static void main(String[] args) {

       int x = 5;

       int y = 7;

       int nSum = x + y;

       System.out.printf("%d + %d = %d\n", x, y, nSum);

    }

以上两种写法的输出结构是一样的,即“5 + 7 = 12”。

这种改变不仅仅是形式上的,printf还可以提供更为灵活、强大的输出功能,比如限定按照两位整数的形式输出,可以写为:

public class Test { 

    public static void main(String[] args) {

       int x = 5;

       int y = 7;

       int nSum = x + y;

       System.out.printf("d + d = d\n", x, y, nSum);

    }

}

运行输出结果将是“05 + 07 = 12”。 

其实这个功能在Java里面并没有什么大用,具体的printf格式化字符串格式请参见JDK文档中的具体说明。 

4.属性文件

后缀为“.properties”的文件在Java中被称为属性文件,是Java中历史悠久,使用频繁的配置文件(或者叫资源文件)格式。

属性文件的基本格式为:key=value

Java提供现成的API来读取properties文件的内容,并进行解析,所以使用非常方便。运行时候只要把“.properties”文件放到classpath下就可以了。

示例如下:假设有一个test.properties如下:

#表示注释

test1=This is Java properties

#默认的properties是不认中文的,需要编码(后面会学到),所以这里用英文测试

test2=Welcome to Java World

Java读取

Java有好几种方法来读取properties文件,这里演示其中一种:

import java.io.*;

public class Test {

    public static void main(String args[]) {

       try {

           String name = "test.properties";

           InputStream in = new BufferedInputStream(new FileInputStream(name));

           Properties p = new Properties();

           p.load(in);

           System.out.println("test1的值=="+p.getProperty("test1"));

           System.out.println("test2的值=="+p.getProperty("test2"));

       } catch (Exception err) {

           err.printStackTrace();

       }

    }

}

运行结果:

    test1的值==This is Java properties

test2的值==Welcome to Java World

作业                                 

1.在MyPoint 类中增加equals方法(覆盖Object的equals方法),以比较两个MyPoint对象的内容是否相等。

2.编写一个截取字符串的方法,输入为一个字符串和字节数,输出为按字节截取的字符串。但是要保证汉字不被截半个,如"我ABC"4,应该截为"我AB",输入"我ABC汉DEF",6,应该输出为"我ABC"而不是"我ABC+汉的半个"。 

3:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。请编写一个方法来实现上述加密算法。

5.定义一个长度为10的一维字符串数组,在每一个元素存放一个单词;然后运行时从命令行输入一个单词,程序判断数组是否包含有这个单词,包含这个单词就打印出“Yes”,不包含就打印出“No”。

8:统计字符串中英文字母、空格、数字和其它字符的个数。

4.一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和。 (不使用数学公式,要求用递归)

5.输出一个字符数组中的所有字符的所有组合。比如有字符集str={A,B,C}。应输出:

A  B  C  AB  AC  BA  BC  CA  CB  ABC  ACB  BAC  BCA  CAB  CBA

6.已知两个对像String s1,String s2,已用ASC码排序好了,编写程序将两个String 合并,得到的结果。例如:s1="abc" s2="abc" 得s="aabbcc";结果也是排序的

7.两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。

8.企业发放的奖金根据利润提成。利润低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%,高于100万元时,超过100万元的部分按1%提成,请编写程序,输入当月利润,求应发放奖金总数?

9.老伯伯要带鱼、狗、猫过河到对岸.,有一条船,只能坐一个人,老伯每次只能带一样动物过河,当老伯不在的时侯狗会咬猫,猫会吃鱼.,请问怎么顺序过河呢?要求:编写程序,由程序来推出过河的顺序

Java私塾跟我学系列——JAVA  网址:http://www.javass.cn  电话:010-68434236

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26660100/viewspace-715630/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/26660100/viewspace-715630/

你可能感兴趣的:(Java私塾跟我学系列——JAVA篇 第六章 常见类的使用)