JavaSE高级(二)

static

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

1. static变量(类变量)
  • static修饰的变量叫做静态变量或类变量
  • 属于类,而不是某个特定对象
  • 所有实例共享一个静态变量
  • 在类加载时初始化
java 复制代码
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关键字
csharp 复制代码
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代码块
  • 用于初始化静态变量
  • 在类加载时执行,只执行一次
  • 可以有多个静态代码块,按顺序执行
ini 复制代码
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修饰的嵌套类称为静态嵌套类
  • 与外部类的实例无关,可以直接创建
  • 只能访问外部类的静态成员
csharp 复制代码
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. 继承的基本语法
scala 复制代码
class 父类 {
    // 父类的成员变量和方法
}

class 子类 extends 父类 {
    // 子类特有的成员变量和方法
}
2. 继承的特点
  • 代码复用:子类可以直接使用父类的非私有成员
  • 扩展性:子类可以添加自己的新成员
  • 单继承:Java只支持单继承(一个子类只有一个直接父类)
  • 多层继承:可以形成继承层次结构(A->B->C)
  • 构造方法不能继承:子类不能继承父类的构造方法,但可以通过super()调用
3. 继承示例
typescript 复制代码
// 父类
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注解明确表示这是重写方法
scala 复制代码
// 父类
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()不能同时出现在一个构造方法中
scala 复制代码
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:常量,值不能被修改
arduino 复制代码
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. 多态的实现方式
方法重载-编译时多态
csharp 复制代码
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)
    }
}
方法重写-运行时多态
scala 复制代码
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进行类型检查更安全
ini 复制代码
Animal animal = new Dog();
if (animal instanceof Dog) {
    Dog myDog = (Dog) animal;  // 向下转型
    myDog.bark();  // 可以调用Dog特有的方法
}
5.多态的应用场景
方法参数多态
csharp 复制代码
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());  // 输出"喵喵叫"
    }
}
返回类型多态
scala 复制代码
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");
    }
}
集合中的多态
csharp 复制代码
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. 综合示例
java 复制代码
// 父类
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修饰的变量表示常量,一旦被赋值就不能再修改

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

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

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

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

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

final方法不能被子类重写

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

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

final类不能被继承:

kotlin 复制代码
final class FinalClass {
    // 类内容
}

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

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

arduino 复制代码
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示例:不可变类
arduino 复制代码
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. 普通代码块(局部代码块)
  • 作用:限定变量的作用范围(局部变量生命周期)
  • 示例:
csharp 复制代码
public void demo() {
    int x = 10;
    System.out.println(x); // 正常访问

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

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

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

通过合理使用代码块

抽象类

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

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

(1)定义抽象类

使用abstract关键字声明:

csharp 复制代码
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)子类继承抽象类

子类必须实现所有的抽象方法:

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

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

(3)使用抽象类

typescript 复制代码
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. 经典示例:模版方法模式

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

csharp 复制代码
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. 不能实例化:不能直接创建接口的示例
接口定义语法
csharp 复制代码
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关键字实现接口:

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

示例代码:

typescript 复制代码
// 定义接口
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常量)
csharp 复制代码
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修饰的内部类
  • 不能直接访问外部类的非静态成员
  • 可以看做是一个普通的类,只是定义在另一个类内部
csharp 复制代码
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的局部变量
  • 作用域限于定义它的代码块
csharp 复制代码
class Outer {
    void outerMethod() {
        final int localVar = 20;
        
        class LocalInner {
            void display() {
                System.out.println("localVar = " + localVar);
            }
        }
        
        LocalInner inner = new LocalInner();
        inner.display();
    }
}
匿名内部类
  • 没有类名的内部类
  • 通常用于创建接口或抽象类的即时代码实现
  • 只能创建一个实例
csharp 复制代码
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中的事件处理器

示例代码:

csharp 复制代码
// 综合示例
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();
    }
}
相关推荐
徐小黑ACG7 分钟前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
战族狼魂3 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
杉之4 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch5 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
bobz9655 小时前
k8s 怎么提供虚拟机更好
后端
bobz9656 小时前
nova compute 如何创建 ovs 端口
后端
用键盘当武器的秋刀鱼6 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
Asthenia04127 小时前
从迷宫到公式:为 NFA 构造正规式
后端
Asthenia04127 小时前
像整理玩具一样:DFA 化简和状态等价性
后端
Asthenia04127 小时前
编译原理:打包思维-NFA 怎么变成 DFA
后端