面向对象
什么是面向对象
以对象为核心。
类是对象创建的模板,对象是类的实例。
面向对象三大特性是什么
- 封装:类的创建者将类具体实现隐藏,使用者只需要使用外部接口即可
- 继承:类有子类和父类,有从属关系。提高代码复用性。
- 多态:同一个方法可以被不同的对象以不同的方式执行。子类可以替代父类出现在任何需要父类的地方
怎么理解多态的特性
- 什么是多态:接口的多种不同的实现方式即为多态。多个对象调用同一个方法,得到不同的结果。
- 多态使用:
父类类名 对象 = new 子类类名(); - 向上转型(默认):子类型赋值给父类型。对象只能访问父类中的属性和方法,但会优先访问子类重写的方法。
- 向下转型:子类型赋值给父类型后,强转回子类型。
class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking");
}
}
public class Main {
public static void main(String[] args) {
// 向上转型
Animal myAnimal = new Dog();
myAnimal.eat();
// 向下转型
if (myAnimal instanceof Dog) {
Dog myDog = (Dog) myAnimal;
myDog.bark();
}
}
}
Java为什么只能单继承
- 使用简单:多继承会导致“钻石问题”,子类有多个相同方法需要继承。
- 多继承在其他语言中也不经常使用
- Java可以通过实现多个接口实现“多继承”
抽象类和接口
接口和抽象类有什么区别
相同点:
- 都可以定义抽象方法,让子类去实现
- 都不能实例化
不同点:
- 抽象类用继承
extend,接口用实现implements - 接口可以多实现,抽象类只能单继承
- 抽象类可以实现接口,接口只能继承接口
- 抽象类可以定义成员属性,接口只能定义静态常量
- 抽象类可以定义构造方法,控制子类实例化。接口没有构造方法。
接口的补充:
- Java8:
default关键字实现接口默认方法,子类可以不重写。提高兼容性。 - Java9:
private关键字可以封装私有方法,可以提高默认方法的函数内的代码复用性。
方法重写和重载
方法重载和重写有什么区别
- 重载:类中定义了多个方法名相同,但参数不同的方法。
- 重写:子类存在方法与父类的方法的名字相同、参数相同
方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
多态性:相同的名称但有着不同的实现。
内部类
内部类汇总
- 成员内部类:在成员位置上定义类
- 可以访问外部类静态属性和非静态属性
- 外部类成员方法调用成员内部类的方法需要先创建对象
public class User {
static String name;
int age;
class IdCard {
String id;
public void getIdCardData() {
System.out.println(name);
System.out.println(id);
System.out.println(age);
}
}
IdCard idCard = new IdCard();
public void getUserData() {
System.out.println(idCard.id);
}
}
- 局部内部类:在类的方法中定义类
- 可以访问外部类静态属性和非静态属性
public class User {
static String name;
int age;
public void say() {
class IdCard {
String birthday;
public void getIdCardData() {
System.out.println(name);
System.out.println(age);
System.out.println(birthday);
}
}
IdCard idCard = new IdCard();
idCard.getIdCardData();
}
}
- 静态(成员)内部类:在成员位置上定义静态类
- 只能访问外部类静态属性,不能访问非静态属性
public class User {
static String name;
int age;
static class IdCard {
String id;
public void getIdCardData() {
System.out.println(name);
System.out.println(id);
// System.out.println(age);
}
}
IdCard idCard = new IdCard();
public void getUserData() {
System.out.println(idCard.id);
}
}
- 匿名内部类:只有类体没有类名的类,通常用于创建只需要使用一次的类的实例。
public abstract class Animal {
String name;
abstract void eat();
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal() {
@Override
void eat() {
System.out.println("The animal is eating");
}
};
animal.eat();
}
}
为什么需要内部类?什么是匿名内部类?
内部类的主要作用是可以访问外部类的私有成员。
匿名内部类是只有类体没有类名的类,通常用于创建只需要使用一次的类的实例。可以简化代码书写,不需要单独定义一个实体类。
静态内部类和非静态内部类有什么区别?
外部属性:
- 静态内部类只能访问外部类的静态属性
- 非静态内部类可以访问外部类的静态属性和非静态属性
对外部类实例的依赖:
- 静态内部类可以直接创建
- 非静态内部类需要外部类实例才能创建
静态内部类的使用场景是什么?
用来实现单例模式
- 优点:天然线程安全,实现延迟加载
- 缺点:第一次加载又有延迟
public class Singleton {
public static class Inner {
public static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Inner.INSTANCE;
}
private Singleton() {}
}