Java基础必学知识点 之 语言根基(三)

一、基础概念

1. 什么是面向对象?

对比 面向过程(C语言) 面向对象(Java)
关注点 怎么做(步骤) 谁来做(对象)
例子 把大象装冰箱:1.开门 2.装进去 3.关门 创建三个对象:大象冰箱,调用各自的方法
特点 数据和方法分离 数据和方法封装在对象中
  • 核心: 面向对象就是把现实世界中的“东西”直接映射成程序中的“对象”,每个对象有自己的数据(属性)和操作(方法)。

2. 类与对象

  • 类 (Class): 模板/蓝图,定义了一类事物共有的属性和行为。不占内存。
  • 对象 (Object): 根据类创建出来的具体实例。占内存,有具体的属性值。

示例:
定义一个 Student 类,创建多个学生对象。

// 1. 定义 Student 类(模板)
public class Student {
    // 成员变量(属性)
    String name;
    int age;
    String studentId;

    // 成员方法(行为)
    public void study() {
        System.out.println(name + " 正在学习...");
    }

    public void introduce() {
        System.out.println("大家好,我叫 " + name + ",今年 " + age + " 岁,学号是 " + studentId);
    }
}

// 2. 在另一个类(比如 Main)中创建对象
public class Main {
    public static void main(String[] args) {
        // 创建第一个学生对象
        Student stu1 = new Student();
        stu1.name = "张三";
        stu1.age = 18;
        stu1.studentId = "20240001";
        stu1.introduce(); // 输出:大家好,我叫 张三,今年 18 岁,学号是 20240001
        stu1.study();     // 输出:张三 正在学习...

        // 创建第二个学生对象
        Student stu2 = new Student();
        stu2.name = "李四";
        stu2.age = 19;
        stu2.studentId = "20240002";
        stu2.introduce(); // 输出:大家好,我叫 李四,今年 19 岁,学号是 20240002
    }
}

Student 类定义了“所有学生都有的东西”(姓名、年龄、学习),而 stu1stu2 是两个具体的、不同的学生实例。

  • 成员变量(属性): 对象拥有的数据,如 nameage
  • 成员方法(行为): 对象能执行的操作,如 study()

二、OOP 三大核心特征(重中之重)

1. 封装

  • 目的: 保护数据不被外部随意修改,隐藏内部的复杂实现细节。使用时只需要通过已经提供的 方法 来操作,而不是直接碰内部零件。

  • 实现:

    • private 修饰属性 → 外部不能直接访问。
    • publicgetter/setter → 提供受控的访问入口。
      提供 publicgetter(获取值)和 setter(设置值)方法,让外部通过方法来间接访问。在 setter 方法里,可以加入逻辑检查(比如余额不能为负数)。
  • 示例: 一个 BankAccount 类,余额不允许直接修改。

public class BankAccount {
    private String owner;    // 私有属性
    private double balance;  // 私有属性,不能直接修改

    // 构造方法(稍后细讲)
    public BankAccount(String owner, double initialBalance) {
        this.owner = owner;
        if (initialBalance > 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
        }
    }

    // Getter 方法:提供安全的读取方式
    public double getBalance() {
        return balance;
    }

    // 自定义的业务方法,而不是通用的 setter
    public void deposit(double amount) { // 存款
        if (amount > 0) {
            balance += amount;
            System.out.println("存款成功,当前余额:" + balance);
        } else {
            System.out.println("存款金额必须为正数");
        }
    }

    public void withdraw(double amount) { // 取款
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取款成功,当前余额:" + balance);
        } else {
            System.out.println("余额不足或金额无效");
        }
    }
}

// 测试
public class Main {
    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount("张三", 1000);
        // myAccount.balance = -100; // 错误!balance 是 private,无法访问
        System.out.println("当前余额:" + myAccount.getBalance()); // 输出:1000.0
        
        myAccount.deposit(500);   // 输出:存款成功,当前余额:1500.0
        myAccount.withdraw(2000); // 输出:余额不足或金额无效
        myAccount.withdraw(200);  // 输出:取款成功,当前余额:1300.0
    }
}

2. 继承

  • 概念: 一个类(子类)可以继承另一个类(父类)的属性和方法,实现代码复用。这是一个 “is-a” 的关系。Dog 一个 Animal

  • 关键字extends

  • 方法重写 (Override): 子类重新实现父类的方法。

  • super 关键字:在子类中调用父类的构造方法或成员。

  • 示例: AnimalDog / Cat

// 父类
public class Animal {
    String name;
    
    public void eat() {
        System.out.println(name + " 正在吃东西");
    }
}

// 子类 Dog
public class Dog extends Animal {
    // 子类特有的属性
    public String breed; // 品种

    // 方法重写 (Override)
    @Override
    public void eat() {
        System.out.println(name + " 正在啃骨头");
    }
    
    // 子类特有的方法
    public void bark() {
        System.out.println(name + " 汪汪叫");
    }
}

// 子类 Cat
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println(name + " 正在吃鱼");
    }
    
    public void meow() {
        System.out.println(name + " 喵喵叫");
    }
}

// 测试
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.eat();  // 输出:旺财 正在啃骨头 (调用的是重写后的)
        dog.bark(); // 输出:旺财 汪汪叫

        Cat cat = new Cat();
        cat.name = "咪咪";
        cat.eat();  // 输出:咪咪 正在吃鱼
        cat.meow(); // 输出:咪咪 喵喵叫
    }
}

3. 多态

  • 概念:同一个行为,作用于不同的对象,可以产生不同的结果。

  • 核心语法: 通过父类引用调用子类重写的方法 。例如:Animal myAnimal = new Dog();

  • 编译时类型 vs 运行时类型:

    • 编译时类型(声明类型)决定能调用哪些方法。
    • 运行时类型(实际类型)决定执行哪个版本的方法。

myAnimal编译时类型Animal,编译器只认 Animal 类里的方法(比如 eat())。
myAnimal运行时类型Dog,实际执行时,会执行 Dog 类里重写后的方法。

  • 多态的好处: 方法参数写成父类型,可以传入任意子类对象,扩展性强。

示例: 写一个 makeSound(Animal a) 方法

// 沿用上面的 Animal, Dog, Cat 类

public class Main {
    // 这个方法的参数是 Animal 类型,但你可以传入任何 Animal 的子类对象
    public static void makeSound(Animal a) {
        // 这里展示了多态:a 可能是 Dog,也可能是 Cat
        if (a instanceof Dog) {
            Dog d = (Dog) a; // 向下转型
            d.bark();
        } else if (a instanceof Cat) {
            Cat c = (Cat) a;
            c.meow();
        } else {
            a.eat(); // 默认行为
        }
    }
    
    // 更经典的多态例子
    public static void letAnimalEat(Animal a) {
        a.eat(); // 编译时看 Animal 有 eat(),运行时看具体子类的 eat()
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        Cat cat = new Cat();
        cat.name = "咪咪";
        
        letAnimalEat(dog); // 输出:旺财 正在啃骨头
        letAnimalEat(cat); // 输出:咪咪 正在吃鱼
        
        makeSound(dog); // 输出:旺财 汪汪叫
        makeSound(cat); // 输出:咪咪 喵喵叫
    }
}

三、进阶 OOP 相关语法

1. 构造方法

  • 特点: 方法名与类名相同,没有返回值。在创建对象时(new)自动调用,用于初始化对象。

  • 默认构造: 如果不写构造方法,Java 会提供默认无参构造。

  • 有参构造 & 重载:你可以定义多个构造方法,参数列表不同,方便用不同方式创建对象。

public class Person {
    String name;
    int age;
    
    // 无参构造
    public Person() {
    }
    
    // 有参构造(重载)
    public Person(String name) {
        this.name = name; // 用 this 区分成员变量和参数
        System.out.println("一个叫" + name + "的人被创建了");
    }
    
    // 另一个有参构造(重载)
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

2. this 关键字

  • 代表 当前对象 的引用。

  • 用途: 区分成员变量和局部变量(如this.name = name;)。

  • 关键用法:

    限制
    this.属性 / this.方法() 只能在非静态方法/构造方法中使用
    this(...) 调用构造方法 必须是构造方法中的第一条语句,且只能在构造方法中使用
  • 示例:

public class Student {
    private String name;
    private int age;
    
    // 构造方法1:两个参数
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("调用2参数构造方法");
    }
    
    // 构造方法2:只有姓名,年龄使用默认值
    public Student(String name) {
        this(name, 18);  // 调用上面的2参数构造方法
        System.out.println("调用1参数构造方法");
    }
    
    // 构造方法3:无参数,使用默认值
    public Student() {
        this("匿名", 18);  // 调用2参数构造方法
        System.out.println("调用无参数构造方法");
    }
    
    public static void main(String[] args) {
        Student s1 = new Student("张三", 20);
        Student s2 = new Student("李四");
        Student s3 = new Student();
    }
}

执行结果:
调用2参数构造方法
调用2参数构造方法
调用1参数构造方法
调用2参数构造方法
调用无参数构造方法

3. static 关键字

  • 实例变量/方法 静态变量/方法:
类型 属于 访问方式 共享性
实例变量/方法 对象 对象.xxx 每个对象独立一份
静态变量/方法 类名.xxx 所有对象共享一份
  • 静态方法中 不能直接访问 实例变量和实例方法(因为没有 this),但是可以通过对象引用来访问
public class School {
    public static String schoolName = "第一中学"; // 静态变量
    public String studentName;                  // 实例变量
    
    public static void printSchoolName() {      // 静态方法
        System.out.println("学校名称:" + schoolName);
        // System.out.println(studentName); // 错误!静态方法不能访问非静态变量
    }
    
    public void printInfo() {                   // 实例方法
        System.out.println(schoolName + " 的学生:" + studentName);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        System.out.println(School.schoolName); // 直接通过类名访问
        
        School s1 = new School();
        School s2 = new School();
        s1.studentName = "张三";
        s2.studentName = "李四";
        
        s1.printInfo(); // 输出:第一中学 的学生:张三
        s2.printInfo(); // 输出:第一中学 的学生:李四
    }
}

4. 代码块

  • 构造块: 写在类里,方法外的 { }。每次创建对象时,在 构造方法之前 执行。

  • 静态块:用 static { } 包裹。在 类第一次加载时 执行一次,常用于初始化静态变量。

public class Demo {
    static {
        System.out.println("静态块:类加载时执行一次");
    }
    
    {
        System.out.println("构造块:每次创建对象前执行");
    }
    
    public Demo() {
        System.out.println("构造方法执行");
    }
    
    public static void main(String[] args) {
        new Demo();
        System.out.println("---");
        new Demo();
    }
}
// 输出顺序:
// 静态块:类加载时执行一次
// 构造块:每次创建对象前执行
// 构造方法执行
// ---
// 构造块:每次创建对象前执行
// 构造方法执行

四、抽象 & 接口(非常重要)

1. 抽象类

抽象类是使用 abstract 关键字修饰的类,不能被实例化,主要用于被其他类继承。

  • 基本语法:
// 抽象类
public abstract class Animal {
    // 普通成员变量
    private String name;
    
    // 普通方法(有实现)
    public void eat() {
        System.out.println("动物吃东西");
    }
    
    // 抽象方法(没有方法体)
    public abstract void makeSound();
}
  • 抽象方法

  • 使用 abstract 关键字修饰。

  • 没有方法体(没有大括号和实现代码)。

  • 必须以分号结尾。

// 正确:抽象方法
public abstract void doSomething();

// 错误:抽象方法不能有方法体
public abstract void doSomething() { }  // 编译错误
  • 抽象类特点对比总结:
普通类 抽象类
能否实例化 可以 不可以
可以有抽象方法 不可以 可以
可以有普通方法 可以 可以
可以有构造方法 可以 可以
可以有成员变量 可以 可以
  • 示例:
public abstract class Vehicle {
    private String brand;
    private int speed;
    
    // 构造方法(子类可以调用)
    public Vehicle(String brand) {
        this.brand = brand;
        System.out.println("Vehicle构造方法被调用");
    }
    
    // 普通方法
    public void setSpeed(int speed) {
        this.speed = speed;
        System.out.println(brand + " 速度设置为: " + speed);
    }
    
    // 抽象方法
    public abstract void start();
    public abstract void stop();
}

// 子类必须实现所有抽象方法
public class Car extends Vehicle {
    public Car(String brand) {
        super(brand);  // 调用父类构造方法
    }
    
    @Override
    public void start() {
        System.out.println("汽车通过点火启动");
    }
    
    @Override
    public void stop() {
        System.out.println("汽车踩刹车停止");
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        // Vehicle v = new Vehicle();  // 错误:不能实例化抽象类
        
        Car car = new Car("特斯拉");
        car.start();    // 输出:汽车通过点火启动
        car.setSpeed(100);  // 输出:特斯拉 速度设置为: 100
        car.stop();     // 输出:汽车踩刹车停止
    }
}

2. 接口

  • 接口定义"规则"或"标准"。
  • 任何类只要遵守这些规则,就能被统一使用。
  1. 定义接口:
// 使用 interface 关键字,不是 class
public interface Animal {
    // 接口中的方法没有方法体(没有大括号)
    void eat();
    void sleep();
}
  1. 实现接口(使用 implements 关键字):
// 类使用 implements 实现接口
public class Dog implements Animal {
    // 必须实现接口中的所有方法
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    
    @Override
    public void sleep() {
        System.out.println("狗趴着睡觉");
    }
}

public class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    @Override
    public void sleep() {
        System.out.println("猫蜷缩着睡觉");
    }
}
  1. 使用接口:
public class Test {
    public static void main(String[] args) {
        // 接口不能直接创建对象
        // Animal a = new Animal();  错误!
        
        // 但可以用接口引用实现类的对象(多态)
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        dog.eat();   // 输出:狗吃骨头
        cat.eat();   // 输出:猫吃鱼
    }
}
  1. 核心:
特点 说明
不能实例化 new 接口名() 是错误的
多实现 一个类可以实现多个接口
多继承 接口可以继承多个接口
方法默认是 public abstract 可以不写,编译器自动加上
接口中可以定义常量,默认是 public static final 接口中的变量都是常量
  1. 接口的继承:
  • 接口可以继承多个接口。
interface A {
    void methodA();
}

interface B {
    void methodB();
}

// 接口可以多继承
interface C extends A, B {
    void methodC();
}

// 实现C的类必须实现所有方法(A、B、C中的)
public class MyClass implements C {
    @Override
    public void methodA() {
        System.out.println("实现A");
    }
    
    @Override
    public void methodB() {
        System.out.println("实现B");
    }
    
    @Override
    public void methodC() {
        System.out.println("实现C");
    }
}

3. 抽象类 vs 接口(初学者必知)

对比项 抽象类 接口
关键字 abstract class interface
继承/实现 单继承 多实现
构造方法 可以有 不能有
成员变量 可以是普通变量 只能是常量
普通方法 可以有 默认方法/静态方法
何时使用 "是什么"关系 "能做什么"关系
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐