第14章 java.lang研究
本章讨论那些由java.lang定义的类和接口。正如你所知道的那样,java.lang被自动导入所有的程序。它所包含的类和接口对所有实际的Java程序都是必要的。它是Java最广泛使用的包。
java.lang包括了下面这些类:
Boolean | Long | StrictMath (Java 2,1.3) |
Byte | Math | String |
Character | Number | StringBuffer |
Class | Object | System |
ClassLoader | Package (Java 2) | Thread |
Compiler | Process | >ThreadGroup |
Double | Runtime | ThreadLocal (Java 2) |
Float | >RuntimePermission (Java 2) | Throwable |
>InheritableThreadLocal (Java 2) | SecurityManager | Void |
>Integer | >Short | > |
另外还有两个由Character定义的类:Character.Subset和Character.UnicodeBlock,它们是在Java 2中新增加的。
java.lang也定义了如下的接口:
· Cloneable
· Comparable
· Runnable
其中Comparable接口是在Java 2中新增加的。
java.lang中的几个类包含了过时的方法,其中的大多数可以追溯到Java 1.0。在Java2中仍然提供了这些方法,用于支持逐渐减少的老程序,而这些方法在新程序中不被推荐使用。大多数的过时方法出现在Java 2之前,因此在这里不讨论这些方法。而在Java 2中出现的那些过时的方法将被提及。
Java 2也在java.lang包中增加了几个新的类和方法,这些新类和方法被说明如下。
14.1 简单类型包装器
在本书的第1部分,我们提到因为性能的原因,Java使用简单的类型,例如整型(int)和字符(char)。这些数据类型不是对象层次结构的组成部分。它们通过值传递给方法而不能直接通过引用传递。而且,也没有办法使两种方法对整型(int)引用同一实例(same instance)。有时需要对这些简单的类型建立对象表达式。例如在第15章中讨论的仅仅处理对象的枚举类;如果要将简单类型存储到这些类中的一个,需要在类中包装简单类型。为了满足这种需要,Java提供了与每一个简单类型相应的类。本质上,这些类在类中包装(wrap)简单类型。因此,它们通常被称作类型包装器(wrappers)。
抽象类Number定义了一个由包装数字类型字节型(byte),短整型(short),整型(int),长整型(long),浮点型(float)和双精度型(double)的类实现的超类。Number有返回上面不同数字格式的对象值的抽象方法。也就是,doubleValue( )方法返回双精度(double)值,floatValue( )方法返回浮点(float)值等。这些方法如下:
byte byteValue( )
double doubleValue( )
float floatValue( )
int intValue( )
long longValue( )
short shortValue( )
这些方法的返回值可以被舍入。
Number有6个具体的子类包含了6种数字类型的显式值:双精度型(Double),浮点型(Float),字节型(Byte),短整型(Short),整型(Integer)和长整型(Long)。
14.1.2 Double和Float
双精度(Double)和浮点(Float)分别是对类型double和类型float的浮点值的包装器。浮点(Float)构造函数如下所示:
Float(double num)
Float(float num)
Float(String str) 引发NumberFormatException异常
正如你所看到的,浮点(Float)对象可以由类型float或类型double的值创建。它们也能由浮点数的字符串表达式创建。
双精度(Double)构造函数如下:
Double(double num)
Double(String str) 引发NumberFormatException异常
双精度(Double)对象可以被双精度(double)值或包含了浮点值的字符串创建。
由浮点(Float)定义的方法在表14-1中列出。由双精度(Double)定义的方法在表14-2中列出。浮点(Float)和双精度(Double)都定义了下面的常数:
MAX_VALUE | 最大正值 |
MIN_VALUE | 最小正值 |
NaN | 非数字 |
POSITIVE_INFINITY | 正无穷 |
NEGATIVE_INFINITY | 负无穷 |
TYPE | 浮点(float)或双精度(double)的类(Class)对象 |
表14-1 由Float定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象的值(字节型) |
int compareTo(Float f) | 将调用对象的数值与f中的数值进行比较,如果两者相等,返回0。如果调用对象的值小于f的值,则返回负值。如果调用对象的值大于f的值,则返回正值(在Java 2中新增加的) |
int compareTo(object obj) | 当obj是类Float中的对象时,该方法与compareTo(Float)的功能相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
double doubleValue() | 返回调用对象的值(双精度型) |
boolean equals(Object FloatObj) | 如果float调用对象与FloatObj相等,则返回true。否则返回false |
static int float ToIntBits(float num) | 返回与num相应的与IEEE兼容的单精度位模式 |
Float floatValue() | 返回调用对象的值(浮点型) |
int hashCode() | 返回调用对象的散列值 |
static float intBitsToFloat(int num) | 返回由num指定的,与IEEE兼容的单精度位模式的等价浮点(float)值 |
int intValue() | 返回整型(int)形式的调用对象值 |
boolean isInfinite() | 如果调用对象包含有无穷大值,则返回true。否则返回false |
static boolean isInfinite(float num) | 如果num指定了一个无穷大值,则返回true。否则返回false |
boolean isNaN() | 如果调用对象中包含了非数字值,则返回true。否则返回false |
static boolean isNaN(float num) | 如果num指定了一个非数字值,则返回true。否则返回false |
long longValue() | 返回调用对象的值(长整型) |
static float parseFloat(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价浮点值(在Java 2中新增加的) |
short shortValue() | 返回调用对象值(短整型) |
String toString() | 返回调用对象的等价字符串形式 |
static String to String(float num) | 返回由num指定的值的等价字符串 |
static Float valueOf(String str) throws NumberForamtException | 返回包含了由str中的字符串指定的值的float对象 |
表14-2 由Double定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象的值(字节型) |
int compareTo(Double d) | 将调用对象的值与d的数值进行比较。如果这两个值相等,则返回0。如果调用对象的数值小于d的数值,则返回负值。如果调用对象的数值大于d的数值,则返回正值(在Java 2中新增加的) |
Int compareTo(Object obj) | 如果obj属于类Double,其操作与compareTo(Double)相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
static long doubleToLongBits(double num) | 返回与num相应的与IEEE兼容的双精度位模式 |
double doubleValue() | 返回调用对象的值(双精度) |
boolean equals(Object DoubleObj) | 如果double调用对象与DoubleObj相等,则返回true。否则,返回false |
float floatValue() | 返回调用对象的值(浮点型) |
int hashcode() | 返回调用对象的散列码 |
int intValue() | 返回调用对象的值(整型) |
boolean isInfinite() | 如果调用对象包含了一个无穷大值,则返回true。否则,返回false |
static boolean isInfinite(double num) | 如果num指定了一个无穷大值,则返回true。否则,返回false |
boolean is NaN() | 如果调用对象包含了一个非数字值,则返回true。否则,返回false |
static boolean isNaN(double num) | 如果num指定了一个非数字值,则返回true。否则,返回false |
static double longBitsToDouble(long num) | 返回由num指定的,与IEEE兼容的双精度位模式的双精度(double)等价值 |
long longValue() | 返回调用对象的值(长整型) |
static double parseDouble(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价双精度(double)形式(在Java 2中新增加的) |
short shortValue() | 返回调用对象的值(短整型) |
String toString() | 返回调用对象的等价字符串形式 |
Static String toString(double num) | 返回由num指定的值的等价字符串形式 |
Static Double valueOf(String str) throws NumberFormatException | 返回包含了由str中的字符串指定的值的double对象 |
在下面的例子中创建两个double对象——一个通过使用双精度(double)值实现,另一个通过传递一个可以被解析为双精度(double)的字符串来实现。
class DoubleDemo {
public static void main(String args[]) {
Double d1 = new Double(3.14159);
Double d2 = new Double("314159E-5");
System.out.println(d1 + " = " + d2 + " -> " + d1.equals(d2));
}
}
正如从下面的输出中可以看到的那样,如同通过equals( )方法返回true,两种构造函数创建相同的双精度(double)实例。
3.14159 = 3.14159 –> true
理解isInfinite( )和isNaN( )
浮点(Float)和双精度(Double)提供了isInfinite( )和isNaN( )方法,这些方法会有助于操作两个特殊的双精度(double)和浮点(float)值,这些方法检验两个由IEEE浮点规范定义的独特的值:无穷和NaN(非具体数字)。当被检验的值为无穷大或无穷小值时,isInfinite( )方法返回true。当被检验值为非数字时,isNaN( )方法返回true。
在下面的例子中构造了两个Double对象;一个是无穷,另一个是非数字:
// Demonstrate isInfinite() and isNaN()
class InfNaN {
public static void main(String args[]) {
Double d1 = new Double(1/0.);
Double d2 = new Double(0/0.);
System.out.println(d1 + ": " + d1.isInfinite() + ", " + d1.isNaN());
System.out.println(d2 + ": " + d2.isInfinite() + ", " + d2.isNaN());
}
}
程序运行产生如下的输出:
Infinity: true, false
NaN: false, true
14.1.3 Byte, Short, Integer 和 Long
Byte,Short,Integer,和Long类分别是字节型(byte),短整型(short),整型(int)和长整型(long)整数类型的包装器。它们的构造函数如下:
Byte(byte num)
Byte(String str) 引发一个NumberFormatException异常
Short(short num)
Short(String str) 引发一个NumberFormatException异常
Integer(int num)
Integer(String str) 引发一个NumberFormatException异常
Long(long num)
Long(String str) 引发一个NumberFormatException异常
正如你能看到的,这些对象可由数值或含有有效整数值的字符串创建。
由这些类定义的方法列在表14-3到表14-6中。正如你能看到的,它们定义方法以便从字符串解析整数和将字符串转换为整数。为方便起见,这些方法提供的变量可以用来指定radix,也称为基数。通常二进制(binary)的基数是2,八进制(octal)的基数是8,十进制(decimal)的基数是10,而十六进制(hexadecimal)的基数为16。
表14-3 由Byte定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象值(字节型) |
int compareTo(Byte b) | 将调用对象的数值与b的数值进行比较。如果这两个数值相等,则返回0。如果调用对象的数值小于b的数值,则返回负值。如果调用对象的数值大于b的数值,则返回正值(在Java 2中新增加的) |
int compareTo(Object obj) | 如果obj属于类Byte,其操作与compareTo(Byte)相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
static Byte decode(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定的值的Byte对象 |
double doubleValue() | 返回调用对象值(双精度度型) |
boolean equals(Object ByteObj) | 如果Byte调用对象与ByteObj相等,则返回true。否则,返回false |
float floatValue() | 返回调用对象值(浮点型) |
int hashCode() | 返回调用对象的散列码 |
int intValue() | 返回调用对象值(整型) |
long longValue() | 返回调用对象值(长整型) |
static byte parseByte(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价字节(byte)形式 |
static byte parseByte(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回包含在由str指定的字符串中的数字的等价字节 |
short shortValue() | 返回调用对象值(短整型) |
String toString() | 返回一个包含了调用对象的等价十进制形式的字符串 |
static String toString(byte num) | 返回一个包含了num的等价十进制形式的字符串 |
static Byte valueOf(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定的值的Byte对象 |
static Byte valueOf(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回一个包含了由str中的字符串指定的值的Byte对象 |
表14-4 由Short定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象值(字节型) |
int compareTo(Short s) | 将调用对象的数值和s的数值进行比较。如果这两个值相等,则返回0。如果调用对象的数值小于s的数值,则返回负值 如果调用对象的数值大于s的数值,则返回正值(在Java 2中新增加的) |
int compareTo(Object obj) | 如果obj属于类Short,其操作与compareTo(Short)相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
static Short decode(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定值的Short对象 |
double doubleValue() | 返回调用对象值(双精度型) |
boolean equals(Object ShortObj) | 如果整型(Interger)调用对象与ShortObj相等,则返回true。否则,返回false |
float floatValue() | 返回调用对象值(浮点值) |
int hashCode() | 返回调用对象的散列码 |
int intValue() | 返回调用对象值(整型) |
long longValue() | 返回调用对象值(长整型) |
static short parseShort(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价短整型(Short)数 |
static short parseShort(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回包含在由str指定的字符串中的数字的等价短整型(Short)数 |
short shortValue() | 返回调用对象值(短整型) |
String toString() | 返回一个包含了调用对象的等价十进制形式的字符串 |
static String to String(short num) | 返回一个包含了num的等价十进制形式的字符串 |
static Shortvalue Of(Stringstr)throws NumberFormatException | 以10为基数,返回一个包含了由str中的字符串指定的值的Short对象 |
static Short valueOf(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回一个包含了由str中的字符串指定的值的Short对象 |
表14-5 由Integer定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象值(字节型) |
int compareTo(Integer i) | 将调用对象的数值与i的数值进行比较。如果这两个值相等,则返回0。如果调用对象的数值小于i的数值,则返回负值。如果调用对象的数值大于i的数值,则返回正值(在Java 2中新增加的) |
续表
方法 | 描述 |
int compareTo(Object obj) | 如果obj属于类Integer,其操作与compareTo(Integer)相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
static Integer decode(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定值的Integer对象 |
double doubleValue() | 返回调用对象值(双精度型) |
boolean equals(Object IntegerObj) | 如果调用Interger对象与IntegerObj相等,则返回true。否则,返回false |
float floatValue()static Integer getInteger (String propertyName) | 返回调用对象值(浮点型) 返回与由propertyname指定的环境属性相关联的值,调用失败返回null |
static Integer getInteger (String propertyName,int default) | 返回与由propertyname指定的环境属性相关联的值,调用失败返回default值 |
static Integer getInteger (String propertyName,Integer default) | 返回与由propertyname指定的环境属性相关联的值,调用失败返回default值 |
int hashCode() | 返回调用对象的散列码 |
int intValue() | 返回调用对象值(整型) |
long longValue() | 返回调用对象值(长整型) |
static int parseInt(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价整数(integer)值 |
static int parseInt(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回包含在由str指定的字符串中的数字的等价整数值 |
short shortValue() | 返回调用对象值(短整型) |
static String toBinaryString(int num) | 返回一个包含了num的等价二进制形式的字符串 |
static String toHexString(int num) | 返回一个包含了num的等价十六进制形式的字符串 |
static String toOctalString(int num) | 返回一个包含了num的等价八进制形式的字符串 |
String toString() | 返回一个包含了调用对象的等价十进制形式的字符串 |
static String toString(int num) | 返回一个包含了num的等价十进制形式的字符串 |
static String toString(int num,int radix) | 以指定的基数(radix)为底,返回一个包含了num的等价十进制形式的字符串 |
static Integer valueOf(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定的值的Integer对象 |
static Integer valueOf(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回一个包含了由str中的字符串指定的值的Integer对象 |
表14-6 由Long定义的方法
方法 | 描述 |
byte byteValue() | 返回调用对象值(字节型) |
int compareTo(Long l) | 将调用对象的数值和l的数值进行比较,如果这两个值相等,则返回0。如果调用对象的数值小于l的数值,则返回负值。如果调用对象的数值大于l的数值,则返回正值(在Java 2中新增加的) |
int compareTo(Object obj) | 如果obj属于类long,其操作与compareTo(Long)相同。否则,引发一个ClassCastException异常(在Java 2中新增加的) |
static Long decode(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定的值的Long对象 |
double doubleValue() | 返回调用对象值(双精度型) |
boolean equals(Object LongObj) | 如果调用Long对象与LongObj相等,则返回true。否则,返回false |
float floatValue() | 返回调用对象值(浮点型) |
static Long getLong(String propertyname) | 返回与由propertyname指定的环境属性相关联的值,调用失败则返回null |
static Long getLong(String propertyname, long default) | 返回与由propertyname指定的环境属性相关联的值,调用失败则返回default的值 |
static long getLong(String propertyname, Long default) | 返回与由propertyname指定的环境属性相关联的值,调用失败则返回default的值 |
int hashcode() | 返回调用对象的散列码 |
int intValue() | 返回调用对象值(整型) |
long longValue() | 返回调用对象值(长整型) |
static long parseLong(String str) throws NumberFormatException | 以10为基数,返回包含在由str指定的字符串中的数字的等价长整型(Long)数 |
static long parseLong(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回包含在由str指定的字符串中的数字的等价长整型(Long)数 |
short shortValue() | 返回调用对象值(短整型) |
static String toBinaryString(long num) | 返回一个包含了num的等价二进制形式的字符串 |
static String toHexString(long num) | 返回一个包含了num的等价十六进制形式的字符串 |
static String toOctalString(long num) | 返回一个包含了num的等价八进制形式的字符串 |
String toString() | 返回一个包含了调用对象的等价十进制形式的字符串 |
static String toString(long num) | 返回一个包含了num的等价十进制形式的字符串 |
static String toString(long num,int radix) | 以指定的基数(radix)为底,返回一个包含了num的等价十进制形式的字符串 |
static Long valueOf(String str) throws NumberFormatException | 返回一个包含了由str中的字符串指定的值的Long对象 |
续表
方法 | 描述 |
static Long valueOf(String str,int radix) throws NumberFormatException | 以指定的基数(radix)为底,返回一个包含了由str中的字符串指定的值的Long对象 |
定义下面的常数:
MIN_VALUE | 最小值 |
MAX_VALUE | 最大值 |
TYPE | 字节(Byte),短整型(short),整型(int)或长整型(long)的类(Class)对象 |
数字和字符串的转换
程序设计中一个最常见的任务是将一个数字的字符串表达式转换成内部的二进制格式。幸运的是Java提供了一个方便的方法去完成这项任务。Byte,Short,Integer和Long类分别提供了parseByte( ),parseShort( ),parseInt( )和parseLong( )方法。这些方法返回与调用它们的数值字符串相应的字节(byte),短整型(short),整型(int)和长整型(long)值(在Float和Double类中也有相似的方法)。
下面的程序说明了parseInt( )方法。该程序完成对用户输入的一系列整数的求和。在程序中通过使用readLine( )方法读取整数,使用parseInt( )方法将这些字符串转换成与之相应的整型(int)值。
/* This program sums a list of numbers entered
by the user. It converts the string representation
of each number into an int using parseInt().
*/
import java.io.*;
class ParseDemo {
public static void main(String args[])
throws IOException
{
// create a BufferedReader using System.in
BufferedReader br = new
BufferedReader(new InputStreamReader(System.in));
String str;
int i;
int sum=0;
System.out.println("Enter numbers, 0 to quit.");
do {
str = br.readLine();
try {
i = Integer.parseInt(str);
} catch(NumberFormatException e) {
System.out.println("Invalid format");
i = 0;
}
sum += i;
System.out.println("Current sum is: " + sum);
} while(i != 0);
}
}
为了将一个整数转换为一个十进制的字符串,可以使用在Byte,Short,Integer或Long类中定义的toString( )方法。Integer和Long类还同时提供了toBinaryString( ),toHexString( )和toOctalString( )方法,可以分别将一个值转换成二进制,十六进制和八进制字符串。
下面的程序说明了向二进制,十六进制和八进制的转换:
/* Convert an integer into binary, hexadecimal,
and octal.
*/
class StringConversions {
public static void main(String args[]) {
int num = 19648;
System.out.println(num + " in binary: " +
Integer.toBinaryString(num));
System.out.println(num + " in octal: " +
Integer.toOctalString(num));
System.out.println(num + " in hexadecimal: " +
Integer.toHexString(num));
}
}
程序的输出结果如下所示:
19648 in binary: 100110011000000
19648 in octal: 46300
19648 in hexadecimal: 4cc0
字符(Character)是围绕字符型(char)的一个简单的包装器。字符(Character)的构造函数如下:
Character(char ch)
这里ch指定了被创建的字符(Character)对象所包装的字符。
调用如下的charValue( )方法可以获得包含在字符(Character)对象中的字符型(char)值。
char charValue( )
调用的结果返回字符。
字符(Character)类定义了几个常数,包括下面这些:
MAX_RADIX | 最大基数 |
MIN_RADIX | 最小基数 |
MAX_VALUE | 最大字符值 |
MIN_VALUE | 最小字符值 |
TYPE | 字符型(char)的类(Class)对象 |
字符(Character)包括了几个静态方法,这些方法完成将字符分类并改变它们的大小写。这些方法在表14-7中列出。下面的例子说明了这些方法。
// Demonstrate several Is... methods.
class IsDemo {
public static void main(String args[]) {
char a[] = {'a', 'b', '5', '?', 'A', ' '};
for(int i=0; i<a.length; i++) {
if(Character.isDigit(a[i]))
System.out.println(a[i] + " is a digit.");
if(Character.isLetter(a[i]))
System.out.println(a[i] + " is a letter.");
if(Character.isWhitespace(a[i]))
System.out.println(a[i] + " is whitespace.");
if(Character.isUpperCase(a[i]))
System.out.println(a[i] + " is uppercase.");
if(Character.isLowerCase(a[i]))
System.out.println(a[i] + " is lowercase.");
}
}
}
程序的输出结果如下所示:
a is a letter.
a is lowercase.
b is a letter.
b is lowercase.
5 is a digit.
A is a letter.
A is uppercase.
is whitespace.
表14-7 各种字符(Character)方法
方法 | 描述 |
static boolean isDefined(char ch) | 如果ch是由Unicode定义的,则返回true,否则,返回false |
static boolean isDigit(char ch) | 如果ch是一个数字,则返回true,否则,返回false |
static boolean isIdentifierIgnorable(char ch) | 如果在一个标识符中ch应被忽略,则返回true,否则,返回false |
static boolean isISOControl(char ch) | 如果ch是一个ISO控制字符,则返回true,否则,返回false |
续表
方法 | 描述 |
static boolean isJavaIdentifierPart(char ch) | 如果ch被做为Java标识符的一部分(除了第一个字符),则返回true。否则,返回false |
static boolean isJavaIdentifierStart(char ch) | 如果ch被做为Java标识符的首字符,则返回true。否则返回false |
static boolean isLetter(char ch) | 如果ch是一个字母,则返回true。否则返回false |
static boolean isLetterOrDigit(char ch) | 如果ch是一个字母或一个数字,则返回true。否则返回false |
static boolean isLowerCase(char ch) | 当ch是小写字母时,返回true。否则返回false |
static boolean isSpaceChar(char ch) | 如果ch是Unicode编码的空格字符,则返回true。否则返回false |
static boolean isTitleCase(char ch) | 如果ch是Unicode编码的标题字符,则返回true。否则返回false |
static boolean isUnicodeIdentifierPart (char ch) | 如果ch被做为Unicode编码标识符的一部分(除了第一个字符),则返回true。否则,返回false |
static boolean isUnicodeIdentifierStart (char ch) | 如果ch被做为一个Unicode标识符的首字符,则返回true。否则返回false |
static boolean isUpperCase(char ch) | 如果ch是一个大写字母,则返回true。否则返回false |
static boolean isWhitespace(char ch) | 如果ch是一个空白符,则返回true。否则,返回false |
static char toLowerCase(char ch) | 返回ch的小写等价形式 |
static char toTitleCase(char ch) | 返回ch的标题等价形式 |
static char toUpperCase(char ch) | 返回ch的大写等价形式 |
字符(Character)定义了如下形式的forDigit( )和digit( )方法:
static char forDigit(int num, int radix)
static int digit(char digit, int radix)
forDigit( )方法返回与num的值关联的数字字符。而转换的基数由radix指定。digit( )方法按照给定的基数,返回与指定字符(该字符可能是一个数字)相关联的整数值。
由Character类定义的另一个方法是compareTo( ),该方法具有如下的两种形式:
int compareTo(Character c)
int compareTo(Object obj)
第一种形式当调用对象与c具有相同值时返回0。当调用对象具有比c小的值时返回一个负值。否则它将返回一个正值。在第二种形式中,当obj是对Character类的一个引用时,其功能与第一种形式一样。否则它将引发一个ClassCastException异常。这些方法是在Java 2中新增加的。
Character类还定义了equals( )和hashCode( )方法。
另两个与字符有关的类是Character.Subset和Character.UnicodeBlock,其中Character.Subset类用于描述Unicode编码的一个子集,而Character.UnicodeBlock类中包含了Unicode 2.0编码的字符块。
Boolean是一个围绕布尔(boolean)值的非常细小的包装器,主要用在通过引用传递布尔(boolean)变量的场合。它包含了常数TRUE和FALSE,这些常数定义了布尔(Boolean)对象的真与假。Boolean也定义了TYPE域,它是boolean的Class对象。在Boolean中定义了如下的构造函数:
Boolean(boolean boolValue)
Boolean(String boolString)
在第一种形式中,boolValue要么是true,要么是false。在第二种形式中,如果在boolString中包含了字符串“true”(无论是大写形式还是小写形式),则新的布尔(Boolean)对象将为真,否则为假。
Boolean定义了如表14-8中列出的方法。
表14-8 由Boolean定义的方法
方法 | 描述 |
boolean booleanValue( ) | 返回布尔(boolean)等价形式 |
boolean equals(Object boolObj) | 如果调用对象与boolObj相等,则返回true。否则返回false |
static boolean getBoolean(String propertyName) | 如果由propertyName指定的系统属性为true,则返回true。否则返回false |
int hashCode( ) | 返回调用对象的散列码 |
String toString( ) | 返回调用对象的字符串等价形式 |
static Boolean valueOf(String boolString) | 如果在boolString中包含了“true”(以大写或小写形式),则返回true。否则返回false |
Void类有一个TYPE域,该域保存对类型void的Class对象的引用。这样做将不创建类的实例。
抽象类Process封装了一个进程(process)——也就是说一个正在执行的程序。它主要被当作由Runtime类中的exec( )方法所创建的对象的类型的超类。Runtime类将在下面介绍。在抽象类Process中,包含了如下表14-9中列出的抽象方法。
表14-9 由Process定义的抽象方法
方法 | 描述 |
void destroy( ) | 中断进程 |
int exitValue( ) | 返回一个从子进程获得的退出码 |
InputStream getErrorStream( ) | 返回一个从进程的err输出流中读输入的输入流 |
InputStream getInputStream( ) | 返回一个从进程的out输出流中读输入的输入流 |
OutputStream getOutputStream( ) | 返回一个从进程的in输入流中写输出的输出流 |
Int waitFor( ) throws InterruptedException | 返回由进程返回的退出码。这个方法直到调用它的进程中止,才会返回 |
Runtime类封装了运行时环境。一般不实例化一个Runtime对象。但是可以通过调用静态方法Runtime.getRuntime( )而获得对当前Runtime对象的引用。一旦获得了对当前对象的引用,就可以调用几个控制Java虚拟机的状态和行为的方法。小应用程序(Applets)和其他不可信赖的编码由于没有引起一个安全异常(SecurityException)而不能调用任何的Runtime方法。
表14-10给出了由Runtime定义的方法。Java 2中不赞成使用方法runFinalizersOnExit( )。这种方法是在Java 1.1中增加的,但被认为是一种不稳定的方法。
表14-10 由Runtime定义的常用方法
方法 | 描述 |
void addShutdownHook(Thread thrd) | 当Java虚拟机终止时,寄存器thrd作为线程而运行 |
Process exec(String progName) throws IOException | 将由progName指定的程序作为独立的进程来执行。返回描述新进程的类型Process的对象 |
Process exec(String progName, String environment[ ]) throws IOException | 将由progName指定的程序作为独立的进程来执行。该独立进程的环境由environment指定。返回描述新进程的类型Process的对象 |
Process exec(String comLineArray[ ], String environment[ ]) throws IOException | 将由comLineArray中的字符串指定的命令行作为独立的进程来执行。运行环境由environment指定。返回描述新进程的类型Process的对象 |
void exit(int exitCode) | 暂停执行并且向父进程返回exitCode的值,按照约定,0表示正常中止,所有的其他值表示有某种形式的错误 |
long freeMemory( ) | 返回Java运行系统可以利用的空闲内存的大概字节数 |
void gc( ) | 初始化垃圾回收站 |
static Runtime getRuntime( ) | 返回当前的Runtime对象 |
续表
方法 | 描述 |
void halt(int code) | 立即终止Java虚拟机,不执行任何的终止线程和善后处理程序。code的值返回给调用进程(在Java 2的1.3版中新增加的) |
void load(String libraryFileName) | 载入库中文件由libraryFileName指定的动态库,必须指定它的完全路径 |
void loadLibrary(String libraryName) | 载入库名为libraryName的动态库 |
boolean removeShutdownHook(Thread thrd) | 当Java虚拟机中止,从线程列表中移出thrd的运行。如果成功,也就是说如果线程被移出,则返回true(在Java 2的1.3版中新增加的) |
void runFinalization( ) | 调用未用的但还不是回收站中对象的finalize()方法 |
long totalMemory( ) | 返回程序可以利用的内存的总字节数 |
void traceInstructions(boolean traceOn) | 根据traceOn的值,打开或关闭指令跟踪。如果traceOn值为true,跟踪被显示。如果traceOn值为false,跟踪被关闭 |
void traceMethodCalls(boolean traceOn) | 根据traceOn的值,打开或关闭调用跟踪的方法。如果traceOn的值为true,跟踪被显示。如果traceOn的值为false,跟踪被关闭 |
让我们来看一看Runtime类的两个最普遍的用法:内存管理和执行附加进程。
14.4.1 内存管理
尽管Java提供了自动垃圾回收,有时也想知道对象堆的大小以及它还剩下多少。可以利用这些信息检验你的代码的效率,或估计对某些类型,有多少对象可以被实例化。为了获得这些值,可以使用totalMemory( )和freeMemory( )方法。
正如我们在第1部分提及的,Java的垃圾回收器周期性地运行将不再使用的对象放入回收站。然而有时想在收集器的下一个指定循环之前收集被丢弃的对象。可以通过调用gc( )方法按照要求运行垃圾回收器。一个好的尝试是调用gc( )方法,然后再调用freeMemory( )方法以获得内存使用的底线。接着执行你的程序,并再一次调用freeMemory( )方法看分配了多少内存。下面的例子说明了这个思想。
// Demonstrate totalMemory(), freeMemory() and gc().
class MemoryDemo {
public static void main(String args[]) {
Runtime r = Runtime.getRuntime();
long mem1, mem2;
Integer someints[] = new Integer[1000];
System.out.println("Total memory is: " +
r.totalMemory());
mem1 = r.freeMemory();
System.out.println("Initial free memory: " + mem1);
r.gc();
mem1 = r.freeMemory();
System.out.println("Free memory after garbage collection: "
+ mem1);
for(int i=0; i<1000; i++)
someints[i] = new Integer(i); // allocate integers
mem2 = r.freeMemory();
System.out.println("Free memory after allocation: "
+ mem2);
System.out.println("Memory used by allocation: "
+ (mem1-mem2));
// discard Integers
for(int i=0; i<1000; i++) someints[i] = null;
r.gc(); // request garbage collection
mem2 = r.freeMemory();
System.out.println("Free memory after collecting" +
" discarded Integers: " + mem2);
}
}
这个例子的一个输出样本如下(当然,你的实际运行结果可能会与之不同):
Total memory is: 1048568
Initial free memory: 751392
Free memory after garbage collection: 841424
Free memory after allocation: 824000
Memory used by allocation: 17424
Free memory after collecting discarded Integers: 842640
14.4.2 执行其他的程序
在可靠的环境中,可以在你的多任务操作系统中使用Java去执行其他特别繁重的进程(也即程序)。exec( )方法的几种形式允许命名想运行的程序以及它们的输入参数。exec( )方法返回一个Process对象,这个对象可以被用来控制你的Java程序如何与这个正在运行的新进程相互作用。因为Java可以运行在多种平台和多种操作系统的情况下,exec( )方法本质上是依赖于环境的。
下面的例子使用exec( )方法装入Window的简单文本编辑器——notepad。显而易见,这个例子必须在Windows操作系统下运行。
// Demonstrate exec().
class ExecDemo {
public static void main(String args[]) {
Runtime r = Runtime.getRuntime();
Process p = null;
try {
p = r.exec("notepad");
} catch (Exception e) {
System.out.println("Error executing notepad.");
}
}
}
exec( )方法有几个形式可用,而在本例子中展示的是最常用的一种。在新程序开始运行之后,由exec( )方法返回的Process对象可以被Process方法使用。可以使用destroy( )方法杀死子进程。waitFor( )方法暂停你的程序直至子进程结束。当子进程结束后,exitValue( )方法返回子进程返回的值。如果没有问题发生,它通常返回0。下面是前面关于exec( )方法例子的改进版本。例子被修改为等待直至正在运行的进程退出:
// Wait until notepad is terminated.
class ExecDemoFini {
public static void main(String args[]) {
Runtime r = Runtime.getRuntime();
Process p = null;
try {
p = r.exec("notepad");
p.waitFor();
} catch (Exception e) {
System.out.println("Error executing notepad.");
}
System.out.println("Notepad returned " + p.exitValue());
}
}
当子进程正在运行时,可以从它的标准输入输出进行读和写。getOutputStream( )方法和getInputStream( )方法返回子进程的标准输入(in)和输出(out)的句柄(关于I/O将在第17章详细讨论)。
System类保存静态方法和变量的集合。标准的输入,输出和Java运行时错误输出存储在变量in,out和err中。由System类定义的方法列在表14-11中。注意当所做操作是安全方式所不允许的时,许多方法引发一个安全异常(SecurityException)。应当注意的另一点是:Java 2不赞成使用runFinalizersOnExit( )方法。该方法是在Java 1.1中增加的,同时也被证明是不可靠的。
让我们看一看System类的一些普遍用法。
表14-11 由Sysem定义的方法
方法 | 描述 |
static void arraycopy(Object source, int sourceStart, Object target, int targetStart, int size) | 复制数组。被复制的数组由source传递,而source中开始复制数组时的下标由sourceStart传递。接收复制的数组由target传递。而target中开始复制数组时的下标由targetStart传递。Size是被复制的元素的个数 |
static long currentTimeMillis( ) | 返回自1970年1月1日午夜至今的时间,时间单位为毫秒。 |
static void exit(int exitCode) | 暂停执行,返回exitCode值给父进程(通常为操作系统)。按照约定,0表示正常退出,所有其他的值代表某种形式的错误 |
static void gc( ) | 初始化垃圾回收 |
static Properties getProperties( ) | 返回与Java运行系统有关的属性类(Properties class)将在第15章中介绍) |
static String getProperty(String which) | 返回与which有关的属性。如果期望的属性没有被发现,返回一个空对象(null object) |
static String getProperty(String which, String default) | 返回一个与which有关的属性。如果期望的属性没有被发现,则返回default |
static SecurityManager getSecurityManager( ) | 返回当前的安全管理程序,如果没有安装安全管理程序,则返回一个空对象(null object) |
static native int identityHashCode(Object obj) | 返回obj的特征散列码 |
static void load(String libraryFileName) | 载入其文件由libraryFileName指定的动态库,必须指定其完全路径 |
static void loadLibrary(String libraryName) | 载入其库名为libraryName的动态库 |
static String mapLibraryName(String lib) | 对应名为lib的库,返回一个指定平台的名字(在Java 2中新增加的) |
static void runFinalization( ) | 启动调用不用的但还不是回收站中的对象的finalize( )方法。 |
static void setErr(PrintStream eStream) | 设置标准的错误(err)流为iStream |
static void setIn(InputStream iStream) | 设置标准的输入(in)流为oStream |
static void setOut(PrintStream oStream) | 设置标准的输出(out)流eStream |
static void setProperties(Properties sysProperties) | 设置由sysProperties指定的当前系统属性 |
Static String setProperty(String which, String v) | 将v值赋给名为which的属性(在Java 2中新增加的) |
static void setSecurityManager ( SecurityManager secMan) | 设置由secMan指定的安全管理程序 |
14.5.1 使用currentTimeMillis( )记录程序执行的时间
可以发现System类的一个特别有意义的用法是利用currentTimeMillis( )方法来记录你的程序的不同部分的执行时间。currentTimeMillis( )方法返回自从1970年1月1号午夜起到现在的时间,时间单位是毫秒。如果要记录你的程序中一段有问题程序的运行时间可以在这段程序开始之前存储当前时间,在该段程序结束之际再次调用currentTimeMillis( )方法。执行该段程序所花费的时间为其结束时刻的时间值减去其开始时刻的时间值。下面的程序说明了这一点:
// Timing program execution.
class Elapsed {
public static void main(String args[]) {
long start, end;
System.out.println("Timing a for loop from 0 to 1,000,000");
// time a for loop from 0 to 1,000,000
start = System.currentTimeMillis(); // get starting time
for(int i=0; i < 1000000; i++) ;
end = System.currentTimeMillis(); // get ending time
System.out.println("Elapsed time: " + (end-start));
}
}
这里是程序运行的一个输出样本(记住你的程序的运行结果可能与此不同):
Timing a for loop from 0 to 1,000,000
Elapsed time: 10
14.5.2 使用arraycopy( )
使用arraycopy( )方法可以将一个任意类型的数组快速地从一个地方复制到另一个地方。这比使用Java中编写的循环要快的多。下面是一个用arraycopy( )方法复制两个数组的例子。首先,将数组a复制给数组b,接下来,数组a中的所有元素向后移一位,然后数组b中元素向前移一位。
// Using arraycopy().
class ACDemo {
static byte a[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 };
static byte b[] = { 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 };
public static void main(String args[]) {
System.out.println("a = " + new String(a));
System.out.println("b = " + new String(b));
System.arraycopy(a, 0, b, 0, a.length);
System.out.println("a = " + new String(a));
System.out.println("b = " + new String(b));
System.arraycopy(a, 0, a, 1, a.length - 1);
System.arraycopy(b, 1, b, 0, b.length - 1);
System.out.println("a = " + new String(a));
System.out.println("b = " + new String(b));
}
}
正如从下面的输出中看到的那样,可以使用相同的源和目的在任一方向进行复制:
a = ABCDEFGHIJ
b = MMMMMMMMMM
a = ABCDEFGHIJ
b = ABCDEFGHIJ
a = AABCDEFGHI
b = BCDEFGHIJJ
14.5.3 环境属性
下面的属性在Java 2的所有环境中可以使用:
file.separator | java.vendor.url | os.arch |
java.class.path | java.version | os.name |
java.class.version | java.vm.name | os.version |
java.ext.dirs | java.vm.specification.name | Path.separator |
java.home | java.vm.specification.vendor | User.dir |
java.specification.name | java.vm.specification.version | User.home |
java.specification.vendor | java.vm.vendor | User.name |
java.specification.version | java.vm.version |
|
java.vendor | line.separator |
|
可以通过调用System.getProperty( )方法来获得不同环境变量的值。例如下面的程序显示当前用户目录的路径:
class ShowUserDir {
public static void main(String args[]) {
System.out.println(System.getProperty("user.dir"));
}
}
正如我们在第1部分所提及的,Object类是其他所有类的一个超类。表14-12给出了Object类中定义的方法,这些方法对于每一个对象都是可用的。
表14-12 由Object定义的方法
方法 | 描述 |
Object clone( ) Throws CloneNotSupportedException | 创建一个与调用对象一样的新对象 |
Boolean equals(Object object) | 如果调用对象等价于object返回true |
void finalize( ) throws Throwable | 默认的finalize( )方法。常常被子类重载 |
final Class getClass( ) | 获得描述调用对象的Class对象 |
int hashCode( ) | 返回与调用对象关联的散列码 |
final void notify( ) | 恢复等待调用对象的线程的执行 |
final void notifyAll( ) | 恢复等待调用对象的所有线程的执行 |
String toString( ) | 返回描述对象的一个字符串 |
final void wait( ) throws InterruptedException | 等待另一个执行的线程 |
final void wait(long milliseconds) throws InterruptedException | 等待直至指定毫秒数的另一个执行的线程 |
final void wait(long milliseconds, int nanoseconds) throws InterruptedException | 等待直至指定毫秒加毫微秒数的另一个执行的线程 |
14.7 使用clone( )和Cloneable接口
由Object类定义的绝大部分方法在本书其他部分讨论。而一个特别值得关注的方法是clone( )。clone( )方法创建调用它的对象的一个复制副本。只有那些实现Cloneable接口的类能被复制。
Cloneable接口没有定义成员。它通常用于指明被创建的一个允许对对象进行位复制(也就是对象副本)的类。如果试图用一个不支持Cloneable接口的类调用clone( )方法,将引发一个CloneNotSupportedException异常。当一个副本被创建时,并没有调用被复制对象的构造函数。副本仅仅是原对象的一个简单精确的拷贝。
复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。这里是另一个例子。如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的话,将导致错误。
由于复制可能引起问题,因此在Object内,clone( )方法被说明为protected。这就意味着它必须或者被由实现Cloneable的类所定义的方法调用,或者必须被那些类显式重载以便它是公共的。让我们看关于下面每一种方法的例子。
下面的程序实现Cloneable接口并定义cloneTest( )方法,该方法在Object中调用clone( )方法:
// Demonstrate the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// This method calls Object's clone().
TestClone cloneTest() {
try {
// call clone in Object.
return (TestClone) super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
x2 = x1.cloneTest(); // clone x1
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
这里,方法cloneTest( )在Object中调用clone( )方法并且返回结果。注意由clone( )方法返回的对象必须被强制转换成它的适当类型(TestClone)。
下面的例子重载clone( )方法以便它能被其类外的程序所调用。为了完成这项功能,它的存取说明符必须是public,如下所示:
// Override the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// clone() is now overridden and is public.
public Object clone() {
try {
// call clone in Object.
return super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo2 {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
// here, clone() is called directly.
x2 = (TestClone) x1.clone();
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
由复制带来的副作用最初一般是比较难发现的。通常很容易想到的是类在复制时是很安全的,而实际却不是这样。一般在没有一个必须的原因的情况下,对任何类都不应该执行Cloneable。
Class封装对象或接口运行时的状态。当类被加载时,类型Class的对象被自动创建。不能显式说明一个类(Class)对象。一般地,通过调用由Object定义的getClass( )方法来获得一个类(Class)对象。由Class定义的一些最常用的方法列在表14-13中。
表14-13 由Class定义的一些方法
方法 | 描述 |
static Class forName(String name) throws ClassNotFoundException | 返回一个给定全名的Class对象 |
static Class forName(String name, Boolean how, ClassLoader ldr) throws ClassNotFoundException | 返回一个给定全名的Calss对象。对象由ldr指定的加载程序加载。如果how为true,对象被初始化,否则它将不被初始化(在Java 2中新增加的) |
Class[ ] getClasses( ) | 对每一个公共类和接口,返回一个类(Class)对象。这些公共类和接口是调用对象的成员 |
ClassLoader getClassLoader( ) | 返回一个加载类或接口的ClassLoader对象,类或接口用于实例化调用对象 |
续表
方法 | 描述 |
Constructor[ ] getConstructors( ) throws SecurityException | 对这个类的所有的公共构造函数,返回一个Constructor对象 |
Constructor[ ] getDeclaredConstructors( ) throws SecurityException | 对由这个类所声明的所有构造函数,返回一个Constructor对象 |
Field[ ] getDeclaredFields( ) throws SecurityException | 对由这个类所声明的所有域,返回一个Field对象 |
Method[ ] getDeclaredMethods( ) throws SecurityException | 对由这个类或接口所声明的所有方法,返回一个Method对象 |
Field[ ] getFields( ) throws SecurityException | 对于这个类的所有公共域,返回一个Field对象 |
Class[ ] getInterfaces( ) | 当调用对象时,这个方法返回一个由该对象的类类型实现的接口数组。当调用接口时,这个方法返回一个由该接口扩展的接口数组 |
Method[ ] getMethods( ) throws SecurityException | 对这个类中的所有公共方法,返回一个Method对象 |
String getName( ) | 返回调用对象的类或接口的全名 |
ProtectionDomain getProtectionDomain( ) | 返回与调用对象有关的保护范围(在Java 2中新增加的) |
Class getSuperclass( ) | 返回调用对象的超类。如果调用对象是类型Object的,则返回值为空(null) |
Boolean isInterface( ) | 如果调用对象是一个接口,则返回true。否则返回false |
Object newInstance( ) throws IllegalAccessException, InstantiationException | 创建一个与调用对象类型相同的新的实例(即一个新对象)。这相当于对类的默认构造函数使用new。返回新对象 |
String toString( ) | 返回调用对象或接口的字符串表达式 |
由Class定义的方法经常用在需要知道对象的运行时类型信息的场合。如同表14-13中所说明的那样,由Class提供的方法确定关于特定的类的附加信息。例如它的公共构造函数,域以及方法。这对于本书后面将要讨论的Java Beans函数是很重要的。
下面的程序说明了getClass( )(从Object继承的)和getSuperclass( )方法(从Class继承的):
// Demonstrate Run-Time Type Information.
class X {
int a;
float b;
}
class Y extends X {
double c;
}
class RTTI {
public static void main(String args[]) {
X x = new X();
Y y = new Y();
Class clObj;
clObj = x.getClass(); // get Class reference
System.out.println("x is object of type: " +
clObj.getName());
clObj = y.getClass(); // get Class reference
System.out.println("y is object of type: " +
clObj.getName());
clObj = clObj.getSuperclass();
System.out.println("y's superclass is " +
clObj.getName());
}
}
这个程序的输出如下所示:
x is object of type: X
y is object of type: Y
y’s superclass is X
抽象类ClassLoader规定了类是如何加载的。应用程序可以创建扩展ClassLoader的子类,实现它的方法。这样做允许使用不同于通常由Java运行时系统加载的另一些方法来加载类。由ClassLoader定义的一些方法列在表14-14中。
表14-14 由CalssLoader定义的一些方法
方法 | 描述 |
final Class defineClass(String str, byte b[ ], int index, int numBytes) throws ClassFormatError | 返回一个类(Class)对象,类的名字在str中,对象包含在由b指定的字节数组中。该数组中对象开始的位置下标由index指定,而该数组的长度为numBytes。b中的数据必须表示一个有效的对象 |
final Class findSystemClass(String name) throws ClassNotFoundException | 返回一个给定名字的类(Class)对象 |
abstract Class loadClass(String name, boolean callResolveClass) throws ClassNotFoundException | 如果callResolveClass为true,这个抽象方法的实现工具必须加载一个给定名字的类,并调用resolveClass( )方法 |
final void resolveClass(Class obj) | 用obj引用的类被解析(即,它的名字被输入在类名字空间中) |
Math类保留了所有用于几何学,三角学以及几种一般用途方法的浮点函数。Math定义了两个双精度(double)常数:E(近似为2.72)和PI(近似为3.14)。
14.10.1 超越函数
下面的三种方法对一个以弧度为单位的角度接收一个双精度(double)参数并且返回它们各自的超越函数的结果:
方法 | 描述 |
Static double sin(double arg) | 返回由以弧度为单位由arg指定的角度的正弦值 |
static double cos(double arg) | 返回由以弧度为单位由arg指定的角度的余弦值 |
static double tan(double arg) | 返回由以弧度为单位由arg指定的角度的正切值 |
下面的方法将超越函数的结果作为一个参数,按弧度返回产生这个结果的角度值。它们是其非弧度形式的反。
方法 | 描述 |
static double asin(double arg) | 返回一个角度,该角度的正弦值由arg指定 |
static double acos(double arg) | 返回一个角度,该角度的余弦值由arg指定 |
static double atan(double arg) | 返回一个角度,该角度的正切值由arg指定 |
static double atan2(double x, double y) | 返回一个角度,该角度的正切值为x/y |
14.10.2 指数函数
Math定义了下面的指数方法:
方法 | 描述 |
static double exp(double arg) | 返回arg的e |
static double log(double arg) | 返回arg的自然对数值 |
static double pow(double y, double x) | 返回以y为底数,以x为指数的幂值;例如pow(2.0, 3.0)返回8.0 |
static double sqrt(double arg) | 返回arg的平方根 |
14.10.3 舍入函数
Math类定义了几个提供不同类型舍入运算的方法。这些方法列在表14-15中。
表14-15 由Math定义的舍入方法
方法 | 描述 |
static int abs(int arg) | 返回arg的绝对值 |
static long abs(long arg) | 返回arg的绝对值 |
static float abs(float arg) | 返回arg的绝对值 |
static double abs(double arg) | 返回arg的绝对值 |
static double ceil(double arg) | 返回大于或等于arg的最小整数 |
static double floor(double arg) | 返回小于或等于arg的最大整数 |
static int max(int x, int y) | 返回x和y中的最大值 |
static long max(long x, long y) | 返回x和y中的最大值 |
static float max(float x, float y) | 返回x和y中的最大值 |
static double max(double x, double y) | 返回x和y中的最大值 |
static int min(int x, int y) | 返回x和y中的最小值 |
static long min(long x, long y) | 返回x和y中的最小值 |
static float min(float x, float y) | 返回x和y中的最小值 |
static double min(double x, double y) | 返回x和y中的最小值 |
static double rint(double arg) | 返回最接近arg的整数值 |
static int round(float arg) | 返回arg的只入不舍的最近的整型(int)值 |
static long round(double arg) | 返回arg的只入不舍的最近的长整型(long)值 |
14.10.4 其他的数学方法
除了给出的方法,Math还定义了下面这些方法:
static double IEEEremainder(double dividend, double divisor)
static double random( )
static double toRadians(double angle)
static double toDegrees(double angle)
IEEEremainder( )方法返回dividend/divisor的余数。random( )方法返回一个伪随机数,其值介于0与1之间。在大多数情况下,当需要产生随机数时,通常用Random类。toRadians( )方法将角度的度转换为弧度。而toDegrees( )方法将弧度转换为度。这后两种方法是在Java 2中新增加的。
下面是一个说明toRadians( )和toDegrees( )方法的例子:
// Demonstrate toDegrees() and toRadians().
class Angles {
public static void main(String args[]) {
double theta = 120.0;
System.out.println(theta + " degrees is " +
Math.toRadians(theta) + " radians.");
theta = 1.312;
System.out.println(theta + " radians is " +
Math.toDegrees(theta) + " degrees.");
}
}
程序输出如下所示:
120.0 degrees is 2.0943951023931953 radians.
1.312 radians is 75.17206272116401 degrees.
在Java 2的1.3版本中增加了StrictMath类。这个类定义一个与Math中的数学方法类似的一套完整的数学方法。两者的区别在于StrictMath中的方法对所有Java工具保证产生精确一致的结果,而Math中的方法更大程度上是为了提高性能。
Compiler类支持创建将字节码编译而非解释成可执行码的Java环境。常规的程序不使用它。
14.13 Thread,ThreadGroup和Runnable
Runnable接口以及Thread和ThreadGroup类支持多线程编程。下面分别予以说明。
注意:关于管理线程,实现Runnable接口以及创建多线程程序的概述已在第11章中介绍过。
Runnable接口必须由启动执行的独立线程的类所实现。Runnable仅定义了一种抽象方法,叫做run( )。该方法是线程的入口点。它的形式如下所示:
abstract void run( )
所创建的线程必须实现该方法。
Thread创建一个新的执行线程。它定义了如下的构造函数:
Thread( )
Thread(Runnable threadOb)
Thread(Runnable threadOb, StringthreadName)
Thread(String threadName)
Thread(ThreadGroup groupOb, Runnable threadOb)
Thread(ThreadGroup groupOb, Runnable threadOb, String threadName)
Thread(ThreadGroup groupOb, String threadName)
threadOb是实现Runnable接口的类的一个实例,它定义了线程运行开始的地方。线程的名字由threadName指定。当名字未被指定时,Java虚拟机将创建一个。groupOb指定了新线程所属的线程组。当没有线程组被指定时,新线程与其父线程属于同一线程组。
下面的常数由Thread定义:
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIORITY
正如所期望的那样,这些常数指定了最大,最小以及默认的线程优先权。
由Thread定义的方法列在表14-16中。在比Java 2早的版本中,Thread中也包括了stop( ),suspend( )以及resume( )方法。然而正如在第11章中解释的那样,这些方法由于其固有的不稳定性而在Java 2中被摈弃了。在Java 2中摈弃的还有countStackFrames( )方法,因为它调用了suspend( )方法。
表14-16 由Thread定义的方法
方法 | 描述 |
static int activeCount( ) | 返回线程所属的线程组中线程的个数 |
void checkAccess( ) | 引起安全管理程序检验当前的线程能访问和/或能改变在其上checkAccess( )方法被调用的线程 |
static Thread currentThread( ) | 返回一个Thread对象,该对象封装了调用这个方法的线程 |
void destroy( ) | 终止线程 |
static int enumerate(Thread threads[ ]) | 将当前线程组中的所有Thread对象的拷贝放入threads中。返回线程的个数 |
ClassLoader getContextClassLoader( ) | 返回用于对这个线程加载类和资源的类加载程序(在Java 2中新增加的) |
final String getName( ) | 返回线程名 |
final int getPriority( ) | 返回线程的属性设置 |
final ThreadGroup getThreadGroup( ) | 返回调用线程是其中一个成员的ThreadGroup对象 |
void interrupt( ) | 中断线程 |
static boolean interrupted( ) | 如果当前执行的线程已经被预先设置了中断,则返回true;否则,返回false |
final boolean isAlive( ) | 如果线程仍在运行中,则返回true;否则返回false |
final boolean isDaemon( ) | 如果线程是一个后台进程线程(Java运行系统的一部分),则返回true;否则返回false |
boolean isInterrupted( ) | 如果线程被中断,则返回true,否则返回false |
final void join( ) throws InterruptedException | 等待直至线程终止 |
续表
方法 | 描述 |
final void join(long milliseconds) throws InterruptedException | 等待直到为终止线程而指定的以毫秒计时的时间 |
final void join(long milliseconds, int nanoseconds) throws InterruptedException | 等待直到为终止线程而指定的以毫秒加毫微秒计时的时间 |
void run( ) | 开始线程的执行 |
void setContextClassLoader(ClassLoader cl) | 设置将被调用线程用于cl的类加载程序(在Java 2中新增加的) |
final void setDaemon(boolean state) | 标记线程为后台进程线程 |
final void setName(String threadName) | 将线程的名字设置为由threadName指定的名字 |
final void setPriority(int priority) | 设置由priority指定的线程优先权 |
static void sleep(long milliseconds) throws InterruptedException | 以指定的毫秒为单位的时间长度挂起执行的线程 |
static void sleep(long milliseconds, int nanoseconds) throws InterruptedException | 以指定的毫秒加毫微秒为单位的时间长度挂起执行的线程 |
void start( ) | 开始线程的执行 |
String toString( ) | 返回线程的等价字符串形式 |
static void yield( ) | 调用线程将CPU让给其他的线程 |
线程组(ThreadGroup)创建了一组线程。它定义了如下的两个构造函数:
ThreadGroup(String groupName)
ThreadGroup(ThreadGroup parentOb, String groupName)
对于两种形式,groupName指定了线程组的名字。第一种形式创建一个新的线程组,该线程组将当前的线程作为它的父线程。在第二种形式中,父线程由parentOb指定。
由ThreadGroup定义的方法列在表14-17中。在比Java 2更早出现的Java版本中,ThreadGroup中也包括了stop( ),suspend( )以及resume( )方法。这些方法由于其本身固有的不稳定性,而在Java 2中被摈弃。
表14-17 由ThreadGroup定义的方法
方法 | 描述 |
int activeCount( ) | 返回线程组加上以这个线程作为父类的所有线程组中线程的个数 |
int activeGroupCount( ) | 返回调用线程是父类的线程的组数 |
final void checkAccess( ) | 引起安全管理程序检验调用线程能访问和/或能改变在其上checkAccess( )方法被调用的线程组 |
续表
方法 | 描述 |
final void destroy( ) | 撤消被调用的线程组(以及任一子线程组) |
int enumerate(Thread group[ ]) | 将构成调用线程组的线程放入group数组中 |
int enumerate(Thread group[ ], boolean all) | 将构成调用线程组的线程放入group数组中。如果all为true,那么线程组的所有子线程组中的线程也被放入group中 |
int enumerate(ThreadGroup group[ ]) | 将调用线程组的子线程组放入group数组中 |
int enumerate(ThreadGroup group[ ], boolean all) | 将调用线程组的子线程组放入group数组中。如果all为true,所有子线程组的子线程组(等等)也被放入group中 |
final int getMaxPriority( ) | 返回对线程组设置的最大优先权 |
final String getName( ) | 返回线程组名 |
final ThreadGroup getParent( ) | 如果调用ThreadGroup对象没有父类,则返回null;否则返回调用对象的父类 |
final void interrupt( ) | 调用线程组中所有线程的interrupt( )方法(在Java 2中新增加的) |
final boolean isDaemon( ) | 如果线程组是一个端口后台进程组,则返回true;否则返回false |
boolean isDestroyed( ) | 如果线程组已经被破坏,则返回true;否则,返回false |
void list( ) | 显示关于线程组的信息 |
final boolean parentOf(ThreadGroup group) | 如果调用线程是group的父线程(或group本身),则返回true;否则返回false |
final void setDaemon(boolean isDaemon) | 如果isDaemon为true,那么调用线程组被标记为一个端口后台进程组 |
final void setMaxPriority(int priority) | 对调用线程组设置最大优先权priority |
String toString( ) | 返回线程组的字符串等价形式 |
void uncaughtException(Thread thread, Throwable e) | 当一个异常未被捕获时,该方法被调用 |
线程组提供了一种方便的方法,可以将一组线程当做一个单元来管理。这在想挂起或恢复一些相关的线程的情况下,是特别有用的。例如假想在一个程序中,有一组线程被用来打印文档,另一组线程被用来将该文档显示在屏幕上,同时另一组线程将文档保存为磁盘文件。如果打印被异常中止了,想用一种很简单的方法停止所有与打印有关的线程。线程组为这种处理提供了方便。下面的程序说明了这种用法,在程序中创建两个线程组,每一线程组中有两个线程:
// Demonstrate thread groups.
class NewThread extends Thread {
boolean suspendFlag;
NewThread(String threadname, ThreadGroup tgOb) {
super(tgOb, threadname);
System.out.println("New thread: " + this);
suspendFlag = false;
start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(getName() + ": " + i);
Thread.sleep(1000);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (Exception e) {
System.out.println("Exception in " + getName());
}
System.out.println(getName() + " exiting.");
}
void mysuspend() {
suspendFlag = true;
}
synchronized void myresume() {
suspendFlag = false;
notify();
}
}
class ThreadGroupDemo {
public static void main(String args[]) {
ThreadGroup groupA = new ThreadGroup("Group A");
ThreadGroup groupB = new ThreadGroup("Group B");
NewThread ob1 = new NewThread("One", groupA);
NewThread ob2 = new NewThread("Two", groupA);
NewThread ob3 = new NewThread("Three", groupB);
NewThread ob4 = new NewThread("Four", groupB);
System.out.println("/nHere is output from list():");
groupA.list();
groupB.list();
System.out.println();
System.out.println("Suspending Group A");
Thread tga[] = new Thread[groupA.activeCount()];
groupA.enumerate(tga); // get threads in group
for(int i = 0; i < tga.length; i++) {
((NewThread)tga[i]).mysuspend(); // suspend each thread
}
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Resuming Group A");
for(int i = 0; i < tga.length; i++) {
((NewThread)tga[i]).myresume(); // resume threads in group
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.join();
ob2.join();
ob3.join();
ob4.join();
} catch (Exception e) {
System.out.println("Exception in Main thread");
}
System.out.println("Main thread exiting.");
}
}
该程序的一个输出样本如下所示:
New thread: Thread[One,5,Group A]
New thread: Thread[Two,5,Group A]
New thread: Thread[Three,5,Group B]
New thread: Thread[Four,5,Group B]
Here is output from list():
java.lang.ThreadGroup[name=Group A,maxpri=10]
Thread[One,5,Group A]
Thread[Two,5,Group A]
java.lang.ThreadGroup[name=Group B,maxpri=10]
Thread[Three,5,Group B]
Thread[Four,5,Group B]
Suspending Group A
Three: 5
Four: 5
Three: 4
Four: 4
Three: 3
Four: 3
Three: 2
Four: 2
Resuming Group A
Waiting for threads to finish.
One: 5
Two: 5
Three: 1
Four: 1
One: 4
Two: 4
Three exiting.
Four exiting.
One: 3
Two: 3
One: 2
Two: 2
One: 1
Two: 1
One exiting.
Two exiting.
Main thread exiting.
注意在这个程序中,线程组A被挂起四秒。由于输出确认,造成线程One和线程Two暂停,但是线程Three和线程Four仍然运行。四秒钟之后,线程One和线程Two被恢复。注意线程组A是如何被挂起和恢复的。首先通过对线程组A调用enumerate( )方法得到线程组A中的线程。然后每一个线程重复通过得到的数组而被挂起。为了恢复线程组A中的线程,序列再一次被遍历,每一个线程被恢复。最后一点:这个例子使用了Java 2推荐使用的方法去完成挂起和恢复线程的任务。而没有用在Java 2中被摈弃的方法suspend( )和resume( )。
14.14 ThreadLocal和InheritableThreadLocal
在Java 2的java.lang中增加了两个与线程有关的类:
· ThreadLocal 用于创建线程局部变量。每个线程都拥有自己局部变量的拷贝。
· InheritableThreadLocal 创建可以被继承的线程局部变量。
在Java 2中增加了一个称为Package的类。这个类封装了与包有关的版本数据。包版本信息由于包的增值以及由于Java程序可能需要知道哪些包版本可以利用而变得更加重要。Package中定义的方法列在表14-18中。下面的程序通过显示程序当前已知的包而说明了Package。
表14-18 由Package定义的方法
方法 | 描述 |
String getImplementationTitle( ) | 返回调用包的标题 |
String getImplementationVendor( ) | 返回调用包的实现程序的程序名 |
String getImplementationVersion( ) | 返回调用包的版本号 |
String getName( ) | 返回调用包的名字 |
Static Package getPackage(String pkgName) | 返回一个由pkgName指定的Package对象 |
续表
方法 | 描述 |
Static Package[ ] getPackages( ) | 返回调用程序当前已知的所有包 |
String getSpecificationTitle( ) | 返回调用包的规格说明的标题 |
String getSpecificationVendor( ) | 返回对调用包的规格说明的所有者的名字 |
String getSpecificationVersion( ) | 返回调用包的规格说明的版本号 |
Int hashCode( ) | 返回调用包的散列码 |
Boolean isCompatibleWith(String verNum) throws NumberFormatException | 如果verNum小于或等于调用包的版本号,则返回true |
Boolean isSealed( ) | 如果调用包被封,则返回true;否则返回false |
Boolean isSealed(URL url) | 如果调用包相对于url被封,则返回true;否则返回false。 |
String toString( ) | 返回调用包的等价字符串形式 |
// Demonstrate Package
class PkgTest {
public static void main(String args[]) {
Package pkgs[];
pkgs = Package.getPackages();
for(int i=0; i < pkgs.length; i++)
System.out.println(
pkgs[i].getName() + " " +
pkgs[i].getImplementationTitle() + " " +
pkgs[i].getImplementationVendor() + " " +
pkgs[i].getImplementationVersion()
);
}
}
在Java 2的java.lang中也新增加了RuntimePermission。它与Java的安全机制有关,这里不做进一步的讨论。
Throwable类支持Java的异常处理系统,它是派生所有异常类的类。在本书第10章已经讨论过它。
SecurityManager是一个子类可以实现的抽象类,它用于创建一个安全管理程序。一般不需要实现自己的安全管理程序,如果非要这样做,需要查阅与你的Java开发系统一起得到的相关文档。
Java 2在java.lang中新增加了一个接口:Comparable。实现Comparable的类的对象可以被排序。换句话说,实现Comparable的类包含了可以按某种有意义的方式进行比较的对象。Comparable接口说明了一个方法,该方法用于确定Java 2调用一个类的实例的自然顺序。该方法如下所示:
int compareTo(Object obj)
这个方法比较调用对象和obj。如果他们相等,就返回0。如果调用对象比obj小,则返回一个负值。否则返回一个正值。
该接口由前面已经介绍的几种类实现。特别是Byte,Character,Double,Float,Long,Short,String以及Integer类定义了compareTo( )方法。另外,下一章将会介绍到,实现这个接口的对象可以被使用在不同的集合中。
14.20 java.lang.ref和java.lang.reflect包
在Java中定义了两个java.lang的子包:java.lang.ref和java.lang.reflect。下面分别予以简单介绍。
在前面学到过,在Java中,垃圾回收工具自动确定何时对一个对象,没有引用存在。然后这个对象就被认为是不再需要的,同时它所占的内存也被释放。在Java 2中新增加的java.lang.ref包中的类对垃圾回收处理提供更加灵活的控制。例如,假设你的程序创建了大量的在后面某个时间又想重新使用的对象,可以持续保持对这些对象的引用,但是这可能需要更多的内存开销。
作为替代,可以对这些对象定义“软”引用。如果可以利用的内存接近用完的话,一个可以“软实现”的对象可以从垃圾回收工具中释放。在那种情况下,垃圾回收工具将这个对象的“软”引用设为空(null)。否则,垃圾回收工具保存对象以便以后使用。
程序设计人员具有确定是否一个“软实现”的对象被释放的能力。如果它被释放了,可以重新创建它。如果没有释放,该对象对于后面的应用将一直是可以利用的。也可以为对象创建“弱”(weak)和“假想”(phantom)引用,不过关于这些以及java.lang.ref包中其他特性的讨论已经超过了本书的范围。
Reflection是一个程序分析自己的能力。包java.lang.reflect提供了获得关于一个类的域、构造函数、方法和修改符的能力。需要这些信息去创建可以使你利用Java Beans组件的软件工具。这个工具使用映射动态地确定组件的特征。这个主题将在第25章中讨论。
另外,包java.lang.reflect包括了一个可以动态创建和访问数组的类。