Java面向对象编程

深入学习Java的面向对象编程特性,掌握类、对象、继承、多态、封装、抽象等核心概念和实现方法。

Java面向对象编程

面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它使用"对象"来设计应用程序和计算机程序。Java是一种纯面向对象的编程语言,本教程将带你深入学习Java的面向对象编程特性。

一、面向对象编程基础

1.1 面向对象编程的概念

面向对象编程是一种以对象为中心的编程思想,它将数据和对数据的操作封装在一个单元中,通过对象之间的交互来完成任务。

1.2 面向对象编程的四大特性

  • 封装:将数据和方法包装在类中,隐藏内部实现细节
  • 继承:允许一个类继承另一个类的属性和方法
  • 多态:允许不同类的对象对同一消息做出不同的响应
  • 抽象:通过抽象类和接口定义行为规范

二、类和对象

2.1 类的定义

类是对象的蓝图或模板,它定义了对象的属性(成员变量)和行为(方法)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class Person {
    // 成员变量(属性)
    private String name;
    private int age;
    private String gender;
    
    // 构造方法
    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    // 成员方法(行为)
    public void introduce() {
        System.out.println("大家好,我是" + name + ",今年" + age + "岁," + gender + "生。");
    }
    
    // getter和setter方法
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getGender() {
        return gender;
    }
    
    public void setGender(String gender) {
        this.gender = gender;
    }
}

2.2 对象的创建和使用

对象是类的实例,通过new关键字创建对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 创建Person对象
Person person1 = new Person("张三", 25, "男");
Person person2 = new Person("李四", 22, "女");

// 使用对象的方法
person1.introduce();  // 输出:大家好,我是张三,今年25岁,男生。
person2.introduce();  // 输出:大家好,我是李四,今年22岁,女生。

// 使用getter和setter
person1.setAge(26);
System.out.println(person1.getName() + "的年龄是" + person1.getAge());

2.3 构造方法

构造方法是一种特殊的方法,用于初始化对象。它的名称与类名相同,没有返回类型。

  • 默认构造方法:如果没有定义构造方法,编译器会自动生成一个无参数的默认构造方法
  • 有参构造方法:可以定义带参数的构造方法,用于初始化对象的属性
  • 构造方法重载:可以定义多个不同参数的构造方法
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Student {
    private String name;
    private int id;
    private double score;
    
    // 无参构造方法
    public Student() {
        this.name = "未知";
        this.id = 0;
        this.score = 0.0;
    }
    
    // 有参构造方法
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
        this.score = 0.0;
    }
    
    // 全参构造方法
    public Student(String name, int id, double score) {
        this.name = name;
        this.id = id;
        this.score = score;
    }
}

三、封装

3.1 封装的概念

封装是将数据和操作数据的方法结合起来,对对象的内部实现细节进行隐藏,只提供公共的接口供外部访问。

3.2 封装的实现

  • 使用访问修饰符控制成员变量的访问权限
  • 提供公共的getter和setter方法来访问和修改成员变量
  • 可以在setter方法中添加验证逻辑,确保数据的有效性
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class BankAccount {
    // 使用private修饰符隐藏成员变量
    private String accountNumber;
    private double balance;
    
    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        // 验证初始余额
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
        }
    }
    
    // 提供getter方法获取账户余额
    public double getBalance() {
        return balance;
    }
    
    // 提供公共方法存款
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存款成功,当前余额:" + balance);
        } else {
            System.out.println("存款金额必须大于0");
        }
    }
    
    // 提供公共方法取款
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取款成功,当前余额:" + balance);
        } else if (amount <= 0) {
            System.out.println("取款金额必须大于0");
        } else {
            System.out.println("余额不足");
        }
    }
}

3.3 访问修饰符

  • private:只有在同一类中可以访问
  • default(默认):在同一包中可以访问
  • protected:在同一包中或子类中可以访问
  • public:在任何地方都可以访问

四、继承

4.1 继承的概念

继承是指一个类(子类)可以继承另一个类(父类)的属性和方法,并可以添加自己的属性和方法。

4.2 继承的实现

在Java中,使用extends关键字实现继承。Java只支持单继承,但可以实现多个接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 父类
public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + "正在进食");
    }
    
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
}

// 子类
public class Dog extends Animal {
    // 子类特有的属性
    private String breed;
    
    // 子类构造方法
    public Dog(String name, String breed) {
        super(name);  // 调用父类构造方法
        this.breed = breed;
    }
    
    // 子类特有的方法
    public void bark() {
        System.out.println(name + "汪汪叫");
    }
    
    // 重写父类方法
    @Override
    public void eat() {
        System.out.println(name + "(" + breed + ")正在吃骨头");
    }
}

// 使用
Dog myDog = new Dog("小黑", "拉布拉多");
myDog.eat();    // 输出:小黑(拉布拉多)正在吃骨头
myDog.sleep();  // 输出:小黑正在睡觉
myDog.bark();   // 输出:小黑汪汪叫

4.3 super关键字

  • 调用父类的构造方法:super(参数);
  • 调用父类的成员变量:super.成员变量名
  • 调用父类的成员方法:super.成员方法名()

4.4 方法重写(Override)

子类可以重写父类的方法,以提供特定于子类的实现。重写的方法必须与父类方法具有相同的方法名、参数列表和返回类型。

五、多态

5.1 多态的概念

多态是指允许不同类的对象对同一消息做出不同的响应。Java中的多态主要通过方法重写和方法重载实现。

5.2 向上转型和向下转型

  • 向上转型:子类对象可以赋值给父类引用(自动类型转换)
  • 向下转型:父类引用转换为子类对象(需要强制类型转换,且要先进行类型检查)
1
2
3
4
5
6
7
8
9
// 向上转型
Animal animal = new Dog("小黑", "拉布拉多");
animal.eat();  // 输出:小黑(拉布拉多)正在吃骨头

// 向下转型
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();  // 输出:小黑汪汪叫
}

5.3 方法重载(Overload)

方法重载是指在同一个类中定义多个同名但参数列表不同的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Calculator {
    // 重载add方法
    public int add(int a, int b) {
        return a + b;
    }
    
    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

六、抽象类和接口

6.1 抽象类

抽象类是不能实例化的类,它可以包含抽象方法(没有实现的方法)和具体方法(有实现的方法)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 抽象类
public abstract class Shape {
    // 抽象方法(没有实现)
    public abstract double calculateArea();
    
    // 具体方法(有实现)
    public void display() {
        System.out.println("面积为:" + calculateArea());
    }
}

// 具体子类
public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double calculateArea() {
        return width * height;
    }
}

6.2 接口

接口是一种抽象类型,它定义了一组方法规范,但没有提供实现。一个类可以实现多个接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 接口定义
public interface Swimmable {
    void swim();
    String getSwimmingStyle();
}

public interface Runnable {
    void run();
    int getRunningSpeed();
}

// 实现多个接口
public class Human implements Swimmable, Runnable {
    private String name;
    
    public Human(String name) {
        this.name = name;
    }
    
    @Override
    public void swim() {
        System.out.println(name + "正在游泳");
    }
    
    @Override
    public String getSwimmingStyle() {
        return "自由泳";
    }
    
    @Override
    public void run() {
        System.out.println(name + "正在跑步");
    }
    
    @Override
    public int getRunningSpeed() {
        return 5; // 5米/秒
    }
}

6.3 抽象类和接口的区别

特性 抽象类 接口
实现方式 使用extends继承 使用implements实现
继承限制 只能继承一个抽象类 可以实现多个接口
方法类型 可以包含抽象方法和具体方法 Java 8之前只能包含抽象方法,之后可以包含默认方法和静态方法
成员变量 可以有各种修饰符的成员变量 只能有public static final修饰的常量
构造方法 可以有构造方法 不能有构造方法

七、内部类

7.1 内部类的概念

内部类是定义在另一个类内部的类,它可以访问外部类的所有成员,包括private成员。

7.2 内部类的类型

  • 成员内部类:定义在类中,方法外的非静态内部类
  • 局部内部类:定义在方法或代码块中的内部类
  • 匿名内部类:没有名称的内部类,通常用于实现接口或继承类
  • 静态内部类:使用static修饰的内部类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 外部类
public class OuterClass {
    private int outerVar = 10;
    private static int staticOuterVar = 20;
    
    // 成员内部类
    public class MemberInnerClass {
        public void accessOuter() {
            System.out.println("访问外部类实例变量:" + outerVar);
            System.out.println("访问外部类静态变量:" + staticOuterVar);
        }
    }
    
    // 静态内部类
    public static class StaticInnerClass {
        public void accessOuter() {
            // 不能访问外部类的实例变量
            // System.out.println("访问外部类实例变量:" + outerVar); // 编译错误
            System.out.println("访问外部类静态变量:" + staticOuterVar);
        }
    }
    
    // 方法中的局部内部类
    public void methodWithLocalClass() {
        class LocalInnerClass {
            public void display() {
                System.out.println("局部内部类访问外部变量:" + outerVar);
            }
        }
        
        LocalInnerClass local = new LocalInnerClass();
        local.display();
    }
    
    // 匿名内部类示例
    public void createAnonymousClass() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类实现Runnable接口");
            }
        };
        
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

// 使用内部类
OuterClass outer = new OuterClass();

// 使用成员内部类
OuterClass.MemberInnerClass memberInner = outer.new MemberInnerClass();
memberInner.accessOuter();

// 使用静态内部类
OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.accessOuter();

// 使用局部内部类
outer.methodWithLocalClass();

// 使用匿名内部类
outer.createAnonymousClass();

八、包装类

8.1 包装类的概念

包装类是基本数据类型的包装器,将基本数据类型转换为对象。Java为每种基本数据类型都提供了对应的包装类。

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

8.2 自动装箱和拆箱

  • 自动装箱:基本数据类型自动转换为包装类对象
  • 自动拆箱:包装类对象自动转换为基本数据类型
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 自动装箱
Integer i = 100;
Double d = 3.14;
Boolean b = true;

// 自动拆箱
int intValue = i;
double doubleValue = d;
boolean boolValue = b;

// 字符串转换为基本数据类型
int num = Integer.parseInt("100");
double decimal = Double.parseDouble("3.14");
boolean flag = Boolean.parseBoolean("true");

// 基本数据类型转换为字符串
String intStr = Integer.toString(100);
String doubleStr = Double.toString(3.14);
String boolStr = Boolean.toString(true);

九、学习建议

  1. 理解面向对象编程思想:不要只记住语法,要理解面向对象编程的本质和设计原则
  2. 掌握封装、继承、多态的使用:这些是面向对象编程的核心概念
  3. 学会使用抽象类和接口:它们是实现多态和代码组织的重要工具
  4. 多做练习:通过实际项目练习面向对象编程的应用
  5. 学习设计模式:设计模式是面向对象编程的最佳实践

结语

本教程介绍了Java面向对象编程的核心概念,包括类和对象、封装、继承、多态、抽象类和接口等。掌握这些知识对于编写高质量的Java程序至关重要。

面向对象编程是一种思维方式,需要不断地实践和积累经验。希望本教程对你的Java学习有所帮助!

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计