從這期開始,我會陸續整理與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經典知識點以及面試題就到這裏了,我們下期再見哈!