Java經典知識點&面試題整理01

從這期開始,我會陸續整理與Java相關的重要知識點,這些知識點與一些面試題也會相關聯,基本我每一期的話,以5道題爲主,然後我會認真的對每一道題進行講解。

1.尋找200以外的最小質數。

本題提供兩種解法,首先法一較爲簡單,大部分人也能想到,從200開始遍歷,依次查詢,設置一個flag作爲標誌進行判斷,代碼如下:

public class FindPrime {

	public static void main(String[] args) {
		int num=200;
		boolean flag;
		do {
			num++;
			flag=false;
			for (int i = 2; i < num; i++) {
				if (num%i==0) {
					flag=true;
					break;
				}
			}
		} while (flag);
		System.out.println(num);
	}
}

上述方法比較常規,do...while...語句循環結束的標誌是flag=false,即不存在任何大於等於2的因子能被num整除,得出的結果是211,下面介紹第二種解法,代碼如下:

public class FindPrime {
	
	/**
	 * 判斷是質數的方法
	 * @param n
	 * @return
	 */
	public static boolean isPrime(int n) {
		//把所有大於2的偶數先排除
		if(n>2 && (n&1) == 0)
			return false;
		/* 運用試除法:
		 * 1.只有奇數需要被測試
		 * 2.測試範圍從2與根號{n},反之亦然 */
		for(int i=3; i<=Math.sqrt(n); i+=2)
			if (n%i == 0) 
				return false;
		    return true;
		}
	
	public static void main(String[] args) {
		boolean flag = false;
		 for(int i=200;;i++){
		     if(isPrime(i)){        
		    	 System.out.print("200外的最小質數是:"+i);
		    	 flag = true;
		     }
		     if(flag == true)
		    	 break;
		 }     
	}
}

這種解法較前一種解法可能稍微煩一點,但是我們理解之後就會感覺並不難懂。我們寫一個函數用於判斷是否是質數,該方法首先把大於2的偶數先排除掉,然後從3開始遍歷,每次加2,如果有因子能夠被n整除,那麼返回false,否則返回true。

2.比較數組複製中ArrayCopy,CopyOf以及CopyOfRange函數的區別。

下面我以一個Demo來講解各自的用法,代碼如下:

import java.util.Arrays;

public class ArrayCopy {

	public static void main(String[] args) {
		int[] a = new int[] {1,2,3,4,5};
		int[] b = {6,7,8,9,10,11,12,13,14,15};
		//把a數組從下標0開始,複製到b數組,長度爲5
		System.arraycopy(a, 0, b, 0, 5);
		for(int i : b) {
			System.out.print(i+" ");
		}
		System.out.println();
		//把長度前3的a數組複製到c數組
		int[] c = new int[3];
		c = Arrays.copyOf(a, 3);
		System.out.println(Arrays.toString(c));
		int[] d = new int[3];
		//該方法是從a數組的下標from開始複製,到下標to結束
		d = Arrays.copyOfRange(a, 1, 4);
		System.out.println(Arrays.toString(d));
	}
}

運行結果是:

1 2 3 4 5 11 12 13 14 15 
[1, 2, 3]
[2, 3, 4]

①:arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length)函數,src代表原數組名,srcPos代表原數組起始下標,dest代表目標數組,destPos代表目標數組起始下標,length表示複製數組的長度,在這個例子中,我們把整個數組a複製到了數組b中下標0-4共5個元素;

②:copyOf(int[] original, int newLength)函數,該函數實際也是調用了arraycopy函數,original表示原始數組名,newLength代表複製的數組長度,這裏的例子我們是把數組a前三個元素複製到數組c中去,我們可以查看一下底層源碼,如下:

 public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

③:copyOfRange(int[] original, int from, int to)函數,該函數也是調用了arraycopy函數,orinigal表示原始數組名,from表示起始下標,to表示末尾下標,這裏的例子是把數組a中從下標1-4(不包含4)中的元素複製到d數組,我們也查看一下該函數底層源碼,如下:

 public static int[] copyOfRange(int[] original, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        int[] copy = new int[newLength];
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }

這裏我們調用了Arrays中的toString方法,我們可以查看一下其方法的底層源碼,如下:

 public static String toString(int[] a) {
        if (a == null)
            return "null";
        int iMax = a.length - 1;
        if (iMax == -1)
            return "[]";

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(a[i]);
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");
        }
    }

3.請簡述static的常見用法。

static的用法包含靜態屬性,靜態方法以及靜態代碼塊。下面我們一個Demo來展示其具體的用法,代碼如下:

public class StaticDemo {
	
	//常量
	static final double PI = 3.14;
	private String name;
	static int num;

	static {
		System.out.println("這裏是靜態代碼塊");
		System.out.println(num);
	}

	static void hello() {
		System.out.println("靜態方法");
	}

	public static void main(String[] args) {
		// 所有對象共享 num
		// 靜態變量訪問方式 1. 先實例化對象 使用對象名.屬性名
		// 2. 直接調用 類名.屬性名
		StaticDemo sd1 = new StaticDemo();
		StaticDemo sd2 = new StaticDemo();
		System.out.println(sd1.num);//0
		System.out.println(sd2.num);//0
		System.out.println(num);//0
		// 非當前類調用 static修飾的變量
		System.out.println(StaticDemo.num);//0
		hello();
	}

}

注意static只能修飾成員,不能修飾局部變量,上述代碼就不作過多解釋了,static代碼塊中的內容先執行,然後對於靜態屬性num,可以直接調用,也可以類名.num進行調用。

4.舉例說明什麼是單例模式,以及其具體的用法。

我們以具體的例子進行說明單例模式的用法,新建一個UserService接口,包含登錄以及註冊的抽象方法,如下:

public interface UserService {
	
	//用戶註冊功能
	public boolean register(String name,String pwd);
	//用戶登錄功能
	public String login(String name,String pwd);
}

然後就是新建UserServiceImpl類,實現UserService接口,該類運用了單例模式,其特點是:①定義一個私有的構造方法,不讓其他類直接實例化;②定義一個私有的靜態對象,外部訪問不到,並且static只創建一次,全部對象共享;③定義一個公有的靜態方法,讓其他類可以進行訪問。具體代碼如下:

public class UserServiceImpl implements UserService {
	
	//有一個私有的構造方法,不讓別的類直接進行實例化
	private UserServiceImpl () {
		System.out.println("使用單例模式進行改造!");
	}
	
	//私有的靜態變量,外部訪問不到;利用static只創建一次,全部對象共享;
	private static UserServiceImpl instance = new UserServiceImpl();
	
	//提供一個公關的靜態方法,讓其他類訪問
	public static UserServiceImpl getInstance() {
		return instance;
	}

	@Override
	public boolean register(String name, String pwd) {
		System.out.println("單例註冊!");
		return false;
	}

	@Override
	public String login(String name, String pwd) {
		System.out.println("單例登錄!");
		return null;
	}

}

然後我們新建一個測試類TestSingleton,代碼如下:

public class TestSingleton {

	public static void main(String[] args) {
		for(int i=1;i<=10;i++) {
			UserService service = UserServiceImpl.getInstance();
			service.login("chen", "123");
		}
	}

}

運行結果如下:

使用單例模式進行改造!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!
單例登錄!

從結果我們也可以發現,構造方法只調用了一次,這就是單例模式最顯著的特徵。

5.什麼是抽象類,什麼情況下一個類必須聲明爲抽象類?

抽象類是抽象方法和非抽象方法的集合,如果全部方法都是抽象方法,那麼用interface替代abstract,在以下情況一個類必須聲明爲抽象類:

含有一個或多個抽象方法時

當一個類是抽象類的子類,但並沒有繼承父類所有的抽象方法時

當一個類實現了一個接口,但並沒有實現所有抽象方法時

這裏就不做代碼演示了,這裏相對簡單一些,好了,第一期Java經典知識點以及面試題就到這裏了,我們下期再見哈!

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