面向对象
三大特性
什么是面向对象?三大特性是什么?
答案: 面向对象(OOP)是一种编程思想,将现实世界的事物抽象为对象,通过对象之间的交互完成功能。
三大特性:
- 封装(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
封装
定义:将对象的属性和方法封装起来,隐藏内部实现细节,只暴露必要的接口。
优点:
- 提高安全性
- 降低耦合度
- 便于维护
java
public class Person {
// 私有属性
private String name;
private int age;
// 公共方法访问
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age < 150) { // 数据校验
this.age = age;
}
}
}继承
定义:子类继承父类的属性和方法,实现代码复用。
特点:
- Java只支持单继承
- 子类可以重写父类方法
- 使用extends关键字
java
// 父类
public class Animal {
protected String name;
public void eat() {
System.out.println("动物吃东西");
}
}
// 子类
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void bark() {
System.out.println("汪汪叫");
}
}多态
定义:同一个方法调用,不同对象有不同的行为。
实现方式:
- 方法重载(编译时多态)
- 方法重写(运行时多态)
条件:
- 继承
- 重写
- 父类引用指向子类对象
java
public class PolymorphismDemo {
public static void main(String[] args) {
// 父类引用指向子类对象
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.eat(); // 输出:狗吃骨头
animal2.eat(); // 输出:猫吃鱼
// 向下转型
if (animal1 instanceof Dog) {
Dog dog = (Dog) animal1;
dog.bark();
}
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}类与对象
类和对象的关系?
答案:
- 类:对象的模板,描述对象的属性和行为
- 对象:类的实例,具体的个体
java
// 类
public class Car {
String brand;
String color;
void drive() {
System.out.println("开车");
}
}
// 对象
Car car1 = new Car();
car1.brand = "BMW";
car1.color = "黑色";
car1.drive();构造方法的作用?
答案: 构造方法用于创建对象时初始化对象。
特点:
- 方法名与类名相同
- 没有返回值类型
- 创建对象时自动调用
- 可以重载
java
public class Person {
private String name;
private int age;
// 无参构造
public Person() {
this.name = "未知";
this.age = 0;
}
// 有参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 构造方法重载
public Person(String name) {
this(name, 0); // 调用其他构造方法
}
}this和super关键字的区别?
答案:
| 关键字 | 作用 |
|---|---|
| this | 引用当前对象 |
| super | 引用父类对象 |
java
public class Parent {
String name = "父类";
public Parent() {
System.out.println("父类构造方法");
}
public void show() {
System.out.println("父类方法");
}
}
public class Child extends Parent {
String name = "子类";
public Child() {
super(); // 调用父类构造方法(必须在第一行)
System.out.println("子类构造方法");
}
public void show() {
System.out.println(this.name); // 子类
System.out.println(super.name); // 父类
super.show(); // 调用父类方法
}
}抽象类与接口
抽象类和接口的区别?
答案:
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract | interface |
| 继承 | 单继承 | 多实现 |
| 方法 | 可以有具体实现 | 默认抽象(JDK8+可有default方法) |
| 变量 | 可以有实例变量 | 只能有常量(public static final) |
| 构造方法 | 可以有 | 不能有 |
| 访问修饰符 | 任意 | 默认public |
java
// 抽象类
public abstract class Animal {
String name; // 实例变量
public Animal(String name) { // 构造方法
this.name = name;
}
abstract void sound(); // 抽象方法
public void sleep() { // 具体方法
System.out.println("睡觉");
}
}
// 接口
public interface Flyable {
int MAX_SPEED = 100; // 常量
void fly(); // 抽象方法
default void land() { // 默认方法(JDK8+)
System.out.println("降落");
}
static void info() { // 静态方法(JDK8+)
System.out.println("飞行接口");
}
}
// 实现
public class Bird extends Animal implements Flyable {
public Bird(String name) {
super(name);
}
@Override
void sound() {
System.out.println("鸟叫");
}
@Override
public void fly() {
System.out.println("鸟飞");
}
}什么时候用抽象类,什么时候用接口?
答案:
使用抽象类:
- 有共同的属性和方法
- 需要构造方法
- 需要非public成员
使用接口:
- 定义行为规范
- 需要多继承
- 不同类有相同行为
java
// 抽象类:描述"是什么"
abstract class Vehicle {
String brand;
abstract void start();
}
// 接口:描述"能做什么"
interface Drivable {
void drive();
}
interface Flyable {
void fly();
}
// 汽车:是交通工具,能驾驶
class Car extends Vehicle implements Drivable {
void start() {}
public void drive() {}
}
// 飞机:是交通工具,能驾驶,能飞
class Plane extends Vehicle implements Drivable, Flyable {
void start() {}
public void drive() {}
public void fly() {}
}内部类
内部类有哪些?
答案:
1. 成员内部类
java
public class Outer {
private String name = "外部类";
class Inner { // 成员内部类
public void show() {
System.out.println(name); // 可以访问外部类成员
}
}
public void test() {
Inner inner = new Inner();
inner.show();
}
}
// 使用
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();2. 静态内部类
java
public class Outer {
private static String name = "外部类";
static class Inner { // 静态内部类
public void show() {
System.out.println(name); // 只能访问静态成员
}
}
}
// 使用
Outer.Inner inner = new Outer.Inner();3. 局部内部类
java
public class Outer {
public void test() {
class Inner { // 局部内部类
public void show() {
System.out.println("局部内部类");
}
}
Inner inner = new Inner();
inner.show();
}
}4. 匿名内部类
java
public class AnonymousDemo {
public static void main(String[] args) {
// 匿名内部类实现接口
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
// Lambda表达式(JDK8+)
Runnable runnable2 = () -> System.out.println("Lambda");
}
}Object类
Object类的常用方法?
答案:
java
public class Object {
// 1. equals() - 比较对象是否相等
public boolean equals(Object obj) {
return (this == obj);
}
// 2. hashCode() - 返回对象的哈希码
public native int hashCode();
// 3. toString() - 返回对象的字符串表示
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 4. clone() - 克隆对象
protected native Object clone() throws CloneNotSupportedException;
// 5. getClass() - 获取对象的Class对象
public final native Class<?> getClass();
// 6. wait() / notify() / notifyAll() - 线程通信
public final native void wait(long timeout) throws InterruptedException;
public final native void notify();
public final native void notifyAll();
// 7. finalize() - 垃圾回收前调用(已废弃)
protected void finalize() throws Throwable { }
}为什么重写equals()必须重写hashCode()?
答案: 保证equals()相等的对象,hashCode()也相等,否则在HashMap等集合中会出现问题。
java
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}问题示例:
java
Person p1 = new Person("Tom", 20);
Person p2 = new Person("Tom", 20);
System.out.println(p1.equals(p2)); // true
Map<Person, String> map = new HashMap<>();
map.put(p1, "value1");
System.out.println(map.get(p2)); // 如果没重写hashCode(),返回null练习题
- 什么是向上转型和向下转型?
- 为什么Java不支持多继承?
- 内部类有什么优缺点?
- 如何实现对象的深拷贝?