从这期开始,我会陆续整理与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经典知识点以及面试题就到这里了,我们下期再见哈!