假設有這樣一個案例,我們有一個file文件,裏面有a b c d e f g h i j 一共10條數據,我們需要以4條爲一批,分成3批處理,即第一批是a b c d,第二批數據是e f g h,第三批數據是i j,所以樓主採用Map<Integer, List<TSSBBody>>方式裝數據,有多少批數據,就有多少個鍵值對,至於List的size(),必然是4 4 2,這種理解起來,比較簡單,所以開始擼代碼:
// 判斷一個file文件有多少行
public long getLineNumber(File file) {
if (file.exists()) {
try {
FileReader fileReader = new FileReader(file);
LineNumberReader lineNumberReader = new LineNumberReader(fileReader);
lineNumberReader.skip(Long.MAX_VALUE);
long lines = lineNumberReader.getLineNumber() + 1;
fileReader.close();
lineNumberReader.close();
return lines;
} catch (IOException e) {
e.printStackTrace();
}
}
return 0;
}
public static void main(String[] args) throws InterruptedException {
int TD_PileSize = 4;
File file = new File("E:\\ceshi\\1.txt");
long lineNumber = new Test().getLineNumber(file);
int DataTotal = Integer.valueOf(String.valueOf(lineNumber));
// 分多少批到特色獲取數據
int pageCount = (int) Math.ceil((double) DataTotal / TD_PileSize);
if (DataTotal == 0) {
System.out.println("沒有需要推送的數據");
}
System.out.println("需要推送的數據有" + DataTotal + "條,分" + pageCount + "批推送!");
InputStreamReader inputReader = null;
BufferedReader bufferReader = null;
OutputStream outputStream = null;
try {
InputStream inputStream = new FileInputStream(file);
inputReader = new InputStreamReader(inputStream, "GBK");
bufferReader = new BufferedReader(inputReader);
// 讀取一行
String line = null;
Map<Integer, List<TSSBBody>> map = new HashMap<Integer, List<TSSBBody>>();
List<TSSBBody> listBody = new ArrayList<TSSBBody>();
if (DataTotal < TD_PileSize | DataTotal == TD_PileSize) {
while ((line = bufferReader.readLine()) != null) {
TSSBBody body = null; // 爲了不報錯 填null 實際是處理line 轉化爲對象
listBody.add(body);
}
map.put(0, listBody);
} else {
int lineNum = 0;
int mapNum = 0;
while ((line = bufferReader.readLine()) != null) {
lineNum++;
TSSBBody body = null; // 爲了不報錯 填null 實際是處理line 轉化爲對象
listBody.add(body);
if (lineNum % TD_PileSize == 0) {
mapNum++;
map.put(mapNum - 1, listBody);
System.err.println("清空前==" + listBody.size());
listBody.clear();
}
}
map.put(mapNum, listBody);
System.out.println("mapNum============" + mapNum); //值=2
for (Map.Entry<Integer, List<TSSBBody>> a : map.entrySet()) {
System.err.println("" + a.getKey());
for (TSSBBody ttBody : a.getValue()) {
System.err.println(ttBody.toString());
}
}
}
} catch (IOException e) {
System.out.println("" + e.getMessage());
} finally {
IOCloseUtil.closeAll(outputStream, bufferReader, inputReader);
}
}
其實代碼邏輯很好理解,當讀取4行倍數時,就執行賦值list,然後賦值給map,然後clear()重新賦值,理解起來覺得沒毛病,其實問題大了去了,執行代碼跟蹤,發現map遍歷,list的值都是i j,很奇怪是不是??
我們把listBody.clear()這句話改成:
listBody = null;
listBody = new ArrayList<TSSBBody>();
這兩句,問題就解決了。然後仔細一想,這不就是Java中的值引用還是對象引用的問題嗎?
值傳遞(形參類型是基本數據類型):方法調用時,實際參數把它的值傳遞給對應的形式參數,形式參數只是用實際參數的值初始化自己的存儲單元內容,是兩個不同的存儲單元,所以方法執行中形式參數值的改變不影響實際參數的值。
引用傳遞(形參類型是引用數據類型):也稱爲傳地址,方法調用時,實際參數是對象(或數組),這時實際參數與形式參數指向同一個地址,在方法執行中,對形式參數的操作實際上就是對實際參數的操作,這個結果在方法結束後被保留了下來,所以方法執行中形式參數的改變將會影響實際參數。
所以,通過clear方法清除之後再加入map,實際上所有的list都是同一個對象, 指向了同一個地址,這樣list裏的值就是最後一次加入list的元素,所以clear後,其實List自始至終都是通過一個對象,自然map的值都是i j。但是new不一樣,new的話就有多個對象,改這個list並不會影響另一個。