Java 取經之路

記錄在java學習和編程過程中的遇到的問題和心得



【1.報錯 】
java.lang.NoSuchMethodError: oracle.i18n.text.converter.CharacterConverterOGS.getInstance(I)Loracle/sql/converter/CharacterConverters;
發生狀態:運行導入的項目,數據導入的是oracle 10g版本中,
解決辦法:orai18n.jar包是oracle11g纔有的,oracle11g之前的jar不叫orai18n.jar,而是nls_charset12.jar。所以在oracle數據庫的安裝目錄下的\jdbc\lib\nls_charset12.jar 拷貝到本項目包中,剔除掉orai18n.jar包。
nls_charset12.jar下載鏈接


【2 eclipse debug時日誌輸出自動保存log】
    經常會遇到這種情況,習慣性的清掉控制檯上的輸出日誌,再然後發現剛纔的日誌居然還有用,不得不又重新調試一遍,爲了解決這種“手賤”的問題,我在網上搜了一些資料,還真解決的方法哈,只需要把日誌同時輸出到設定一個文件就行。方法如下:
    設置Eclipse保存控制檯文件。右鍵項目 -> Debug As -> Debug Configurations菜單。 進入Common標籤下,設置“Standard Input and Output”, 勾選 “File:”, 填寫輸出文件路徑及文件名。如果你勾選了“Append”,輸出的日誌將會被追加寫入到文件最後,否則將會覆蓋重寫文件。
這裏寫圖片描述


【3 java生成指定位數的隨機數】

float Max = 25, Min = 3.0f;  
BigDecimal db = new BigDecimal(Math.random() * (Max - Min) + Min);  
System.out.println(db.setScale(2,BigDecimal.ROUND_HALF_UP).toString());  // 保留2位小數並四捨五入   
db.setScale(2, BigDecimal.ROUND_HALF_UP); 
db.doubleValue();

【4 Java中的編碼 】
    在Java中字符只以一種形式存在,那就是Unicode(不選擇任何特定的編碼,直接使用它們在字符集中的編碼,這是統一的唯一方法。Unicode 是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每個字符設定了統一併且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求)
    但“Java中”到底指的是在哪裏?是指在JVM中、在內存中、在你的代碼裏聲明的每一個char、String類型的變量中。
    JVM 的這種約定使得一個字符分爲兩部分:JVM內部和OS的文件系統。在JVM內部,統一使用U你衝的表示,當這個字符被從JVM內部移到外部(即保存爲文件系統中的一個文件的內容時)就進行編碼轉換,使用了具體的編碼方案。因此可以說所有的編碼轉換隻發生在邊界的地方,JVM和OS的交界處,也就是各種輸入/輸出流(或者Reader、Writer類)起作用的地方。


【5 Java中自加自減運算++、–】
注意:
(1)自增運算符和自減運算符只能用於變量,而不能用於常量或表達式,如5++或(a+b)++都是不合法的。應爲5是常量,常量的值不能改變。(a+b)++也不可能實現,假如a+b的值爲5,那麼自增後得到的6放到什麼地方呢?無變量可供存放!
(2) ++和–的結合方向是“自右向左”(可以參考C語言運算符和結合性表)。一般情況下算數運算符的結合方向爲“自左向右”,如果有-i++,i的左面是負號運算符,右面是自加運算符。如果i的原值等於3,若按照左結合性,相當於(-i)++,而(-i)++是不合法的,應爲對表達式不能進行自加自減運算。
如果有printf(“%d”,-i++);,則先取出i的值3,輸出-i的值-3,然後i增加爲4。
注意-(i++)是先用i的原值3加上負號輸出-3,再對i加1,不要認爲先加完1後再加負號,輸出-4,這是不對的。
(3) 自增(減)運算符常用於循環語句中,使循環變量自動加1;也用於指針變量,使指針變量指向下一個內存地址。更多見關於自增自減運算符的一些問題

例題

public static void main(String[] args) {
    int j=0;
    for(int i=0;i<100;i++)
        j=j++;
    System.out.println(j);//輸出結果爲0;
}

不仔細點很容易認爲結果是100,關鍵在第四行代碼j=j++;j=(j++),分兩步,第一步執行(j++),第二步執行=的賦值運算,將右邊的值再次賦值給j。
對於第一步,j++返回值爲j的原始值(舊值)即0,但此時的j進行了+1變爲了1;對於第二部,又重新對j進行了賦值,將j++的返回值0賦值給了j,所以j還是0。更多見Java中的中間緩存變量機制怎麼理解?


【6 Java中常量問題】
十六進制整型常量:以十六進制表示時,需以0x或0X開頭,如0xff,0X9A。
八進制整型常量:八進制必須以0開頭,如0123,034。
長整型:長整型必須以L作結尾,如9L,342L。
浮點數常量:由於小數常量的默認類型是double型,所以float類型的後面一定要加f(F)。同樣帶小數的變量默認爲double類型。

如:float f;

 f=1.3f;//必須加上f。

字符常量:字符型常量需用兩個單引號括起來(注意字符串常量是用兩個雙引號括起來)。Java中的字符佔兩個字節。一些常用的轉義字符:

①\r表示接受鍵盤輸入,相當於按下了回車鍵;
②\n表示換行;
③\t表示製表符,相當於Table鍵;
④\b表示退格鍵,相當於Back Space鍵;
⑤\'表示單引號;
⑥\''表示雙引號;
⑦\\表示一個斜槓\。

【7 Java 長整型】
MICROS_PER_DAY表示一天的微秒數
MILLIS_PER_DAY表示一天的毫秒數
然後下面例子的結果是多少呢?

public class Test3 {
    public static void main(String[] args) {
        final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
        final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
        System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
    }
}

So easy
數據類型爲 long ,很容易保存這兩個乘積不產生溢出.
因此,結果肯定是 1000!
but…..
結果是: 5
這裏寫圖片描述

解釋:
爲什麼答案與我們想象不一樣呢?
因爲數據溢出了…
你在逗我? 但我沒學過java?
long能表示 -2的63次方到2的63次方-1的整數.
數都數不過來,怎麼會溢出?
哈哈,小心陷阱啊,雖然我們定義的是long類型,
準確的說最終的結果應該是long類型的.

我們看看表達式右邊,
24 * 60 * 60 * 1000 * 1000
這個表達式是以int類型作爲運算的,
int跟int類型相乘,結果還是int類型,
最終結果超過int所能保存的範圍,所以數據溢出了,
然後才被long所保存;

改進

24 * 60 * 60 * 1000 * 1000–>24L * 60 * 60 * 1000 * 1000

在表達式隨便哪個數值後面加上一個l或者L就搞定了,
其結果會自動轉換爲long而不是int了,然後再保存到long類型變量中.
就是這麼簡單,就是這麼任性。


【8 Java 的控制檯輸入】
System.in
Scanner

System.in.read()一次只讀入一個字節數據,而我們通常要取得一個字符串或一組數字
System.in.read()返回一個整數
Scanner 可以取得一個字符串或一組數字
Scanner默認使用Whitespace(即空白字符[空格,TAB和回車])作爲結束符。

Scanner oin=new Scanner(System.in);
String  string=oin.next();

/*delimiter()返回此 Scanner當前正在用於匹配分隔符的 Pattern
默認分隔符輸出爲'\p{javaWhitespace}+'
等效於 java.lang.Character.isWhitespace()*/

System.out.println(oin.delimiter());
oin.useDelimiter(" |,|\\.");//指定 新的分隔符
System.out.println(oin.delimiter());

/*在新增一個Scanner對象時需要一個System.in對象,
因爲實際上還是System.in在取得用戶輸入。
Scanner的next()方法用以取得用戶輸入的字符串;
nextInt()將取得的輸入字符串轉換爲整數類型;
同樣,nextFloat()轉換成浮點型;
nextBoolean()轉換成布爾型。*/

更過分析見
①java 中的Scanner(非常詳細不看後悔)
②Scanner JavaAPI
③java 標準輸入System.in
④Java中從控制檯輸入數據的幾種常用方法


【9 Java反射,參數爲數組】

class A{
    private void sayHello(String[] names){
        //...
        System.out.println("sayHello invoked");
    } 
}

String[] names = new String[]{"A", "B", "C"};
Method sayHello = A.class.getDeclaredMethod("sayHello", String[].class);
sayHello.setAcess(true);
sayHello.invoke(new A(), new Object[]{names});

這裏有兩個地方需要注意

1.A.class.getDeclaredMethod時後面的參數是數組,用加[];
2.sayHello.invoke調用時直接傳一個String[]實例會報異常,需要再次用Object[]包裝一下;


【10 Scanner類nextInt之後用nextLine無法讀取輸入】
問題描述:做搜狐筆試一道編程題時,輸入是首先一整數n佔一行,接着n行字符串如下:

3
hello
your 
my

首先,Scanner是一個掃描器,它掃描數據都是去內存中一塊緩衝區中進行掃描並讀入數據的,而我們在控制檯中輸入的數據也都是被先存入緩衝區中等待掃描器的掃描讀取。這個掃描器在掃描過程中判斷停止的依據就是“空白符”,空格啊,回車啊什麼的都算做是空白符。
nextInt()方法在掃描到空白符的時候會將前面的數據讀取走,但會丟下空白符“\r”在緩衝區中,但是,nextLine()方法在掃描的時候會將掃描到的空白符一同清理掉。
瞭解了這兩個方法特性和區別,就知道了上邊的代碼究竟是怎麼回事,以及知道了解決的方法。像是上邊的代碼nextInt()方法之後在緩衝區中留下了“\r”,然後nextLine()方法再去緩衝區找數據的時候首先看到了“\r”,然後就把這個“\r”掃描接收進來,並在緩衝區內清除掉。
解決辦法:
1.可以再nextInt()方法後面多加一句nextLine()方法專門用來取出緩衝區中留下的空白符
2.可以只用nextLine()方法,然後通過Integer類中的parseInt()方法解析成int數據。因爲nextLine()方法會自動清理掉後邊的空白符。
更多詳細見
java中Scanner類nextInt之後用nextLine無法讀取輸入

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章