[关闭]
@hainingwyx 2017-06-04T08:51:20.000000Z 字数 8869 阅读 1427

6. Java基础类库

Java


与用户互动

Java程序的参数
如果运行Java程序时在类名后紧跟一个或多个字符串(多个字符串之间以空格隔开),JVM就会把这些字符串依次赋给args数组元素。
如果某参数本身包含了空格,则应该将该参数用双引号(")括起来,否则JVM会把这个空格当成参数分隔符,而不是当成参数本身。

使用Scanner获取键盘输入
使用Scanner类可以很方面地获取用户的键盘输入,Scanner是一个基于正则表达式的文本扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值。Scanner类提供了多个构造器,不同的构造器可接受文件、输入流、字符串作为数据源,用于从文件、输入流、字符串中解析数据。
Scanner主要提供了两个方法来扫描输入:

  1. import java.util.*;
  2. public class ScannerKeyBoardTest
  3. {
  4. public static void main(String[] args)
  5. {
  6. // System.in代表标准输入,就是键盘输入
  7. Scanner sc = new Scanner(System.in);
  8. // 增加下面一行将只把回车作为分隔符
  9. // sc.useDelimiter("\n");
  10. // 判断是否还有下一个输入项
  11. while(sc.hasNext())
  12. {
  13. // 输出输入项
  14. System.out.println("键盘输入的内容是:"
  15. + sc.next());
  16. }
  17. }
  18. }

获取任意类型的输入项

  1. import java.util.*;
  2. public class ScannerLongTest
  3. {
  4. public static void main(String[] args)
  5. {
  6. // System.in代表标准输入,就是键盘输入
  7. Scanner sc = new Scanner(System.in);
  8. // 判断是否还有下一个long型整数
  9. while(sc.hasNextLong())
  10. {
  11. // 输出输入项
  12. System.out.println("键盘输入的内容是:"
  13. + sc.nextLong());
  14. }
  15. }
  16. }

文件读取

  1. import java.util.*;
  2. import java.io.*;
  3. public class ScannerFileTest
  4. {
  5. public static void main(String[] args)
  6. throws Exception
  7. {
  8. // 将一个File对象作为Scanner的构造器参数,Scanner读取文件内容
  9. Scanner sc = new Scanner(new File("ScannerFileTest.java"));
  10. System.out.println("ScannerFileTest.java文件内容如下:");
  11. // 判断是否还有下一行
  12. while(sc.hasNextLine())
  13. {
  14. // 输出文件中的下一行
  15. System.out.println(sc.nextLine());
  16. }
  17. }
  18. }

系统相关

System类
System类提供了代表标准输入、标准输出和错误输出的类属性;并提供了一些静态方法用于访问环境变量、系统属性的方法;还提供了加载文件和动态链接库的方法。下面程序通过System类来访问操作的环境变量和系统属性。

  1. import java.io.*;
  2. import java.util.*;
  3. public class SystemTest
  4. {
  5. public static void main(String[] args) throws Exception
  6. {
  7. // 获取系统所有的环境变量
  8. Map<String,String> env = System.getenv();
  9. for (String name : env.keySet())
  10. {
  11. System.out.println(name + " ---> " + env.get(name));
  12. }
  13. // 获取指定环境变量的值
  14. System.out.println(System.getenv("JAVA_HOME"));
  15. // 获取所有的系统属性
  16. Properties props = System.getProperties();
  17. // 将所有系统属性保存到props.txt文件中
  18. props.store(new FileOutputStream("props.txt")
  19. , "System Properties");
  20. // 输出特定的系统属性
  21. System.out.println(System.getProperty("os.name"));
  22. }
  23. }

如果两个对象的相同,一定是同一个对象。

  1. public class IdentityHashCodeTest
  2. {
  3. public static void main(String[] args)
  4. {
  5. // 下面程序中s1和s2是两个不同对象
  6. String s1 = new String("Hello");
  7. String s2 = new String("Hello");
  8. // String重写了hashCode()方法——改为根据字符序列计算hashCode值,
  9. // 因为s1和s2的字符序列相同,所以它们的hashCode方法返回值相同
  10. System.out.println(s1.hashCode()
  11. + "----" + s2.hashCode());
  12. // s1和s2是不同的字符串对象,所以它们的identityHashCode值不同
  13. System.out.println(System.identityHashCode(s1)
  14. + "----" + System.identityHashCode(s2));
  15. String s3 = "Java";
  16. String s4 = "Java";
  17. // s3和s4是相同的字符串对象,所以它们的identityHashCode值相同
  18. System.out.println(System.identityHashCode(s3)
  19. + "----" + System.identityHashCode(s4));
  20. }
  21. }

Runtime类

Runtime类代表Java程序的运行时环境,每个Java程序都有一个与之对应的Runtime实例,应用程序通过该对象与其运行时环境相连。
应用程序不能创建自己的Runtime实例,但可以通过getRuntime()方法获取与之关联的Runtime对象。
Runtime类代表Java程序的运行时环境,可以访问JVM的相关信息,如处理器数量,内存信息等。

  1. public class RuntimeTest
  2. {
  3. public static void main(String[] args)
  4. {
  5. // 获取Java程序关联的运行时对象
  6. Runtime rt = Runtime.getRuntime();
  7. System.out.println("处理器数量:"
  8. + rt.availableProcessors());
  9. System.out.println("空闲内存数:"
  10. + rt.freeMemory());
  11. System.out.println("总内存数:"
  12. + rt.totalMemory());
  13. System.out.println("可用最大内存数:"
  14. + rt.maxMemory());
  15. }
  16. }

除此之外,Runtime还有一个功能:它可以直接单独启动一条进程来运行操作系统的命令。

  1. public class ExecTest
  2. {
  3. public static void main(String[] args)
  4. throws Exception
  5. {
  6. Runtime rt = Runtime.getRuntime();
  7. // 运行记事本程序
  8. rt.exec("notepad.exe");
  9. }
  10. }

常用类

Object类
Object类是所有类、数组、枚举类的父类,也就是说,Java允许把所有任何类型的对象赋给Object类型的变量。当定义一个类时没有使用extends关键字为它显式指定父类,则该类默认继承Object父类。

Object还提供了一个protected修饰的clone()方法,程序员可重写该方法来实现“浅克隆”。
自定义类实现“浅克隆”的步骤:

  1. 自定义类实现Cloneable接口。
  2. 自定义类实现clone()方法。
  3. 在clone()方法中通过super.clone()调用Object的clone()方法来实现“浅克隆”。
  1. class Address
  2. {
  3. String detail;
  4. public Address(String detail)
  5. {
  6. this.detail = detail;
  7. }
  8. }
  9. // 实现Cloneable接口
  10. class User implements Cloneable
  11. {
  12. int age;
  13. Address address;
  14. public User(int age)
  15. {
  16. this.age = age;
  17. address = new Address("广州天河");
  18. }
  19. // 通过调用super.clone()来实现clone()方法
  20. public User clone()
  21. throws CloneNotSupportedException
  22. {
  23. return (User)super.clone();
  24. }
  25. }
  26. public class CloneTest
  27. {
  28. public static void main(String[] args)
  29. throws CloneNotSupportedException
  30. {
  31. User u1 = new User(29);
  32. // clone得到u1对象的副本。
  33. User u2 = u1.clone();
  34. // 判断u1、u2是否相同
  35. System.out.println(u1 == u2); //false
  36. // 判断u1、u2的address是否相同
  37. //不会对引用类型的成员变量值所引用的对象进行深克隆
  38. System.out.println(u1.address == u2.address); //true
  39. }
  40. }

复制出来的只是原有对象的副本,只是一种浅克隆,只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行深克隆。深克隆需要开发者子集进行递归克隆。

Objects类
题外话:工具类命名习惯是添加s,如Arrays、Collections。
hashCode():返回指定对象的hashCode值。
toString:返回指定对象的“描述性”字符串。
requiredNonNull:检查对象是否为null。主要用于对方法形参进行输入校验。

  1. import java.util.Objects;
  2. public class ObjectsTest
  3. {
  4. // 定义一个obj变量,它的默认值是null
  5. static ObjectsTest obj;
  6. public static void main(String[] args)
  7. {
  8. // 输出一个null对象的hashCode值,输出0
  9. System.out.println(Objects.hashCode(obj));
  10. // 输出一个null对象的toString,输出null
  11. System.out.println(Objects.toString(obj));
  12. // 要求obj不能为null,如果obj为null则引发异常
  13. System.out.println(Objects.requireNonNull(obj
  14. , "obj参数不能是null!"));
  15. }
  16. }

String、StringBuffer和StringBuilder

字符串就是一连串的字符序列,Java提供了String和StringBuffer两个类来封装对字符串,并提供了系列方法来操作字符串对象。
String类是不可变类的,
StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append、insert、reverse、setCharAt、setLength等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString方法将其转换为一个String对象。
JDK1.5又新增了一个StringBuilder类,它也代表了字符串对象。StringBuilder是线程不安全的。

  1. public class StringBuilderTest
  2. {
  3. public static void main(String[] args)
  4. {
  5. StringBuilder sb = new StringBuilder();
  6. // 追加字符串
  7. sb.append("java");//sb = "java"
  8. // 插入
  9. sb.insert(0 , "hello "); // sb="hello java"
  10. // 替换
  11. sb.replace(5, 6, ","); // sb="hello, java"
  12. // 删除
  13. sb.delete(5, 6); // sb="hellojava"
  14. System.out.println(sb);
  15. // 反转
  16. sb.reverse(); // sb="avajolleh"
  17. System.out.println(sb);
  18. System.out.println(sb.length()); // 输出9
  19. System.out.println(sb.capacity()); // 输出16
  20. // 改变StringBuilder的长度,将只保留前面部分
  21. sb.setLength(5); // sb="avajo"
  22. System.out.println(sb);
  23. }
  24. }

Math 类
Math类是一个工具类,它的构造器被定义成private的,因此无法创建Math类的对象;Math类中所有方法都是类方法,可以直接通过类名来调用它们。

Random与ThreadLocalRandom
Random类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子,另一个构造器需要程序员显式传入一个long型整数的种子。
相对于Math的random()方法而言,Random类的提供了更多方法来生成各种伪随机数,它不仅可以生成浮点类型的伪随机数,也可以生成整数类型的伪随机数,还可以指定生成随机数的范围。
ThreadLocalRandom是Java7新增的,它可以在多线程环境下代替Random减少多线程资源竞争,从而提供更好的线程安全。

  1. import java.util.*;
  2. public class RandomTest
  3. {
  4. public static void main(String[] args)
  5. {
  6. Random rand = new Random();
  7. System.out.println("rand.nextBoolean():"
  8. + rand.nextBoolean());
  9. byte[] buffer = new byte[16];
  10. rand.nextBytes(buffer);
  11. System.out.println(Arrays.toString(buffer));
  12. // 生成0.0~1.0之间的伪随机double数
  13. System.out.println("rand.nextDouble():"
  14. + rand.nextDouble());
  15. // 生成0.0~1.0之间的伪随机float数
  16. System.out.println("rand.nextFloat():"
  17. + rand.nextFloat());
  18. // 生成平均值是 0.0,标准差是 1.0的伪高斯数
  19. System.out.println("rand.nextGaussian():"
  20. + rand.nextGaussian());
  21. // 生成一个处于int整数取值范围的伪随机整数
  22. System.out.println("rand.nextInt():" + rand.nextInt());
  23. // 生成0~26之间的伪随机整数
  24. System.out.println("rand.nextInt(26):" + rand.nextInt(26));
  25. // 生成一个处于long整数取值范围的伪随机整数
  26. System.out.println("rand.nextLong():" + rand.nextLong());
  27. }
  28. }

BigDecimal
float、double两种基本浮点类型的浮点数容易引起精度丢失。
程序中需要对double浮点数进行加、减、乘、除基本运算,则需要先将double类型数值包装成BigDecimal对象,调用BigDecimal对象的方法执行运算后再将结果转换成double型变量。

  1. public class BigDecimalTest
  2. {
  3. public static void main(String[] args)
  4. {
  5. BigDecimal f1 = new BigDecimal("0.05");
  6. BigDecimal f2 = BigDecimal.valueOf(0.01);
  7. BigDecimal f3 = new BigDecimal(0.05);
  8. System.out.println("使用String作为BigDecimal构造器参数:");
  9. System.out.println("0.05 + 0.01 = " + f1.add(f2));
  10. System.out.println("0.05 - 0.01 = " + f1.subtract(f2));
  11. System.out.println("0.05 * 0.01 = " + f1.multiply(f2));
  12. System.out.println("0.05 / 0.01 = " + f1.divide(f2));
  13. System.out.println("使用double作为BigDecimal构造器参数:");
  14. System.out.println("0.05 + 0.01 = " + f3.add(f2));
  15. System.out.println("0.05 - 0.01 = " + f3.subtract(f2));
  16. System.out.println("0.05 * 0.01 = " + f3.multiply(f2));
  17. System.out.println("0.05 / 0.01 = " + f3.divide(f2));
  18. }
  19. }

注意:创建BigDecimal对象时,不要直接使用double浮点数作为构造器参数调用BigDecimal构造器
。否则会有精度损失。

日期时间类

Date类
Date类从JDK1.0起就开始存在了。但正因为它历史悠久,所以它的大部分构造器、方法都已经过时,不再推荐使用了

Calender类
因为Date类的设计上存在一些缺陷,Java提供了Calendar类来更好地处理日期和时间。Calendar是一个抽象类,它用于表示日历。
Calendar本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法,但它本身不能直接实例化。程序只能创建Calendar子类的实例,Java本身提供了一个GregorianCalendar类,一个代表Gregorian Calendar的子类,它代表了我们通常所说的公历。
开发者可以开发自己的Calendar子类。

  1. import java.util.*;
  2. public class CalendarTest
  3. {
  4. public static void main(String[] args)
  5. {
  6. Calendar c = Calendar.getInstance();
  7. // 取出年
  8. System.out.println(c.get(YEAR));
  9. // 取出月份
  10. System.out.println(c.get(MONTH));
  11. // 取出日
  12. System.out.println(c.get(DATE));
  13. // 分别设置年、月、日、小时、分钟、秒
  14. c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23
  15. System.out.println(c.getTime());
  16. // 将Calendar的年前推1年
  17. c.add(YEAR , -1); //2002-11-23 12:32:23
  18. System.out.println(c.getTime());
  19. // 将Calendar的月前推8个月
  20. c.roll(MONTH , -8); //2002-03-23 12:32:23
  21. System.out.println(c.getTime());
  22. Calendar cal1 = Calendar.getInstance();
  23. cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23
  24. cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
  25. System.out.println(cal1.getTime());
  26. Calendar cal2 = Calendar.getInstance();
  27. cal2.set(2003, 7, 31, 0, 0 , 0); // 2003-8-31
  28. // 因为进位到后月份改为2月,2月没有31日,自动变成29日
  29. cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29
  30. System.out.println(cal2.getTime());
  31. Calendar cal3 = Calendar.getInstance();
  32. cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
  33. // MONTH字段“进位”,但YEAR字段并不增加
  34. cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23
  35. System.out.println(cal3.getTime());
  36. Calendar cal4 = Calendar.getInstance();
  37. cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
  38. // MONTH字段“进位”后变成2,2月没有31日,
  39. // YEAR字段不会改变,2003年2月只有28天
  40. cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28
  41. System.out.println(cal4.getTime());
  42. }
  43. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注