天天看点

java面向对象面试题_Java面向对象面试题

1. Java面向对象的知识结构

1.1 Java语法以及关键字、如接口与类、内部类,final/finally/finalize, throw/throws,域访问符权限等;

1.2 Java面向对象思想以及体系,例如设计思想。

2. 经典面试题

2.1 Java 有没有 goto? 如果有,一般用在什么地方?如果没有,如何跳出当前的多重嵌套循环?

goto是Java中的保留字,在目前Java版本中没有使用。

在Java中跳出多重循环的的方法有三种:

1. break + 标签,在外层循环前加上一个标签lable,

然后在最里层循环使用 break lable.

public static void main(String[] args) {

label: //标记

for (int i = 0 ; i < 10; i++) {

for (int j = 0; j < 10; j++) {

System.out.println("i = " + i + ", j = " + j);

if(j == 5) { //满中一定条件跳到某个标记

break label;

}

}

}

}

2. 通过异常捕获

public static void main(String[] args) {

try {

for (int i = 0; i < 10; i++) {

for (int j = 0; j < 10; j++) {

System.out.println("i = " + i + ", j = " + j);

if (j == 5) {// 满足一定条件抛异常

throw new RuntimeException("test exception for j = 5");

}

}

}

} catch (RuntimeException e) { //循环外层捕获异常

e.printStackTrace();

}

}

3. 通过标置变量

public static void main(String[] args) {

boolean flag = false; //初始化标置变量

for (int i = 0; i < 10; i++) {

for (int j = 0; j < 10; j++) {

System.out.println("i = " + i + ", j = " + j);

if (j == 5) { //满足一定条件进行设置标置变量

flag = true;

}

if (flag) { //内层循环判断标置变量

break;

}

}

if (flag) {//外层循环判断标置变量

break;

}

}

}

2.2 抽象类(abstract class)和接口(interface)有什么异同?

相同点

1. 不能直接实例化。如果要实例化,抽象变量必须实现所有抽象方法,接口变量必须实现接口未实现的方法。

2. 都可以有实现方法(Java1.8之前不能有实现方法)

3. 都可以不需要实现类或者继承者去实现所有方法(Java8 以前的接口,Java8 及以后的接口中可以包括默认方法,不需要实现者实现)。

不同点

1. 抽象类和接口所反映的设计理念不同,抽象类表示的是对象/类的抽象,接口表示的是行为的抽象。

2. 抽象类不可以多重继承,接口可以多重继承。即一个类只能继续一个抽象类,却可以继承多个接口。

3. 抽象类中的方法可以用 public protected 和 default abstract 修饰符,不能用 private、static、synchronize、native 修饰;变量可以在子类中重新定义,也可以重新赋值;

接口的方法默认修饰符是 public abstract, Java8 开始出现静态方法,多加 static 关键字;变量默认是 public static final 型,且必须给其初值,在实现类中也不能重新定义,也不能改变其值。

4. 抽象类可以有构造器,接口没有构造器。

2.3 Java 创建对象的方式有哪些?

1. 使用 new关键字

2. 反射创建,使用java.lang.Class 类的newInstance 方法

这种方式会调用无参的构造函数来创建对象,有两种实现方式。

//方式一,使用全路径包名

User user = (User)Class.forName("com.imooc.interview.demo.User").newInstance();

//方法二,使用class类

User user = User.class.newInstance();

反射,使用 java.lang.reflect.Constructor 类的 newInstance 方法。

Constructor constructor = User.class.getConstructor();

User user = constructor.newInstance();

使用 clone 方法。

public class User implements Cloneable {

public User(Integer age) {

this.age = age;

}

public Integer getAge() {

return age;

}

private Integer age;

// 重写(Overriding)Object的clone方法

@Override

protected User clone() throws CloneNotSupportedException {

return (User) super.clone();

}

public static void main(String[] args) throws Exception {

User person = new User(new Integer(200));

User clone = person.clone();

System.out.println("person == clone, result = " + (person == clone)); // false,拷贝都是生成新对象

System.out.println("person.age == clone.age, result = " + (person.getAge() == clone.getAge())); // true,浅拷贝的成员变量引用仍然指向原对象的变量引用

}

}

浅拷贝和深拷贝

浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,对拷贝后对象的引用仍然指向原来的对象。

深拷贝:不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。

3. 使用反序列化。

为了序列化 / 反序列化一个对象,需要该类实现空接口 Serializable

序列化时首先创建一个输出流对象 oos, 使用 oos 的 writeObject () 方法将 p 对象写入 oos 对象中去。使用反序列化创建对象时,首先创建一个输入流对象 ois,使用输入流对象 ois 的 readObject () 方法将序列化存入的对象读出,重新创建一个对象。

序列化是深拷贝。