JavaSE高级(二)

272 阅读22分钟

static

static是Java中的一个重要关键字,用于修饰类的成员(变量、方法、代码块和嵌套类),表示这些成员属于类本身,而不是类的实例。

1. static变量(类变量)
  • static修饰的变量叫做静态变量或类变量
  • 属于类,而不是某个特定对象
  • 所有实例共享一个静态变量
  • 在类加载时初始化
public class Counter {
    static int count = 0;  // 静态变量

    Counter() {
        count++;
    }
}

class Test {
    public static void main(String[] args) {
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();
        System.out.println(Counter.count);//3
    }
}
2. static方法(类方法)
  • static修饰的方法为静态方法
  • 可以直接通过类名调用,无需创建对象
  • 静态方法中只能直接访问静态成员,不能直接访问实例成员(因为实例成员需要对象存在)
  • 不能使用thissuper关键字
public class MathUtils {
    static int add(int a, int b) {
        return a + b;
    }
}

class Main {
    public static void main(String[] args) {
        int sum = MathUtils.add(5, 3); // 直接通过类名调用
        System.out.println("Sum: " + sum);
    }
}
3. static代码块
  • 用于初始化静态变量
  • 在类加载时执行,只执行一次
  • 可以有多个静态代码块,按顺序执行
class Database {
    static String url;
    static String username;
    static String password;
    
    static {
        // 静态代码块
        url = "jdbc:mysql://localhost:3306/mydb";
        username = "admin";
        password = "password";
    }
}
4. static嵌套类
  • 用static修饰的嵌套类称为静态嵌套类
  • 与外部类的实例无关,可以直接创建
  • 只能访问外部类的静态成员
class Outer {
    static int x = 10;

    static class Inner {
        void display() {
            System.out.println("x = " + x);
        }
    }
}

class Main1 {
    public static void main(String[] args) {
        // 使用
        Outer.Inner inner = new Outer.Inner();
        inner.display();
    }
}
5. 使用场景
  • 当某个成员需要被所有实例共享时(如计数器)
  • 工具类方法(如Math类中的方法)
  • 常量定义(通常final一起使用)
  • 主方法(main方法必须是static的)
注意事项
  • 静态方法不能被重写为非静态方法(反之亦然)
  • 静态方法不能被标记为abstract
  • 静态成员在类加载时初始化,早于对象的创建
  • 过度使用static可能导致代码难以测试和维护

static关键字是Java中实现类级别共享和工具方法的重要机制,合理使用可以提高程序效率和代码组织性.

继承

继承是面向对象编程的三大特性之一(封装、继承、多态),它允许一个类(子类)继承另一个类(父类)的属性和方法。

1. 继承的基本语法
class 父类 {
    // 父类的成员变量和方法
}

class 子类 extends 父类 {
    // 子类特有的成员变量和方法
}
2. 继承的特点
  • 代码复用:子类可以直接使用父类的非私有成员
  • 扩展性:子类可以添加自己的新成员
  • 单继承:Java只支持单继承(一个子类只有一个直接父类)
  • 多层继承:可以形成继承层次结构(A->B->C)
  • 构造方法不能继承:子类不能继承父类的构造方法,但可以通过super()调用
3. 继承示例
// 父类
class Animal {
    String name;

    public void eat() {
        System.out.println(name + "正在吃东西");
    }
}

// 子类
class Dog extends Animal {
    public void bark() {
        System.out.println(name + "正在汪汪叫");
    }
}

// 使用
public class Main2 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "大黄";
        dog.eat();  // 继承自Animal的方法
        dog.bark(); // Dog自己的方法
    }
}
4. 方法重写(Override)
  • 子类可以重新定义父类中已有的方法
  • 必须保持方法签名相同(方法名、参数列表)
  • 访问权限不能比父类更严格
  • 返回类型可以是父类方法返回类型的子类(协变返回类型)
  • 可以使用@Override注解明确表示这是重写方法
// 父类
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

// 子类
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵叫");
    }
}
5.super关键字
  • 用于访问父类的成员(变量、方法、构造器)
  • super()调用父类的构造方法(必须放在子类构造方法的第一行)
  • super.成员访问父类成员
6. 构造方法的继承
  • 在类构造方法默认调用父类的无参构造
  • 如果父类中没有无参构造,必须使用super(参数)显式调用
  • super()和this()不能同时出现在一个构造方法中
class Person {
    String name;
    
    Person(String name) {
        this.name = name;
    }
}

class Student extends Person {
    int grade;
    
    Student(String name, int grade) {
        super(name); // 必须调用父类构造方法
        this.grade = grade;
    }
}
7. final与继承
  • final class:不能被继承
  • final method:不能被重写
  • final variable:常量,值不能被修改
final class FinalClass { // 不能被继承
    final void finalMethod() { // 不能被子类重写
        final int MAX_VALUE = 100; // 常量
    }
}
8. 继承与访问控制
  • private成员:子类不能直接访问
  • protected成员:子类可以访问(即使不在同一个包下)
  • 默认(包私有):同包子类可以访问
  • public成员:所有子类都可以访问
9. Object类
  • Java中所有类的根父类
  • 常用方法:
    • toString():返回对象字符串表示
    • equals():比较对象内容
    • hashCode():返回对象的哈希码值
    • getClass():获取对象的运行时类
10. 继承的应用场景
  • is-a关系(狗是动物)
  • 需要扩展或修改现有类功能
  • 实现多态的基础
  • 框架设计中常用的扩展机制
注意事项
  • 慎用继承,优先考虑组合而非继承
    • 避免过深的继承层次(一般不超过3层)
  • 父类修改可能影响所有子类
  • 子类不应该改变父类方法的预期行为(里氏替换原则)

继承是Java中强大的代码复用机制,但需要合理使用以避免设计上的问题.

多态

多态是面向对象编程的三大特性之一,它允许不同类的对象对同一消息做出不同的响应。多态提高了代码的灵活性和可扩展性。

1. 多态的基本概念

多态是指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在Java中,多态主要体现在以下两个方面:

  • 编译时多态:方法重载
  • 运行时多态:方法重写
2. 多态的实现条件

实现多态需要满足三个条件:

  • 继承关系:存在继承关系的类
  • 方法重写:子类重写父类的方法
  • 向上转型:父类引用指向子类对象
3. 多态的实现方式
方法重载-编译时多态
public class Calculator {
    // 方法重载:同名方法,不同参数
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }

    int add(int a, int b, int c) {
        return a + b + c;
    }
}

class Test01 {
    public static void main(String[] args) {
        // 使用
        Calculator calc = new Calculator();
        System.out.println(calc.add(1, 2));      // 调用int add(int, int)
        System.out.println(calc.add(1.5, 2.5));  // 调用double add(double, double)
        System.out.println(calc.add(1, 2, 3));   // 调用int add(int, int, int)
    }
}
方法重写-运行时多态
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪叫");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵叫");
    }
}

// 使用多态
public class Main {
    public static void main(String[] args) {
        Animal myAnimal;  // 父类引用
        
        myAnimal = new Dog();  // 向上转型
        myAnimal.makeSound();  // 输出"汪汪叫"
        
        myAnimal = new Cat();  // 向上转型
        myAnimal.makeSound();  // 输出"喵喵叫"
    }
}
4. 向上转型和向下转型
向上转型
  • 将子类对象赋值给父类引用
  • 自动进行,不需要强制转换
  • 只能访问父类中声明的方法和属性
向下转型
  • 将父类引用转为子类引用
  • 需要强制类型转换
  • 必须先向上转型才能向下转型
  • 使用insatnceof进行类型检查更安全
Animal animal = new Dog();
if (animal instanceof Dog) {
    Dog myDog = (Dog) animal;  // 向下转型
    myDog.bark();  // 可以调用Dog特有的方法
}
5.多态的应用场景
方法参数多态
public class Zoo {
    public void animalSound(Animal animal) {
        animal.makeSound();  // 根据实际传入的对象类型调用相应方法
    }
}
class Animal {
    public void makeSound() {
        System.out.println("动物叫");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("喵喵叫");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("汪汪叫");
    }
}

class Main {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        zoo.animalSound(new Dog());  // 输出"汪汪叫"
        zoo.animalSound(new Cat());  // 输出"喵喵叫"
    }
}
返回类型多态
class AnimalFactory {
    public Animal1 getAnimal(String type) {
        if ("dog".equalsIgnoreCase(type)) {
            return new Dog1();
        } else if ("cat".equalsIgnoreCase(type)) {
            return new Cat1();
        }
        return null;
    }
}

class Dog1 extends Animal1 {

}

class Cat1 extends Animal1 {

}

class Animal1 {

}

class Main01 {
    public static void main(String[] args) {
        AnimalFactory factory = new AnimalFactory();
        Animal1 dog = factory.getAnimal("dog");
        Animal1 cat = factory.getAnimal("cat");
    }
}
集合中的多态
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());

for (Animal animal : animals) {
    animal.makeSound();  // 多态调用
}
6. 多态的优点和缺点

优点:

  • 提高代码的可扩展性:新增的子类不影响现有的代码
  • 提高代码的灵活性:同一方法处理不同的子类对象
  • 提高代码的可维护性:减少重复代码
  • 接口与实现分离:使用者只需要关注父类接口

缺点:
不能调用子类特有的功能

7. 多态的实现原理

Java通过动态绑定(后期绑定)实现运行时多态:

  1. 编译时:检查方法是否在父类中存在
  2. 运行时:JVM根据实际对象类型调用相应的方法
  3. 虚方法表:存储实际的调用的方法地址
8.注意事项
  1. 只有实例方法有多态,静态方法还有字段没有多态
  2. 私有方法不能被重写,因此没有多态
  3. 构造方法不能被重写,也没有多态
  4. final方法不能被重写,没有多态
  5. 访问权限:重写方法不能比被重写方法更严格
9. 多态调用成员的特点
  • 变量调用:编译看左边,运行还看左边
  • 方法调用:编译看左边,运行看右边
10. 综合示例
// 父类
class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public double calculateBonus() {
        return salary * 0.1;  // 默认10%奖金
    }

    public String getDetails() {
        return "Name: " + name + ", Salary: " + salary;
    }
}

// 子类1
class Manager extends Employee {
    private double bonus;

    public Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    @Override
    public double calculateBonus() {
        return super.calculateBonus() + bonus;  // 经理有额外奖金
    }

    @Override
    public String getDetails() {
        return super.getDetails() + ", Bonus: " + bonus;
    }
}

// 子类2
class Developer extends Employee {
    private int overtimeHours;

    public Developer(String name, double salary, int overtimeHours) {
        super(name, salary);
        this.overtimeHours = overtimeHours;
    }

    @Override
    public double calculateBonus() {
        return overtimeHours * 100;  // 开发者按加班小时计算奖金
    }
}

// 使用多态
public class Company {
    public static void main(String[] args) {
        Employee[] employees = {new Manager("张经理", 20000, 5000), new Developer("李开发", 15000, 20), new Employee("王普通", 10000)};

        for (Employee emp : employees) {
            System.out.println(emp.getDetails());
            System.out.println("奖金: " + emp.calculateBonus());
            System.out.println("------------");
        }
    }
}

多态是Java面向对象编程中非常强大的特性,合理使用多态可以大大提高代码的质量和可维护性。理解多态的关键在于掌握"一个接口,多种实现"的思想

包、final、权限修饰符、代码块

1. 包的作用

包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。

2. 包名的书写规则

包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。

3. 什么时候需要导包?什么时候不需要导包?
  • 使用同一包中的类时,不需要导包
  • 使用java.lang包中的类时,不需要导包
  • 其他情况需要导包
  • 如果使用两个包中的同类名时,需要用全类名(包名+类名)

final关键字

final是Java中一个重要的关键字,用于表示"不可改变的"。它可以修饰类、方法和变量,具有不同的含义和作用

修饰目标继承相关特性
final类不能被继承
final方法不能被子类重写
final变量与继承无关,表示常量
1. final变量
1.1 基本类型final变量:

final修饰的变量表示常量,一旦被赋值就不能再修改

final int MAX_VALUE = 100;
// MAX_VALUE = 200;  // 编译错误,不能重新赋值
1.2 引用类型final变量
final List<String> names = new ArrayList<>();
// names = new ArrayList<>();  // 编译错误,不能重新赋值
names.add("Alice");  // 可以修改对象内容
names.remove(0);     // 可以修改对象内容
1.3 final成员变量

必须在声明时或构造方法中初始化:

class MyClass {
    final int value1 = 10;  // 声明时初始化
    final int value2;
    
    MyClass(int v) {
        value2 = v;  // 构造方法中初始化
    }
}
1.4 final静态变量(常量)

通常与static一起使用定义常量:

class Constants {
    public static final double PI = 3.14159;
    public static final String APP_NAME = "MyApp";
}
2. final方法

final方法不能被子类重写

class Parent {
    public final void show() {
        System.out.println("这是final方法");
    }
}

class Child extends Parent {
    // @Override
    // public void show() {}  // 编译错误,不能重写final方法
}
3. final类

final类不能被继承:

final class FinalClass {
    // 类内容
}

// class SubClass extends FinalClass {}  // 编译错误,不能继承final类
4. final参数

方法参数被声明为final,表示在方法内不能修改参数的值:

public void process(final int input) {
    // input = 10;  // 编译错误,不能修改final参数
    System.out.println(input);
}
5. fianl与性能

使用final可能会带来一些性能优化:

  • final变量可以被JVM优化
  • final方法在早期Java版本中可以进行内联优化
  • final类的方法调用都是非虚方法,可以提高执行效率
6. final的最佳实践
  1. 常量定义:使用public static final 组合定义为全局常量
  2. 不可变类:将类申明为final,所有字段声明为final
  3. 线程安全:final变量是线程安全的,不需要额外的同步
  4. 明确设计意图:表明某些内容不应该被修改
7. 注意事项
  1. final变量必须且只能被赋值一次
  2. final引用变量不能指向其他对象,但是对象内容可以改变
  3. 要创建真正的不可变对象,需要:
    • 类申明为final
    • 将所有字段申明为final
    • 不能提供修改字段的方法
    • 如果字段是引用类型,返回防御性拷贝
8. final示例:不可变类
public final class ImmutablePerson {
    private final String name;
    private final int age;
    private final List<String> hobbies;
    
    public ImmutablePerson(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.hobbies = new ArrayList<>(hobbies);  // 防御性拷贝
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public List<String> getHobbies() {
        return new ArrayList<>(hobbies);  // 返回拷贝,保护内部状态
    }
}

final关键字是Java中实现不可变性和安全性的主要工具,合理使用final可以提高代码的安全性和可维护性

权限修饰符

权限对比表:
修饰符类内部同包不同包的子类不同包的非子类
public
protected×
default××
private×××
1. public(公开的)
  • 作用范围:所有类均可访问
  • 可修饰对象:类、方法、变量、构造器
  • 特点:
    • 被修饰的成员在任何地方都能访问(包括不同的包)
    • 类的public成员可以被其他包的类通过导入后直接使用
2. protected(受保护的)
  • 作用范围:同一包内的所有类以及不同包的子类(通过继承访问)
  • 可修饰对象:方法、变量、构造器(不能修饰外部类)
  • 特点:
    • 主要用于支持继承,允许子类访问父类的protected成员
3. default(默认,即不写修饰符)
  • 作用范围:同一包内的所有类
  • 可修饰对象:类、方法、变量、构造器
  • 特点:
    • 如果未显式指定修饰符,则默认为包级私有
    • 不同包的类(即使有继承关系)无法访问
4. private(私有的)
  • 作用范围:仅当前类内部
  • 可修饰对象:方法、变量、构造器(不能修饰外部类)
  • 特点:
    • 提供最高级别的封装,外部类(包括子类)无法直接访问
    • 通常通过公共的getter/setter方法间接访问私有变量
注意事项
  • 类的修饰符:
    • 外部类只能用publicdefault(不能是protected/private)
    • 内部类可以用所有四种修饰符
  • 继承中的权限:
    • 子类重写父类方法时,权限不能比父类更严格(例如父类方法是protected,子类不能改为private)
  • 封装的原则:
    • 优先使用private,通过公共的方法暴露必要的功能(遵循"最小权限原则")
  • 构造器权限:
    • 如果构造器是private,则只能通过静态工厂方法创建对象(单例模式常用)

通过合理使用修饰符,可以设计出高内聚,低耦合的代码结构

代码块

在代码中,代码块(Code Block)是指{}括起来的一段代码,用于定义作用域或控制执行流程

1. 普通代码块(局部代码块)
  • 作用:限定变量的作用范围(局部变量生命周期)
  • 示例:
public void demo() {
    int x = 10;
    System.out.println(x); // 正常访问

    { // 普通代码块
        int y = 20;
        System.out.println(y); // 正常访问
    }
    // System.out.println(y); // 报错!y 超出作用域
}
2. 静态代码块
  • 作用:在类加载的时候执行
  • 特点:
    • 只执行一次
    • 多个静态块按定义顺序执行
  • 示例:
class MyClass {
    static int num;
    
    static { // 静态代码块
        num = 10;
        System.out.println("Static block executed.");
    }
}
3. 实例代码块
  • 作用:在每次创建对象时执行,优先于构造器
  • 特点:
    • 用于提取多个构造器的公共初始化逻辑
    • 多个实例块按定义顺序执行
  • 示例:
class MyClass {
    int x;
    
    { // 实例代码块
        x = 100;
        System.out.println("Instance block executed.");
    }
    
    public MyClass() {
        System.out.println("Constructor executed.");
    }
}
4. 同步代码块
  • 作用:在多线程控制对共享资源的访问(线程安全)
  • 示例:
public class Counter {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) { // 同步代码块
            count++;
        }
    }
}
5. 条件/循环代码块
  • 作用:配合if、for、while等控制语句的使用
  • 示例:
if (condition) { // if 代码块
    System.out.println("Condition is true.");
}

for (int i = 0; i < 5; i++) { // for 代码块
    System.out.println(i);
}
关键区别总结
代码块类型执行时机典型用途
普通代码块方法调用时限制变量的作用域
静态代码块类加载时(仅一次)初始化静态资源
实例代码块创建对象时(每次)提取构造器公共逻辑
同步代码块线程进入synchronized时解决多线程竞争
条件/循环代码块控制语句触发时流程控制
最佳实践
  • 减少代码块嵌套:避免深层嵌套(如超过3层),提高可读性。
  • 静态代码块替换复杂的静态初始化:
static Map<String, String> config;
static {
    config = new HashMap<>();
    config.put("key1", "value1");
}
  • 同步代码块粒度要小:仅锁定必要部分,避免性能问题

通过合理使用代码块

抽象类

抽象类(Abstract Class)是Java中的一种特殊类,它不能被实例化,主要用于定义模版提供部分实现,强制子类实现特定的方法

1. 抽象类的特点
  • 不能被实例化(不能new)
  • 可以包含抽象方法(无方法体)和普通方法
  • 子类必须实现所有抽象方法(除非子类也是抽象类)
  • 可以包含成员变量、构造方法、静态方法等。
  • 可以定义final方法,防止子类修改。
2. 抽象类的语法

(1)定义抽象类
使用abstract关键字声明:

public abstract class Animal {
    // 普通成员变量
    private String name;

    // 构造方法(虽然不能直接实例化,但子类可以调用)
    public Animal(String name) {
        this.name = name;
    }

    // 普通方法
    public void eat() {
        System.out.println(name + " is eating.");
    }

    // 抽象方法(没有方法体)
    public abstract void makeSound();
}

(2)子类继承抽象类
子类必须实现所有的抽象方法:

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类构造方法
    }

    @Override
    public void makeSound() { // 必须实现抽象方法
        System.out.println("Woof! Woof!");
    }
}

(3)使用抽象类

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Buddy");
        dog.eat();        // 输出: Buddy is eating.
        dog.makeSound();  // 输出: Woof! Woof!
    }
}
3. 什么时候使用抽象类
  • 多个类有共同代码,但部分行为不同(如Animal有eat(),但是makeSound()不同)
  • 需要定义非静态/非final的成员变量
  • 需要构造方法初始化状态
  • 希望强制子类实现某些方法(如模版方法模式)
4. 经典示例:模版方法模式

抽象类定义算法骨架,子类实现具体步骤:

abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();

    // 模板方法(final 防止子类修改算法流程)
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
}

class Cricket extends Game {
    @Override
    void initialize() { System.out.println("Cricket Game Initialized!"); }
    @Override
    void startPlay() { System.out.println("Cricket Game Started!"); }
    @Override
    void endPlay() { System.out.println("Cricket Game Finished!"); }
}

public class Main {
    public static void main(String[] args) {
        Game game = new Cricket();
        game.play(); // 执行模板方法
    }
}
5. 抽象类 VS 接口(Java8+)
特性抽象类接口
实例化不能直接实例化不能直接实例化(Java8+可以default方法)
方法实现可以有抽象方法和普通方法Java7只能有抽象方法,Java8+可以有default方法
变量可以有普通变量和常量只能有public static final 常量
构造方法可以有构造方法不能有构造方法
多继承只能单继承支持实现多个接口
设计目的代码复用+部分实现强制定义行为规范(多态)
6. 总结
  1. 抽象类用于代码复用+强制子类实现特定方法
  2. 接口用于定义行为规范(多继承)
  3. 优先使用接口,除非需要成员变量,构造方法或非静态方法
  4. 抽象类适合模版方法模式,定义算法骨架,子类填充细节

合理使用抽象类,可以写出更灵活,可维护的代码!

Java接口(Interface)

接口是Java中一种重要的抽象类,它定义了一组方法签名(抽象方法)的契约,但不提供实现。类可以实现接口(implement),从而承诺提供接口中所有方法的实现

接口的基本特性
  1. 完全抽象:接口中的方法默认是抽象的(Java8之前)
  2. 多实现:一个类可以实现多个接口
  3. 契约作用:定义行为规范,不关心具体实现
  4. 不能实例化:不能直接创建接口的示例
接口定义语法
public interface 接口名 {
    // 常量声明 (默认 public static final)
    type CONSTANT_NAME = value;
    
    // 方法声明 (默认 public abstract)
    returnType methodName(parameterList);
    
    // Java 8+ 默认方法
    default returnType methodName() {
        // 实现
    }
    
    // Java 8+ 静态方法
    static returnType methodName() {
        // 实现
    }
    
    // Java 9+ 私有方法
    private returnType methodName() {
        // 实现
    }
}
接口实现

类使用implement关键字实现接口:

public class ClassName implements Interface1, Interface2 {
    // 必须实现所有接口的抽象方法
    @Override
    public returnType methodName() {
        // 实现
    }
}
接口的新特性
Java8新增
  1. 默认方法(default methods):
    • 使用default关键字
    • 提供默认实现,实现类可以不重写
    • 主要用于接口衍化,避免破坏现有实现
interface Vehicle {
    default void print() {
        System.out.println("我是一辆车!");
    }
}
  1. 静态方法(static methods)
    • 属于接口本身,通过接口名调用
    • 不能被子接口或实现类继承
interface MathOperations {
    static int add(int a, int b) {
        return a + b;
    }
}
Java9新增
  1. 私有方法(private methods)
    • 只能在接口内部使用
    • 分为私有实例方法和私有静态方法
    • 用于提取公共代码,减少重复
interface DBLogging {
    private void createLog() {
        // 创建日志的通用代码
    }
}
接口和抽象类的区别
特性接口抽象类
方法实现Java之前不能有实现可以有具体的实现
变量只能public static final 常量可以是普通变量
构造方法不能有可以有
多继承一个类实现多个接口一个类只能继承一个抽象类
设计理念"是什么"的契约"是什么"的部分实现
接口的使用场景
  1. 定义不相关类之间的共同行为
  2. 实现多重继承的效果
  3. 定义回调函数(如事件监听器)
  4. 实现松耦合的系统设计
  5. 定义API契约

示例代码:

// 定义接口
interface Animal {
    void eat();
    void sleep();
    
    default void breathe() {
        System.out.println("呼吸空气");
    }
    
    static boolean isAnimal(Object obj) {
        return obj instanceof Animal;
    }
}

// 实现接口
class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    
    @Override
    public void sleep() {
        System.out.println("狗睡在狗窝里");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
        dog.sleep();
        dog.breathe();
        
        System.out.println(Animal.isAnimal(dog)); // true
    }
}

内部类

内部类是定义在另一个类内部的类,它是Java中一种强大的特性,允许将逻辑上相关的类组织在一起,并可以访问外部类的成员

成员内部类
  • 定义在外部类的成员位置
  • 可以访问外部类的所有成员(包括private)
  • 不能有静态成员(除非是static final常量)
class Outer {
    private int x = 10;
    
    class Inner {
        void display() {
            System.out.println("x = " + x); // 可以访问外部类的私有成员
        }
    }
}

// 使用方式
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();
静态内部类
  • 使用static修饰的内部类
  • 不能直接访问外部类的非静态成员
  • 可以看做是一个普通的类,只是定义在另一个类内部
class Outer {
    static int x = 10;
    
    static class StaticNested {
        void display() {
            System.out.println("x = " + x); // 只能访问外部类的静态成员
        }
    }
}

// 使用方式
Outer.StaticNested nested = new Outer.StaticNested();
nested.display();
局部内部类
  • 定义在方法或作用域块内的类
  • 只能访问所在方法中finaleffectively final的局部变量
  • 作用域限于定义它的代码块
class Outer {
    void outerMethod() {
        final int localVar = 20;
        
        class LocalInner {
            void display() {
                System.out.println("localVar = " + localVar);
            }
        }
        
        LocalInner inner = new LocalInner();
        inner.display();
    }
}
匿名内部类
  • 没有类名的内部类
  • 通常用于创建接口或抽象类的即时代码实现
  • 只能创建一个实例
interface Greeting {
    void greet();
}

class Outer {
    void sayHello() {
        Greeting greeting = new Greeting() { // 匿名内部类
            @Override
            public void greet() {
                System.out.println("Hello, world!");
            }
        };
        greeting.greet();
    }
}
内部类的特点
1. 访问权限
  • 成员内部类可以访问外部类的所有成员
  • 静态内部类只能访问外部类的静态成员
2. .this和.new语法
  • OuterClass.this引用外部类实例
  • outerObject.new InnerClass()创建内部类实例
3. 编译后文件
  • 成员内部类:Outer$Inner.class
  • 匿名内部类:Outer$1.class(数字递增)
4. 内存泄露风险
  • 内部类隐式持有外部类的引用,可能导致内存泄露
内部类的使用场景
  1. 逻辑分组:将只在一个地方使用的类逻辑上分组
  2. 增强封装:访问外部类的私有成员
  3. 回调机制:实现事件监听器等回调功能
  4. 多重继承:通过多个内部类模拟多重继承
  5. GUI开发:Swing/AWT中的事件处理器

示例代码:

// 综合示例
class Outer {
    private int outerField = 10;
    private static int staticOuterField = 20;
    
    // 成员内部类
    class MemberInner {
        void accessOuter() {
            System.out.println("访问外部类实例字段: " + outerField);
            System.out.println("访问外部类静态字段: " + staticOuterField);
        }
    }
    
    // 静态嵌套类
    static class StaticNested {
        void accessOuter() {
            // System.out.println(outerField); // 错误,不能访问实例成员
            System.out.println("访问外部类静态字段: " + staticOuterField);
        }
    }
    
    void methodWithLocalClass() {
        int localVar = 30; // effectively final
        
        // 局部内部类
        class LocalInner {
            void display() {
                System.out.println("局部变量: " + localVar);
                System.out.println("外部类字段: " + outerField);
            }
        }
        
        new LocalInner().display();
    }
    
    void methodWithAnonymousClass() {
        // 匿名内部类
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类执行");
                System.out.println("访问外部类字段: " + outerField);
            }
        };
        
        new Thread(r).start();
    }
}

public class InnerClassDemo {
    public static void main(String[] args) {
        Outer outer = new Outer();
        
        // 成员内部类
        Outer.MemberInner memberInner = outer.new MemberInner();
        memberInner.accessOuter();
        
        // 静态嵌套类
        Outer.StaticNested staticNested = new Outer.StaticNested();
        staticNested.accessOuter();
        
        // 局部内部类
        outer.methodWithLocalClass();
        
        // 匿名内部类
        outer.methodWithAnonymousClass();
    }
}