1. 程式人生 > >牛客網(題目的回答大多數來自他人見解,少部分個人領悟)

牛客網(題目的回答大多數來自他人見解,少部分個人領悟)

2017.11.4

1.一個檔案中的字元要寫到另一個檔案中,首先需要( )

使用標準輸出流System.out.println()。
建立檔案字元輸出流。
建立檔案字元輸入流。
標準輸入流System.in.read()。
網友回答的:一個檔案中的字元要寫到另一個檔案中,首先要讀出來,然而對計算機而言,input就是讀進來(外面送進來),out就是寫出去(裡面往外面寫),一個檔案寫到另外一個檔案,所以我們需要先讀取這個檔案,也就是建立字元輸入流。
package com.te;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;

public class InPutcopy {

	public static void main(String[] args) throws IOException {
		
		
		// TODO Auto-generated method stub
		
		File file=new File("C:\\Users\\絕影\\Desktop\\桌面.txt");//建立一個新的file例項
		
		//讀出對應輸入流
		InputStream input = null;
		OutputStream out = null;
		InputStreamReader inp=null;
		OutputStreamWriter inp1=null;
		BufferedReader reader=null;
		BufferedWriter write=null;
		try {
			input = new FileInputStream(file);
			FileReader filer=new FileReader(file);
			inp=new InputStreamReader(input);//位元組流字元流轉化的橋樑
			
			 reader = new BufferedReader(filer);//緩衝讀取字元 將位元組流封裝成BufferedReader物件
			
			
			
			File fi=new File("C:\\Users\\絕影\\Desktop\\7777.txt");
			//寫入對應輸出流
			out=new FileOutputStream(fi);//建立檔案位元組輸出流
			
			
			FileWriter filer1=null;
			try {
				filer1 = new FileWriter(fi);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			 inp1=new OutputStreamWriter(out);//位元組流字元流轉化的橋樑
			
			 write=new BufferedWriter(filer1);//緩衝寫入字元 將位元組流封裝成BufferedReader物件
			
			char a[]=new char[21];
			byte b[]=new byte[21];
			input.read(b);//放入位元組陣列  
			//位元組陣列的read方法的原始碼,下面可知input.read(b)不會導致陣列越界,就是擔心檔案內容放不了進入陣列的情況,因為這個read方法本身
			//陣列放入多少是已經固定的,並非將檔案內容一下子全部放入,所以不會有越界情況
			/*public int read(byte b[]) throws IOException {
				          return read(b, 0, b.length);
				      }
				      
				      *
				      */
			reader.read(a);//放入字元陣列,同理不會因為檔案裡面的字元大於陣列長度越界
			
			
			String line="";
			while((line=reader.readLine()) != null){//一個檔案內容讀入到另外一個
				//write.write(line);
				write.write(line);  
				 //使用緩衝區中的方法將資料寫入到緩衝區中。  
				//write.flush(); 如何finally中沒有關閉流這裡沒有這一句會造成檔案沒有寫入
				System.out.println(line);//這裡也只是輸出後半句
			}
			
			
			
			for(int i=0;i<21;i++) {
				System.out.println(b[i]);//48---57
				System.out.println(a[i]);//這裡不懂,BufferedReader中的引數換inp前面的部分字元沒有輸出
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			reader.close();
			write.close();//這裡把輸出流關閉也會和write.flush()一樣的效果,有點類似資料庫的事務提交
		}
		
		
		
        
	}

}


2.以下多執行緒對int型變數x的操作,哪個不需要進行同步()

++x
x=y
x++
x=1

ABC不是原子性操作,例如想x++,先獲取x的值,自增一,然後再把值賦給x,三步,中間任何一步執行時都可能被其他執行緒訪問或者修改。所以需要同步。

package com.te;

public class Multiplythread extends Thread{
	static int i=0;//多執行緒呼叫
	static int j=0;
	
	@Override
	public  void run() {
		System.out.println(this);
		++i;	
	}
	
	public  void runn() {
		++j;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		for(int i=0;i<1000;i++) {
			Multiplythread th=new Multiplythread();//執行緒1
		    th.start();
		    th.runn();
		   // System.out.println(i);
		}
		/*
		 * 輸出結果不確定(因為對於++i這一步不是原子操作,實際上分為了三步,
		每個java執行緒都有一份自己的工作記憶體,執行緒訪問變數的時候,不能直接訪問主記憶體中的變數,而是先把主記憶體的變數複製到自己的工作記憶體,然後操作自己工作記憶體裡的變數,最後再同步給主記憶體。
		現在就可以解釋為什麼5個執行緒執行a++最後結果不一定是5了,因為a++可以分解為3步操作:
		1.把主記憶體裡的a複製到執行緒的工作記憶體
		2.執行緒對工作記憶體裡的a執行a=a+1
		3.把執行緒工作記憶體裡的a同步回主記憶體,由於在這過程中執行緒是同步的,沒有先後執行順序),這裡需要上面執行緒多一點效果才明顯
		*/
		//我們理想輸出的是1000,但是會出現不同結果.因為假設執行緒1先執行,當它執行完1,2時,到第二個執行緒開始跑,第二個執行緒成功執行完1,2,3然後執行緒1獲得cpu,繼續執行第三把自己工作記憶體裡的變數,再同步給主記憶體
		//同步過去i的值是1,而執行緒2執行同步的值也是1,此時類變數i就是1,而不是我們想要的結果2
		System.out.println("我是來看看終極i的值是:"+Multiplythread.i);
		//不受執行緒控制的變數j就是輸出1000
		System.out.println("我是來看看終極j的值是:"+Multiplythread.j);
	}

}

3.關於匿名內部類敘述正確的是? ( )

正確答案: B   你的答案: A (錯誤)

匿名內部類可以繼承一個基類,不可以實現一個介面
匿名內部類不可以定義構造器
匿名內部類不能用於形參
以上說法都不正確
網友答案: 匿名內部類的建立格式為: new 父類構造器(引數列表)|實現介面(){                                              //匿名內部類的類體實現 }
  1. 使用匿名內部類時,必須繼承一個類或實現一個介面
  2. 匿名內部類由於沒有名字,因此不能定義建構函式
  3. 匿名內部類中不能含有靜態成員變數和靜態方法

A.建構函式可以省略,省略建構函式則new物件例項時,所有的資料型別賦值為0,bool型別賦值為FALSE,引用型別賦值為NULL。 B.建構函式必須與類同名,而且不能有返回型別。而方法是可以與類同名的,但是必須宣告返回資料型別。 C.正確,當new物件是首先呼叫靜態初始資料塊(可省略),然後呼叫父類建構函式(不是子類則不呼叫),最後呼叫自己的建構函式(一定呼叫),這樣才能生成一個物件的例項。 D.建構函式是可以過載的,過載的要求是引數不同。 4.下面不是面向物件的基本原則的是?

正確答案: C   你的答案: E (錯誤)

單一職責原則(Single-Resposibility Principle)
開放封閉原則(Open-Closed principle)
抽象類原則(Abstract-Class principle)
依賴倒置原則(Dependecy-Inversion Principle)
介面隔離原則(Interface-Segregation Principle)

s( Single-Resposibility Principle ): 單一職責原則 o( Open-Closed principle ): 開放封閉原則 l( Liskov-Substituion Principle ): 里氏原則 i( Interface-Segregation Principle ): 介面隔離原則 d( Dependecy-Inversion Principle ): 依賴倒置原則 一個單詞:立方體(solid),很好記!!!
單一職責原則(Single-Resposibility Principle):一個類,最好只做一件事,只有一個引起它的變化。單一職責原則可以看做是低耦合、高內聚在面向物件原則上的引申,將職責定義為引起變化的原因,以提高內聚性來減少引起變化的原因。
開放封閉原則(Open-Closed principle):軟體實體應該是可擴充套件的,而不可修改的。也就是,對擴充套件開放,對修改封閉的。
Liskov替換原則(Liskov-Substituion Principle):子類必須能夠替換其基類。這一思想體現為對繼承機制的約束規範,只有子類能夠替換基類時,才能保證系統在執行期內識別子類,這是保證繼承複用的基礎。
依賴倒置原則(Dependecy-Inversion Principle):依賴於抽象。具體而言就是高層模組不依賴於底層模組,二者都同依賴於抽象;抽象不依賴於具體,具體依賴於抽象。
介面隔離原則(Interface-Segregation Principle):使用多個小的專門的介面,而不要使用一個大的總介面
下列哪個說法是正確的()

正確答案: D   你的答案: B (錯誤)

ConcurrentHashMap使用synchronized關鍵字保證執行緒安全
HashMap實現了Collction介面
Array.asList方法返回java.util.ArrayList物件
SimpleDateFormat是執行緒不安全的

A選項中,ConcurrentHashMap 使用segment來分段和管理鎖,segment繼承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock來保證執行緒安全。

B中,HashMap定義規則如下:

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
C中,應該是Arrays.asList(),其將一個數組轉化為一個List物件,這個方法會返回一個ArrayList型別的物件, 這個ArrayList類並非java.util.ArrayList類,而是Arrays類的內部類:  A、ConcurrentHashMap實際上時 HashTable的升級版,使用segment來分段和管理鎖,並不是synchronized; B、 HashMap實現的介面有:Serializable, Cloneable, Map<K,V> ,沒有實現Cllectio C、Arrays.asList()方法返回的列表是Arrays.ArrayList型別的,並不是java.util.ArrayList;
JAVA反射機制主要提供了以下哪些功能?

正確答案: A B C D   你的答案: A B C (錯誤)

在執行時判斷一個物件所屬的類
在執行時構造一個類的物件
在執行時判斷一個類所具有的成員變數和方法
在執行時呼叫一個物件的方法
普通的java物件是通過new關鍵字把對應類的位元組碼檔案載入到記憶體,然後建立該物件的。 反射是通過一個名為Class的特殊類,用Class.forName("className");得到類的位元組碼物件,然後用newInstance()方法在虛擬機器內部構造這個物件(針對無參建構函式)。 也就是說反射機制讓我們可以先拿到java類對應的位元組碼物件,然後動態的進行任何可能的操作, 包括
  • 在執行時判斷任意一個物件所屬的類
  • 在執行時構造任意一個類的物件
  • 在執行時判斷任意一個類所具有的成員變數和方法
  • 在執行時呼叫任意一個物件的方法
這些都是反射的功能。 使用反射的主要作用是方便程式的擴充套件。
關於ThreadLocal 以下說法正確的是

正確答案: D E   你的答案: A B C E (錯誤)

ThreadLocal繼承自Thread
ThreadLocal實現了Runnable介面
ThreadLocal重要作用在於多執行緒間的資料共享
ThreadLocal是採用雜湊表的方式來為每個執行緒都提供一個變數的副本
ThreadLocal保證各個執行緒間資料安全,每個執行緒的資料不會被另外執行緒訪問和破壞
1、ThreadLocal的類宣告: public class ThreadLocal<T> 可以看出ThreadLocal並沒有繼承自Thread,也沒有實現Runnable介面。所以AB都不對。 2、ThreadLocal類為每一個執行緒都維護了自己獨有的變數拷貝。每個執行緒都擁有了自己獨立的一個變數。 所以ThreadLocal重要作用並不在於多執行緒間的資料共享,而是資料的獨立,C選項錯。 由於每個執行緒在訪問該變數時,讀取和修改的,都是自己獨有的那一份變數拷貝,不會被其他執行緒訪問, 變數被徹底封閉在每個訪問的執行緒中。所以E對。 3、ThreadLocal中定義了一個雜湊表用於為每個執行緒都提供一個變數的副本:  static class ThreadLocalMap {         static class Entry extends WeakReference<ThreadLocal> {             /** The value associated with this ThreadLocal. */             Object value;             Entry(ThreadLocal k, Object v) {                 super(k);                 value = v;             }         }         /**          * The table, resized as necessary.          * table.length MUST always be a power of two.          */         private Entry[] table; }