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);
|
九、学习建议
- 理解面向对象编程思想:不要只记住语法,要理解面向对象编程的本质和设计原则
- 掌握封装、继承、多态的使用:这些是面向对象编程的核心概念
- 学会使用抽象类和接口:它们是实现多态和代码组织的重要工具
- 多做练习:通过实际项目练习面向对象编程的应用
- 学习设计模式:设计模式是面向对象编程的最佳实践
结语
本教程介绍了Java面向对象编程的核心概念,包括类和对象、封装、继承、多态、抽象类和接口等。掌握这些知识对于编写高质量的Java程序至关重要。
面向对象编程是一种思维方式,需要不断地实践和积累经验。希望本教程对你的Java学习有所帮助!