@hainingwyx
2017-06-04T00:51:20.000000Z
字数 8869
阅读 1627
Java
Java程序的参数
如果运行Java程序时在类名后紧跟一个或多个字符串(多个字符串之间以空格隔开),JVM就会把这些字符串依次赋给args数组元素。
如果某参数本身包含了空格,则应该将该参数用双引号(")括起来,否则JVM会把这个空格当成参数分隔符,而不是当成参数本身。
使用Scanner获取键盘输入
使用Scanner类可以很方面地获取用户的键盘输入,Scanner是一个基于正则表达式的文本扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值。Scanner类提供了多个构造器,不同的构造器可接受文件、输入流、字符串作为数据源,用于从文件、输入流、字符串中解析数据。
Scanner主要提供了两个方法来扫描输入:
import java.util.*;public class ScannerKeyBoardTest{public static void main(String[] args){// System.in代表标准输入,就是键盘输入Scanner sc = new Scanner(System.in);// 增加下面一行将只把回车作为分隔符// sc.useDelimiter("\n");// 判断是否还有下一个输入项while(sc.hasNext()){// 输出输入项System.out.println("键盘输入的内容是:"+ sc.next());}}}
获取任意类型的输入项
import java.util.*;public class ScannerLongTest{public static void main(String[] args){// System.in代表标准输入,就是键盘输入Scanner sc = new Scanner(System.in);// 判断是否还有下一个long型整数while(sc.hasNextLong()){// 输出输入项System.out.println("键盘输入的内容是:"+ sc.nextLong());}}}
文件读取
import java.util.*;import java.io.*;public class ScannerFileTest{public static void main(String[] args)throws Exception{// 将一个File对象作为Scanner的构造器参数,Scanner读取文件内容Scanner sc = new Scanner(new File("ScannerFileTest.java"));System.out.println("ScannerFileTest.java文件内容如下:");// 判断是否还有下一行while(sc.hasNextLine()){// 输出文件中的下一行System.out.println(sc.nextLine());}}}
System类
System类提供了代表标准输入、标准输出和错误输出的类属性;并提供了一些静态方法用于访问环境变量、系统属性的方法;还提供了加载文件和动态链接库的方法。下面程序通过System类来访问操作的环境变量和系统属性。
import java.io.*;import java.util.*;public class SystemTest{public static void main(String[] args) throws Exception{// 获取系统所有的环境变量Map<String,String> env = System.getenv();for (String name : env.keySet()){System.out.println(name + " ---> " + env.get(name));}// 获取指定环境变量的值System.out.println(System.getenv("JAVA_HOME"));// 获取所有的系统属性Properties props = System.getProperties();// 将所有系统属性保存到props.txt文件中props.store(new FileOutputStream("props.txt"), "System Properties");// 输出特定的系统属性System.out.println(System.getProperty("os.name"));}}
如果两个对象的相同,一定是同一个对象。
public class IdentityHashCodeTest{public static void main(String[] args){// 下面程序中s1和s2是两个不同对象String s1 = new String("Hello");String s2 = new String("Hello");// String重写了hashCode()方法——改为根据字符序列计算hashCode值,// 因为s1和s2的字符序列相同,所以它们的hashCode方法返回值相同System.out.println(s1.hashCode()+ "----" + s2.hashCode());// s1和s2是不同的字符串对象,所以它们的identityHashCode值不同System.out.println(System.identityHashCode(s1)+ "----" + System.identityHashCode(s2));String s3 = "Java";String s4 = "Java";// s3和s4是相同的字符串对象,所以它们的identityHashCode值相同System.out.println(System.identityHashCode(s3)+ "----" + System.identityHashCode(s4));}}
Runtime类
Runtime类代表Java程序的运行时环境,每个Java程序都有一个与之对应的Runtime实例,应用程序通过该对象与其运行时环境相连。
应用程序不能创建自己的Runtime实例,但可以通过getRuntime()方法获取与之关联的Runtime对象。
Runtime类代表Java程序的运行时环境,可以访问JVM的相关信息,如处理器数量,内存信息等。
public class RuntimeTest{public static void main(String[] args){// 获取Java程序关联的运行时对象Runtime rt = Runtime.getRuntime();System.out.println("处理器数量:"+ rt.availableProcessors());System.out.println("空闲内存数:"+ rt.freeMemory());System.out.println("总内存数:"+ rt.totalMemory());System.out.println("可用最大内存数:"+ rt.maxMemory());}}
除此之外,Runtime还有一个功能:它可以直接单独启动一条进程来运行操作系统的命令。
public class ExecTest{public static void main(String[] args)throws Exception{Runtime rt = Runtime.getRuntime();// 运行记事本程序rt.exec("notepad.exe");}}
Object类
Object类是所有类、数组、枚举类的父类,也就是说,Java允许把所有任何类型的对象赋给Object类型的变量。当定义一个类时没有使用extends关键字为它显式指定父类,则该类默认继承Object父类。
Object还提供了一个protected修饰的clone()方法,程序员可重写该方法来实现“浅克隆”。
自定义类实现“浅克隆”的步骤:
class Address{String detail;public Address(String detail){this.detail = detail;}}// 实现Cloneable接口class User implements Cloneable{int age;Address address;public User(int age){this.age = age;address = new Address("广州天河");}// 通过调用super.clone()来实现clone()方法public User clone()throws CloneNotSupportedException{return (User)super.clone();}}public class CloneTest{public static void main(String[] args)throws CloneNotSupportedException{User u1 = new User(29);// clone得到u1对象的副本。User u2 = u1.clone();// 判断u1、u2是否相同System.out.println(u1 == u2); //false// 判断u1、u2的address是否相同//不会对引用类型的成员变量值所引用的对象进行深克隆System.out.println(u1.address == u2.address); //true}}
复制出来的只是原有对象的副本,只是一种浅克隆,只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行深克隆。深克隆需要开发者子集进行递归克隆。
Objects类
题外话:工具类命名习惯是添加s,如Arrays、Collections。
hashCode():返回指定对象的hashCode值。
toString:返回指定对象的“描述性”字符串。
requiredNonNull:检查对象是否为null。主要用于对方法形参进行输入校验。
import java.util.Objects;public class ObjectsTest{// 定义一个obj变量,它的默认值是nullstatic ObjectsTest obj;public static void main(String[] args){// 输出一个null对象的hashCode值,输出0System.out.println(Objects.hashCode(obj));// 输出一个null对象的toString,输出nullSystem.out.println(Objects.toString(obj));// 要求obj不能为null,如果obj为null则引发异常System.out.println(Objects.requireNonNull(obj, "obj参数不能是null!"));}}
String、StringBuffer和StringBuilder
字符串就是一连串的字符序列,Java提供了String和StringBuffer两个类来封装对字符串,并提供了系列方法来操作字符串对象。
String类是不可变类的,
StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append、insert、reverse、setCharAt、setLength等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString方法将其转换为一个String对象。
JDK1.5又新增了一个StringBuilder类,它也代表了字符串对象。StringBuilder是线程不安全的。
public class StringBuilderTest{public static void main(String[] args){StringBuilder sb = new StringBuilder();// 追加字符串sb.append("java");//sb = "java"// 插入sb.insert(0 , "hello "); // sb="hello java"// 替换sb.replace(5, 6, ","); // sb="hello, java"// 删除sb.delete(5, 6); // sb="hellojava"System.out.println(sb);// 反转sb.reverse(); // sb="avajolleh"System.out.println(sb);System.out.println(sb.length()); // 输出9System.out.println(sb.capacity()); // 输出16// 改变StringBuilder的长度,将只保留前面部分sb.setLength(5); // sb="avajo"System.out.println(sb);}}
Math 类
Math类是一个工具类,它的构造器被定义成private的,因此无法创建Math类的对象;Math类中所有方法都是类方法,可以直接通过类名来调用它们。
Random与ThreadLocalRandom
Random类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子,另一个构造器需要程序员显式传入一个long型整数的种子。
相对于Math的random()方法而言,Random类的提供了更多方法来生成各种伪随机数,它不仅可以生成浮点类型的伪随机数,也可以生成整数类型的伪随机数,还可以指定生成随机数的范围。
ThreadLocalRandom是Java7新增的,它可以在多线程环境下代替Random减少多线程资源竞争,从而提供更好的线程安全。
import java.util.*;public class RandomTest{public static void main(String[] args){Random rand = new Random();System.out.println("rand.nextBoolean():"+ rand.nextBoolean());byte[] buffer = new byte[16];rand.nextBytes(buffer);System.out.println(Arrays.toString(buffer));// 生成0.0~1.0之间的伪随机double数System.out.println("rand.nextDouble():"+ rand.nextDouble());// 生成0.0~1.0之间的伪随机float数System.out.println("rand.nextFloat():"+ rand.nextFloat());// 生成平均值是 0.0,标准差是 1.0的伪高斯数System.out.println("rand.nextGaussian():"+ rand.nextGaussian());// 生成一个处于int整数取值范围的伪随机整数System.out.println("rand.nextInt():" + rand.nextInt());// 生成0~26之间的伪随机整数System.out.println("rand.nextInt(26):" + rand.nextInt(26));// 生成一个处于long整数取值范围的伪随机整数System.out.println("rand.nextLong():" + rand.nextLong());}}
BigDecimal
float、double两种基本浮点类型的浮点数容易引起精度丢失。
程序中需要对double浮点数进行加、减、乘、除基本运算,则需要先将double类型数值包装成BigDecimal对象,调用BigDecimal对象的方法执行运算后再将结果转换成double型变量。
public class BigDecimalTest{public static void main(String[] args){BigDecimal f1 = new BigDecimal("0.05");BigDecimal f2 = BigDecimal.valueOf(0.01);BigDecimal f3 = new BigDecimal(0.05);System.out.println("使用String作为BigDecimal构造器参数:");System.out.println("0.05 + 0.01 = " + f1.add(f2));System.out.println("0.05 - 0.01 = " + f1.subtract(f2));System.out.println("0.05 * 0.01 = " + f1.multiply(f2));System.out.println("0.05 / 0.01 = " + f1.divide(f2));System.out.println("使用double作为BigDecimal构造器参数:");System.out.println("0.05 + 0.01 = " + f3.add(f2));System.out.println("0.05 - 0.01 = " + f3.subtract(f2));System.out.println("0.05 * 0.01 = " + f3.multiply(f2));System.out.println("0.05 / 0.01 = " + f3.divide(f2));}}
注意:创建BigDecimal对象时,不要直接使用double浮点数作为构造器参数调用BigDecimal构造器
。否则会有精度损失。
Date类
Date类从JDK1.0起就开始存在了。但正因为它历史悠久,所以它的大部分构造器、方法都已经过时,不再推荐使用了
Calender类
因为Date类的设计上存在一些缺陷,Java提供了Calendar类来更好地处理日期和时间。Calendar是一个抽象类,它用于表示日历。
Calendar本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法,但它本身不能直接实例化。程序只能创建Calendar子类的实例,Java本身提供了一个GregorianCalendar类,一个代表Gregorian Calendar的子类,它代表了我们通常所说的公历。
开发者可以开发自己的Calendar子类。
import java.util.*;public class CalendarTest{public static void main(String[] args){Calendar c = Calendar.getInstance();// 取出年System.out.println(c.get(YEAR));// 取出月份System.out.println(c.get(MONTH));// 取出日System.out.println(c.get(DATE));// 分别设置年、月、日、小时、分钟、秒c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23System.out.println(c.getTime());// 将Calendar的年前推1年c.add(YEAR , -1); //2002-11-23 12:32:23System.out.println(c.getTime());// 将Calendar的月前推8个月c.roll(MONTH , -8); //2002-03-23 12:32:23System.out.println(c.getTime());Calendar cal1 = Calendar.getInstance();cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23System.out.println(cal1.getTime());Calendar cal2 = Calendar.getInstance();cal2.set(2003, 7, 31, 0, 0 , 0); // 2003-8-31// 因为进位到后月份改为2月,2月没有31日,自动变成29日cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29System.out.println(cal2.getTime());Calendar cal3 = Calendar.getInstance();cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23// MONTH字段“进位”,但YEAR字段并不增加cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23System.out.println(cal3.getTime());Calendar cal4 = Calendar.getInstance();cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31// MONTH字段“进位”后变成2,2月没有31日,// YEAR字段不会改变,2003年2月只有28天cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28System.out.println(cal4.getTime());}}