以下是《瘋狂Java講義》中的一些知識,如有錯誤浅蚪,煩請指正挟鸠。
與用戶互動
Java程序的參數(shù)
如果運行Java程序時在類名后緊跟一個或多個字符串(多個字符串之間以空格隔開),JVM就會把這些字符串依次賦給args數(shù)組元素米辐。
如果某參數(shù)本身包含了空格,則應(yīng)該將該參數(shù)用雙引號(")括起來书释,否則JVM會把這個空格當成參數(shù)分隔符翘贮,而不是當成參數(shù)本身。
使用Scanner獲取鍵盤輸入
使用Scanner類可以很方面地獲取用戶的鍵盤輸入爆惧,Scanner是一個基于正則表達式的文本掃描器狸页,它可以從文件、輸入流检激、字符串中解析出基本類型值和字符串值肴捉。Scanner類提供了多個構(gòu)造器,不同的構(gòu)造器可接受文件叔收、輸入流、字符串作為數(shù)據(jù)源傲隶,用于從文件饺律、輸入流、字符串中解析數(shù)據(jù)跺株。
Scanner主要提供了兩個方法來掃描輸入:
- hasNextXxx():是否還有下一個輸入項复濒,其中Xxx可以是Int脖卖、Long等代表基本數(shù)據(jù)類型的字符串。如果需要判斷是否包含下一個字符串巧颈,則可以省略Xxx畦木。
- nextXxx():獲取下一個輸入項。Xxx的含義與前一個方法中Xxx相同砸泛。
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("鍵盤輸入的內(nèi)容是:"
+ sc.next());
}
}
}
獲取任意類型的輸入項
import java.util.*;
public class ScannerLongTest
{
public static void main(String[] args)
{
// System.in代表標準輸入,就是鍵盤輸入
Scanner sc = new Scanner(System.in);
// 判斷是否還有下一個long型整數(shù)
while(sc.hasNextLong())
{
// 輸出輸入項
System.out.println("鍵盤輸入的內(nèi)容是:"
+ sc.nextLong());
}
}
}
文件讀取
import java.util.*;
import java.io.*;
public class ScannerFileTest
{
public static void main(String[] args)
throws Exception
{
// 將一個File對象作為Scanner的構(gòu)造器參數(shù)唇礁,Scanner讀取文件內(nèi)容
Scanner sc = new Scanner(new File("ScannerFileTest.java"));
System.out.println("ScannerFileTest.java文件內(nèi)容如下:");
// 判斷是否還有下一行
while(sc.hasNextLine())
{
// 輸出文件中的下一行
System.out.println(sc.nextLine());
}
}
}
系統(tǒng)相關(guān)
System類
System類提供了代表標準輸入勾栗、標準輸出和錯誤輸出的類屬性;并提供了一些靜態(tài)方法用于訪問環(huán)境變量盏筐、系統(tǒng)屬性的方法围俘;還提供了加載文件和動態(tài)鏈接庫的方法。下面程序通過System類來訪問操作的環(huán)境變量和系統(tǒng)屬性琢融。
import java.io.*;
import java.util.*;
public class SystemTest
{
public static void main(String[] args) throws Exception
{
// 獲取系統(tǒng)所有的環(huán)境變量
Map<String,String> env = System.getenv();
for (String name : env.keySet())
{
System.out.println(name + " ---> " + env.get(name));
}
// 獲取指定環(huán)境變量的值
System.out.println(System.getenv("JAVA_HOME"));
// 獲取所有的系統(tǒng)屬性
Properties props = System.getProperties();
// 將所有系統(tǒng)屬性保存到props.txt文件中
props.store(new FileOutputStream("props.txt")
, "System Properties");
// 輸出特定的系統(tǒng)屬性
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()方法——改為根據(jù)字符序列計算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程序的運行時環(huán)境她混,每個Java程序都有一個與之對應(yīng)的Runtime實例,應(yīng)用程序通過該對象與其運行時環(huán)境相連泊碑。
應(yīng)用程序不能創(chuàng)建自己的Runtime實例坤按,但可以通過getRuntime()方法獲取與之關(guān)聯(lián)的Runtime對象。
Runtime類代表Java程序的運行時環(huán)境馒过,可以訪問JVM的相關(guān)信息臭脓,如處理器數(shù)量,內(nèi)存信息等腹忽。
public class RuntimeTest
{
public static void main(String[] args)
{
// 獲取Java程序關(guān)聯(lián)的運行時對象
Runtime rt = Runtime.getRuntime();
System.out.println("處理器數(shù)量:"
+ rt.availableProcessors());
System.out.println("空閑內(nèi)存數(shù):"
+ rt.freeMemory());
System.out.println("總內(nèi)存數(shù):"
+ rt.totalMemory());
System.out.println("可用最大內(nèi)存數(shù):"
+ rt.maxMemory());
}
}
除此之外来累,Runtime還有一個功能:它可以直接單獨啟動一條進程來運行操作系統(tǒng)的命令。
public class ExecTest
{
public static void main(String[] args)
throws Exception
{
Runtime rt = Runtime.getRuntime();
// 運行記事本程序
rt.exec("notepad.exe");
}
}
常用類
Object類
Object類是所有類窘奏、數(shù)組嘹锁、枚舉類的父類,也就是說着裹,Java允許把所有任何類型的對象賦給Object類型的變量领猾。當定義一個類時沒有使用extends關(guān)鍵字為它顯式指定父類,則該類默認繼承Object父類。
Object還提供了一個protected修飾的clone()方法摔竿,程序員可重寫該方法來實現(xiàn)“淺克隆”面粮。
自定義類實現(xiàn)“淺克隆”的步驟:
- 自定義類實現(xiàn)Cloneable接口。
- 自定義類實現(xiàn)clone()方法继低。
- 在clone()方法中通過super.clone()調(diào)用Object的clone()方法來實現(xiàn)“淺克隆”熬苍。
class Address
{
String detail;
public Address(String detail)
{
this.detail = detail;
}
}
// 實現(xiàn)Cloneable接口
class User implements Cloneable
{
int age;
Address address;
public User(int age)
{
this.age = age;
address = new Address("廣州天河");
}
// 通過調(diào)用super.clone()來實現(xiàn)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
}
}
復(fù)制出來的只是原有對象的副本,只是一種淺克隆梦裂,只克隆該對象的所有成員變量值似枕,不會對引用類型的成員變量值所引用的對象進行深克隆。深克隆需要開發(fā)者子集進行遞歸克隆年柠。
Objects類
題外話:工具類命名習慣是添加s凿歼,如Arrays、Collections冗恨。
hashCode():返回指定對象的hashCode值答憔。
toString:返回指定對象的“描述性”字符串。
requiredNonNull:檢查對象是否為null掀抹。主要用于對方法形參進行輸入校驗虐拓。
import java.util.Objects;
public class ObjectsTest
{
// 定義一個obj變量,它的默認值是null
static ObjectsTest obj;
public static void main(String[] args)
{
// 輸出一個null對象的hashCode值傲武,輸出0
System.out.println(Objects.hashCode(obj));
// 輸出一個null對象的toString蓉驹,輸出null
System.out.println(Objects.toString(obj));
// 要求obj不能為null,如果obj為null則引發(fā)異常
System.out.println(Objects.requireNonNull(obj
, "obj參數(shù)不能是null揪利!"));
}
}
String态兴、StringBuffer和StringBuilder
字符串就是一連串的字符序列,Java提供了String和StringBuffer兩個類來封裝對字符串疟位,并提供了系列方法來操作字符串對象瞻润。
String類是不可變類的,
StringBuffer對象則代表一個字符序列可變的字符串甜刻,當一個StringBuffer被創(chuàng)建以后绍撞,通過StringBuffer提供的append、insert得院、reverse傻铣、setCharAt、setLength等方法可以改變這個字符串對象的字符序列祥绞。一旦通過StringBuffer生成了最終想要的字符串矾柜,就可以調(diào)用它的toString方法將其轉(zhuǎn)換為一個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);
// 反轉(zhuǎn)
sb.reverse(); // sb="avajolleh"
System.out.println(sb);
System.out.println(sb.length()); // 輸出9
System.out.println(sb.capacity()); // 輸出16
// 改變StringBuilder的長度丧荐,將只保留前面部分
sb.setLength(5); // sb="avajo"
System.out.println(sb);
}
}
Math 類
Math類是一個工具類缆瓣,它的構(gòu)造器被定義成private的,因此無法創(chuàng)建Math類的對象虹统;Math類中所有方法都是類方法弓坞,可以直接通過類名來調(diào)用它們。
Random與ThreadLocalRandom
Random類專門用于生成一個偽隨機數(shù)车荔,它有兩個構(gòu)造器:一個構(gòu)造器使用默認的種子渡冻,另一個構(gòu)造器需要程序員顯式傳入一個long型整數(shù)的種子。
相對于Math的random()方法而言忧便,Random類的提供了更多方法來生成各種偽隨機數(shù)族吻,它不僅可以生成浮點類型的偽隨機數(shù),也可以生成整數(shù)類型的偽隨機數(shù)珠增,還可以指定生成隨機數(shù)的范圍超歌。
ThreadLocalRandom是Java7新增的,它可以在多線程環(huán)境下代替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數(shù)
System.out.println("rand.nextDouble():"
+ rand.nextDouble());
// 生成0.0~1.0之間的偽隨機float數(shù)
System.out.println("rand.nextFloat():"
+ rand.nextFloat());
// 生成平均值是 0.0,標準差是 1.0的偽高斯數(shù)
System.out.println("rand.nextGaussian():"
+ rand.nextGaussian());
// 生成一個處于int整數(shù)取值范圍的偽隨機整數(shù)
System.out.println("rand.nextInt():" + rand.nextInt());
// 生成0~26之間的偽隨機整數(shù)
System.out.println("rand.nextInt(26):" + rand.nextInt(26));
// 生成一個處于long整數(shù)取值范圍的偽隨機整數(shù)
System.out.println("rand.nextLong():" + rand.nextLong());
}
}
BigDecimal
float凝垛、double兩種基本浮點類型的浮點數(shù)容易引起精度丟失懊悯。
程序中需要對double浮點數(shù)進行加、減梦皮、乘炭分、除基本運算赴肚,則需要先將double類型數(shù)值包裝成BigDecimal對象隧饼,調(diào)用BigDecimal對象的方法執(zhí)行運算后再將結(jié)果轉(zhuǎn)換成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構(gòu)造器參數(shù):");
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構(gòu)造器參數(shù):");
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));
}
}
注意:創(chuàng)建BigDecimal對象時铸屉,不要直接使用double浮點數(shù)作為構(gòu)造器參數(shù)調(diào)用BigDecimal構(gòu)造器
退子。否則會有精度損失岖妄。
日期時間類
Date類
Date類從JDK1.0起就開始存在了。但正因為它歷史悠久寂祥,所以它的大部分構(gòu)造器荐虐、方法都已經(jīng)過時,不再推薦使用了
Calender類
因為Date類的設(shè)計上存在一些缺陷丸凭,Java提供了Calendar類來更好地處理日期和時間福扬。Calendar是一個抽象類腕铸,它用于表示日歷。
Calendar本身是一個抽象類铛碑,它是所有日歷類的模板狠裹,并提供了一些所有日歷通用的方法,但它本身不能直接實例化汽烦。程序只能創(chuàng)建Calendar子類的實例涛菠,Java本身提供了一個GregorianCalendar類,一個代表Gregorian Calendar的子類撇吞,它代表了我們通常所說的公歷俗冻。
開發(fā)者可以開發(fā)自己的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));
// 分別設(shè)置年牍颈、月迄薄、日、小時煮岁、分鐘讥蔽、秒
c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23
System.out.println(c.getTime());
// 將Calendar的年前推1年
c.add(YEAR , -1); //2002-11-23 12:32:23
System.out.println(c.getTime());
// 將Calendar的月前推8個月
c.roll(MONTH , -8); //2002-03-23 12:32:23
System.out.println(c.getTime());
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23
cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
System.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-29
System.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-23
System.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-28
System.out.println(cal4.getTime());
}
}