1.概念
面向对象 Object-Oriented Programming, 作为Java编程语言的核心思想,其实就是将现实世界中的事物抽象成对象, 并通过对象之间的交互来实现程序的功能。
1.1万事万物皆对象
Java语言的一种设计理念,在Java编程中,几乎所有的事物都可以被视为对象。每个对象都有自己的状态(即属性)和行为(即方法)。例如,一个人(Person)可以被看作是一个对象,他有姓名、年龄、性别等状态,有吃饭、睡觉、工作等行为。
在Java中,基本数据类型(如int、float、char等)是一个例外,它们不是对象。但是,为了能够将这些基本类型也当作对象处理,Java为每个基本数据类型都提供了一个包装类(如Integer、Float、Character等)。
此外,Java中的类(Class)本身也是对象。每个类都是java.lang.Class类的一个实例。例如,如果你有一个名为Person的类,那么Person.class就是一个Class类的实例。
这种"万事万物皆对象"的设计理念,使得Java编程更加灵活和统一,可以更好地利用面向对象的特性(如封装、继承、多态)来设计和实现代码。
2.面向对象的三个基本概念
2.1 类(class):类是对象的模板或蓝图。定义了一组对象的属性和行为。属性是类的状态的一部分,通常用变量来表示;行为则是类可以执行的操作,通常用方法来表示。例如,我们可以定义一个“学生”类,其中包含“姓名”、“年龄”等属性和“学习”、“睡觉”等行为。
2.2 对象:对象是类的实例。当我们根据类创建一个对象时,该对象将具有类定义的所有属性和行为。每个对象都有自己的状态(即属性的值),但它们共享相同的行为(即方法)。例如,我们可以创建一个名为"小明"的学生对象。
2.3 继承:继承是面向对象编程的一个重要特性,允许我们创建一个新的类,继承现有类的属性和行为,并可以添加新的属性和行为。这样,我们可以重用现有类的代码,避免重复编写相同的代码。例如,我们可以创建一个“大学生”类,继承“学生”类,并添加“参加社团活动”的行为。
3.详解四大特征
3.1封装
封装:一种将类的实现细节隐藏起来,只暴露公共接口的机制。Java 中可以使用访问控制符(public、private、protected)来控制类的成员的可见性,从而实现封装。主要目的是保护对象内部的状态数据。通过封装,我们可以隐藏对象的内部细节,只提供一个公开的接口供外部访问。
3.1.1 基本的封装
我们定义一个Person
类,将其属性name
和age
设置为私有(private
),并通过公开的getName
、setName
、getAge
和setAge
方法来访问和修改这些属性。
public class Person {
//封装属性,只通过get set方法来访问
private String name;
private int age;
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;
}
}
3.1.2 封装和数据验证
我们可以在setAge
方法中添加数据验证的逻辑,确保age
的值在合理的范围内。
public class Person {
private String name;
private int age;
// ...
public void setAge(int age) {
if (age >= 0 && age <= 120) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄必须在0到120之间");
}
}
}
3.1.3 封装和计算属性
我们可以定义一个Rectangle
类,其属性width
和height
是私有的,但我们可以提供一个公开的getArea
方法来计算矩形的面积。
public class Rectangle {
private double width;
private double height;
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getArea() {
return width * height;
}
}
3.1.4 封装集合
public class CustomList {
private List<Object> list = new ArrayList<>();
public void addItem(Object item) {
list.add(item);
}
public void removeItem(Object item) {
list.remove(item);
}
}
这个CustomList
类是对ArrayList
的一个简单封装。在这个类中,我们定义了一个私有的ArrayList
对象list
,这个list
对象是这个类的内部状态,外部代码不能直接访问。
然后,我们为这个类定义了两个公开的方法:addItem
和removeItem
。这两个方法是这个类对外提供的接口,外部代码可以通过这两个方法来操作list
对象,添加或删除元素。
这样,我们就隐藏了ArrayList
的具体实现细节,比如元素是如何存储的,如何实现添加和删除操作的等等。外部代码只需要知道如何使用addItem
和removeItem
这两个方法,就可以操作list
对象,而不需要了解ArrayList
的具体实现。
这就是封装的主要思想:隐藏对象的内部状态(内部状态其实就是这个类的属性)和实现细节,只提供一个公开的接口供外部代码访问。这样可以使代码更容易理解和使用,也可以保护对象的内部状态不被外部代码错误地修改。
3.1.5 封装数据库操作
封装数据库的增删改查操作,提供简单的接口,使得使用者不需要了解SQL语句的具体写法。
public class DatabaseHelper {
private Connection connection;
public DatabaseHelper(Connection connection) {
this.connection = connection;
}
public ResultSet query(String sql) {
// 执行SQL查询并返回结果集
}
public int update(String sql) {
// 执行SQL更新并返回影响的行数
}
// 其他数据库操作...
}
3.1.6 封装网络请求
封装HTTP的GET和POST请求,提供简单的接口,使得使用者不需要了解HTTP协议的具体细节。
public class HttpClient {
public String get(String url) {
// 发送GET请求并返回响应内容
}
public String post(String url, String body) {
// 发送POST请求并返回响应内容
}
}
这个HttpClient
类是对HTTP GET和POST请求的一个封装。在这个类中,我们定义了两个公开的方法:get
和post
。这两个方法是这个类对外提供的接口,外部代码可以通过这两个方法来发送HTTP请求。
在get
方法中,我们将实现发送HTTP GET请求的逻辑,并返回响应内容。在post
方法中,我们将实现发送HTTP POST请求的逻辑,并返回响应内容。这些具体的实现逻辑可能涉及到HTTP协议的很多细节,比如如何构造请求头,如何编码请求体,如何解析响应等等。
但是,对于使用这个HttpClient
类的代码来说,它不需要了解这些细节。它只需要知道如何使用get
和post
这两个方法,提供正确的URL和请求体,就可以发送HTTP请求并获取响应。
这就是封装的主要思想:隐藏实现的复杂性,只提供一个简单的接口供外部代码使用。这样可以使代码更容易理解和使用,也可以降低代码之间的耦合度,提高代码的可维护性。
3.2继承
继承是一种通过已有类创建新类的机制。通过继承,新类可以继承已有类的属性和方法,也可以在此基础上进行扩展和重载。
// 父类
public class Animal {
public void eat() {
System.out.println("Animal eats...");
}
}
// 子类
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog eats...");
}
}
例子中,Dog
类继承了Animal
类,同时重写了eat
方法。
注意:
一个类继承另一个类并不必须重写父类的所有方法。实际上,继承的主要目的就是为了复用父类的代码。当子类继承父类时,子类会自动拥有父类的所有属性和方法,除非子类显式地重写了父类的某个方法。
以下是几种可能的情况,子类可以不重写父类的方法:
-
子类需要父类的功能并且没有特殊的需求。在这种情况下,子类可以直接使用父类的方法,无需重写。
-
子类只需要重写父类的部分方法。如果子类只需要修改父类的部分行为,那么子类只需要重写那部分方法,其他方法可以保持不变。
-
子类需要扩展父类的功能。在这种情况下,子类可以添加新的方法,而不是重写父类的方法。
只有当子类需要改变父类的某个方法的行为时,才需要重写这个方法。重写父类的方法是面向对象编程中的一个重要特性,它允许子类在继承父类的同时,也可以定制自己的行为。
3.3多态
3.3.1 多态:多种形态
3.3.2 多态的表现方式
①方法的重写(Override):子类可以重写父类的方法,当通过父类引用调用这个方法时,实际执行的是子类的方法。这就是所谓的"运行时多态"或"动态绑定"。
②接口的实现:一个类可以实现一个或多个接口,然后通过接口引用调用接口中定义的方法,实际执行的是类的方法。
③类的多态性:一个引用变量可以指向任何类型的对象,只要这个对象的类型是引用变量的类型,或者是它的子类或实现的接口。这样,引用变量就可以在运行时动态地指向不同类型的对象,实现不同的行为。
public class Main {
public static void main(String[] args) {
// 父类引用指向子类对象,实现多态
Animal animal = new Dog();
// 调用的是Dog的eat方法
animal.eat();
}
}
例子中,虽然animal
的静态类型是Animal
,但是它的动态类型是Dog
,因此调用的是Dog
的eat
方法,这就是多态
3.4抽象
在Java中,指把一类事物的共同特性总结出来,形成类。
抽象可以分为两个层次:类的抽象和方法的抽象。
3.4.1 类的抽象
定义抽象类。抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类通常包含一些抽象方法,这些方法只有声明,没有具体的实现。
3.4.2 方法的抽象
定义抽象方法。抽象方法是一种特殊的方法,它只有声明,没有具体的实现。抽象方法必须在抽象类或者接口中定义,子类或者实现类必须实现这个抽象方法。