Java面试基础:面向对象(2)
1. 接口里可以定义哪些方法
抽象方法:抽象方法是接口的核心部分,所有实现接口的类都必须实现这些方法。抽象方法默认是 public 和 abstract 修饰,这些修饰符可以省略。
public interface Animal {void Sound();
}
默认方法:默认方法是在Java8中引入的,允许接口提供具体的实现。实现类可以重写默认方法。
public interface Animal {void Sound();default void eat() {System.out.println("Eating...")}
}
静态方法:静态方法也是中Java8中引入的,属于接口本身,可以通过接口名来直接调用,不需要实现类的对象。
public interface Animal {void Sound();static void staticMethod() {System.out.println("Static method...")}
}
私有方法:私有方法是在Java9中引入的,用于在接口中为默认方法或其他私有方法提供辅助功能。这些方法不能被实现类访问,而是只能在接口内部使用。
public interface Animal {void Sound();default void eat() {System.out.println("Eating...")}private void sleep() {System.out.println("Sleeping...")}
}
2. 接口可以包含构造函数吗
在接口中,不可以有构造方法,在接口里写入构造方法时,编译器会提示:Interface cannot have constructors,因为接口不会有自己的实例,所以不需要有构造函数。
主要原因是构造函数就是初始化 class 的属性或者方法,在 new 的瞬间自动调用,接口都不能 new 实例化,所以就无法调用,因此没有构造函数。
3. 解释Java中的静态变量和静态方法
在Java中静态变量和静态方法是与类本身关联的,而不是与类的实例 (对象) 关联。
它们在内存中只存在一份,可以被类的所有实例共享。
静态变量:
静态变量 (也称为类变量) 是在类中使用 static 关键字声明的变量。它们属于类而不是任何具体的对象。主要的特点有 :
- 共享性: 所有该类的实例共享同一个静态变量。如果一个实例修改了静态变量的值,其他实例也会看到这个更改。
- 初始化: 静态变量在类被加载时初始化,只会对其进行一次分配内存。
- 访问方式: 静态变量可以直接通过类名访问,也可以通过实例访问,但推荐使用类名。
public class Myclass {// 静态变量static int staval = 0;public Myclass() {// 每创建一个对象,静态变量自增staval++;}public static void printStaVal() {System.out.println("Static Val:" + staval);}
}// 示例:
MyClass a1 = new MyClass();
MyClass a2 = new MyClass();
MyClass.printStaVal(); // 输出 Static Val: 2
静态方法:
静态方法是在类中使用 static 关键字声明的方法。类似于静态变量,静态方法也属于类,而不是任何具体的对象。主要的特点:
- 无实例依赖: 静态方法可以在没有创建类实例的情况下调用。对于静态方法来说,不能直接访问非静态的成员变量或方法,因为静态方法没有上下文的实例。
- 访问静态成员: 静态方法可以直接调用其他静态变量和静态方法,但不能直接访问非静态成员。
- 多态性: 静态方法不支持重写 (Override),但可以被隐藏 (Hide)。
public class Myclass {// 静态变量static int staval = 0;// 静态方法public static void stavalIncrement() {staval++;}// 静态方法public static void printStaVal() {System.out.println("Static Val:" + staval);}
}// 示例:
MyClass.stavalIncrement();
MyClass.printStaVal(); // 输出 Static Val: 1
使用场景:
- 静态变量: 常用于需要在所有对象间共享的数据,如计数器、常量等。
- 静态方法: 常用于助手方法 (utility methods)、获取类级别的信息或者是没有依赖于实例的数据处理。
4. 非静态内部类和静态内部类的区别
- 非静态内部类依赖于外部类的实例,而静态内部类不依赖于外部类的实例。
- 非静态内部类可以访问外部类的实例变量和方法,而静态内部类只能访问外部类的静态成员。
- 非静态内部类不能定义静态成员,而静态内部类可以定义静态成员。
- 非静态内部类在外部类实例化后才能实例化,而静态内部类可以独立实例化。
- 非静态内部类可以访问外部类的私有成员,而静态内部类不能直接访问外部类的私有成员,需要通过实例化外部类来访问。
5. 非静态内部类可以直接访问外部方法,编译器是怎么做到的
非静态内部类可以直接访问外部方法是因为编译器在生成字节码时会为非静态内部类维护一个指向外部类实例的引用。
这个引用使得非静态内部类能够访问外部类的实例变量和方法。编译器会在生成非静态内部类的构造方法时,将外部类实例作为参数传入,并在内部类的实例化过程中建立外部类实例与内部类实例之间的联系从而实现直接访问外部方法的功能。
6. Java中 final 的作用是什么
final 关键字在Java中主要有三个方面的作用:修饰类、修饰方法、修饰变量。
修饰类:当 final 修饰一个类是,表示这个类不能被继承,是类继承体系中的最终形态。
例如:Java中的 String 类就是用 final 修饰的,这保证了 String 类的不可变性和安全性,可以防止其他类通过继承来改变 String 类的行为和特性。
修饰方法:用 final 修饰的方法不能在子类中被重写。
例如: java.lang.object 类中的 getClass方法就是 final 的,因为这个方法的行为是由 Java 虚拟机底层实现来保证的,不应该被子类修改。
修饰变量:当用 final 修饰基本数据类型的变量时,一旦该变量被赋值就不能再改变。对于引用数据类型,final 修饰意味着这个引用变量不能再指向其他对象。
例如:这里的 num 是一个常量,就不能再对其进行赋值操作,否则会编译报错。
final int num = 10;
例如:这里 str 不能再指向其他 StringBuilder 对象,但可以通过 str.append() 来修改字符串内容。
final StringBuilder str = new StringBuilder("Hello");