跳到主要内容

Java 面向对象编程

面向对象编程(OOP)是一种程序设计思想。本章将介绍类和对象的核心概念。

类和对象基础

什么是类?

类是一种抽象的数据类型,它定义了一类事物的共同属性和行为。

什么是对象?

对象是类的实例,是具体的存在。

定义类

public class Person {
// 属性(字段)
String name;
int age;
String gender;

// 构造方法
public Person() {
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 方法
public void speak() {
System.out.println("你好,我叫" + name + ",今年" + age + "岁");
}

public void eat() {
System.out.println("正在吃饭");
}
}

创建对象

public class Main {
public static void main(String[] args) {
// 创建对象
Person person = new Person("张三", 20);

// 访问属性
System.out.println(person.name); // 张三
System.out.println(person.age); // 20

// 调用方法
person.speak(); // 你好,我叫张三,今年20岁
}
}

封装

封装是将数据和操作隐藏在类内部,对外提供公共接口。

私有化属性

public class Person {
// 私有化属性
private String name;
private int age;

// 构造方法
public Person() {
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 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) {
if (age > 0 && age < 150) {
this.age = age;
}
}
}

使用封装

Person person = new Person();
person.setName("张三");
person.setAge(20);

System.out.println(person.getName()); // 张三
System.out.println(person.getAge()); // 20

构造方法重载

public class Person {
private String name;
private int age;
private String gender;

// 无参构造方法
public Person() {
}

// 有参构造方法
public Person(String name) {
this.name = name;
}

// 两个参数
public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 三个参数
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}

this 关键字

this 指向当前对象:

public class Person {
private String name;

public Person(String name) {
this.name = name; // this 区分局部变量和成员变量
}

public Person() {
this("默认名字"); // 调用另一个构造方法
}
}

static 关键字

静态属性

public class Person {
// 静态属性(所有对象共享)
public static int count = 0;

private String name;

public Person(String name) {
this.name = name;
count++; // 对象创建时计数加一
}
}

public class Main {
public static void main(String[] args) {
Person p1 = new Person("张三");
Person p2 = new Person("李四");

System.out.println(Person.count); // 2
}
}

静态方法

public class MathUtils {
public static int add(int a, int b) {
return a + b;
}

public static int max(int a, int b) {
return a > b ? a : b;
}
}

// 调用静态方法
int result = MathUtils.add(3, 5);

静态代码块

public class Person {
private String name;

// 静态代码块(类加载时执行一次)
static {
System.out.println("静态代码块执行");
}

public Person() {
System.out.println("构造方法执行");
}
}

初始化块

初始化块用于初始化类或对象,在构造方法之前执行。

实例初始化块

public class Person {
private String name;
private int age;

// 实例初始化块 - 每次创建对象时执行
{
System.out.println("实例初始化块执行");
name = "默认姓名"; // 可以初始化实例变量
}

public Person() {
System.out.println("构造方法执行");
}

public Person(String name) {
this.name = name;
System.out.println("带参构造方法执行");
}
}

// 执行顺序:实例初始化块 -> 构造方法
Person p1 = new Person();
// 输出:
// 实例初始化块执行
// 构造方法执行

Person p2 = new Person("张三");
// 输出:
// 实例初始化块执行
// 带参构造方法执行

静态初始化块

public class Database {
private static String connection;

// 静态初始化块 - 类加载时执行一次
static {
System.out.println("静态初始化块执行");
connection = "jdbc:mysql://localhost:3306/mydb";
}

public static String getConnection() {
return connection;
}
}

// 静态初始化块在类首次加载时执行
// 只执行一次,不管创建多少对象

初始化顺序

public class Order extends Parent {
private static int staticVar = initStaticVar();
private int instanceVar = initInstanceVar();

static {
System.out.println("3. 子类静态初始化块");
}

{
System.out.println("5. 子类实例初始化块");
}

public Order() {
System.out.println("6. 子类构造方法");
}

private static int initStaticVar() {
System.out.println("1. 子类静态变量初始化");
return 1;
}

private int initInstanceVar() {
System.out.println("4. 子类实例变量初始化");
return 1;
}
}

// 初始化顺序:
// 1. 父类静态变量和静态初始化块
// 2. 子类静态变量和静态初始化块
// 3. 父类实例变量和实例初始化块
// 4. 父类构造方法
// 5. 子类实例变量和实例初始化块
// 6. 子类构造方法

内部类

内部类是定义在另一个类内部的类,可以访问外部类的成员。

成员内部类

定义在类内部,与方法平级:

public class Outer {
private String name = "外部类";
private static String staticName = "静态外部类";

// 成员内部类
public class Inner {
private String name = "内部类";

public void show() {
System.out.println("内部类name: " + name); // 内部类
System.out.println("外部类name: " + Outer.this.name); // 外部类
}
}

public Inner getInner() {
return new Inner();
}
}

// 创建成员内部类对象
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.show();

// 或者通过方法创建
Outer.Inner inner2 = outer.getInner();

静态内部类

使用 static 修饰,不能访问外部类的非静态成员:

public class Outer {
private String name = "外部类";
private static String staticName = "静态外部类";

// 静态内部类
public static class StaticInner {
public void show() {
// 不能访问外部类的非静态成员
// System.out.println(name); // 编译错误

System.out.println(staticName); // 可以访问静态成员
}
}
}

// 创建静态内部类对象(不需要外部类实例)
Outer.StaticInner inner = new Outer.StaticInner();
inner.show();

局部内部类

定义在方法内部的类:

public class Outer {
public void method() {
final String localVar = "局部变量";

// 局部内部类
class LocalInner {
public void show() {
System.out.println("访问局部变量: " + localVar);
}
}

// 只能在方法内使用
LocalInner inner = new LocalInner();
inner.show();
}
}

匿名内部类

没有名字的内部类,常用于实现接口或继承类:

// 接口
interface Greeting {
void sayHello();
}

public class Demo {
public static void main(String[] args) {
// 使用匿名内部类实现接口
Greeting greeting = new Greeting() {
@Override
public void sayHello() {
System.out.println("你好,匿名内部类");
}
};
greeting.sayHello();

// 使用 Lambda 简化(如果接口是函数式接口)
Greeting greeting2 = () -> System.out.println("你好,Lambda");
greeting2.sayHello();

// 继承类的匿名内部类
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("线程运行中");
}
};
thread.start();

// 实现 Runnable 接口的匿名内部类
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程运行中");
}
});
thread2.start();

// Lambda 简化
Thread thread3 = new Thread(() -> System.out.println("线程运行中"));
thread3.start();
}
}

内部类的应用场景

// 1. 回调实现
public class Button {
interface OnClickListener {
void onClick();
}

private OnClickListener listener;

public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}

public void click() {
if (listener != null) {
listener.onClick();
}
}
}

// 使用
Button button = new Button();
button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击");
}
});

// 2. Builder 模式
public class Person {
private String name;
private int age;
private String email;

private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
}

// 静态内部类作为 Builder
public static class Builder {
private String name;
private int age;
private String email;

public Builder name(String name) {
this.name = name;
return this;
}

public Builder age(int age) {
this.age = age;
return this;
}

public Builder email(String email) {
this.email = email;
return this;
}

public Person build() {
return new Person(this);
}
}
}

// 使用
Person person = new Person.Builder()
.name("张三")
.age(25)
.email("[email protected]")
.build();

对象的比较

== 和 equals()

// == 比较的是引用(地址)
// equals() 默认也比较引用,但可以被重写

String s1 = new String("hello");
String s2 = new String("hello");

System.out.println(s1 == s2); // false(不同对象)
System.out.println(s1.equals(s2)); // true(String 重写了 equals)

// 自定义类需要重写 equals
public class Person {
private String name;
private int age;

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;

Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}
}

Comparable 接口

实现自然排序:

public class Person implements Comparable<Person> {
private String name;
private int age;

@Override
public int compareTo(Person other) {
// 按年龄升序
return this.age - other.age;

// 按年龄降序
// return other.age - this.age;

// 先按年龄,再按姓名
// int result = this.age - other.age;
// return result != 0 ? result : this.name.compareTo(other.name);
}
}

// 使用
List<Person> people = new ArrayList<>();
Collections.sort(people); // 使用自然排序

Comparator 接口

定义自定义比较器:

import java.util.Comparator;

// 方式1:实现 Comparator 接口
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}

// 使用
Collections.sort(people, new AgeComparator());

// 方式2:匿名内部类
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
});

// 方式3:Lambda 表达式
Collections.sort(people, (p1, p2) -> p1.getAge() - p2.getAge());

// 方式4:Comparator 方法引用
Collections.sort(people, Comparator.comparingInt(Person::getAge));

// 多条件排序
Collections.sort(people, Comparator
.comparingInt(Person::getAge)
.thenComparing(Person::getName));

// 逆序
Collections.sort(people, Comparator.comparingInt(Person::getAge).reversed());

对象的克隆

实现 Cloneable 接口

public class Person implements Cloneable {
private String name;
private int age;
private Address address; // 引用类型

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅拷贝
}

// 深拷贝
protected Person deepClone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) address.clone(); // 克隆引用类型
return cloned;
}
}

public class Address implements Cloneable {
private String city;

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

// 使用
Person p1 = new Person("张三", 20, new Address("北京"));
Person p2 = (Person) p1.clone(); // 浅拷贝
Person p3 = p1.deepClone(); // 深拷贝

使用序列化实现深拷贝

import java.io.*;

public class DeepClone {
@SuppressWarnings("unchecked")
public static <T> T deepCopy(T obj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

// 对象需要实现 Serializable 接口
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}

小结

本章我们学习了:

  1. 类和对象的概念
  2. 类的定义和对象的创建
  3. 封装(私有化属性、Getter/Setter)
  4. 构造方法重载
  5. this 关键字
  6. static 关键字(静态属性、静态方法、静态代码块)
  7. 初始化块(实例初始化块、静态初始化块)
  8. 内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
  9. 对象的比较(equals、Comparable、Comparator)
  10. 对象的克隆(浅拷贝、深拷贝)

练习

  1. 创建一个学生类,包含姓名、学号、成绩属性
  2. 创建一个银行账户类,支持存款、取款、查询余额
  3. 创建一个矩形类,包含长、宽属性,计算面积和周长
  4. 创建一个手机类,包含品牌、型号、价格,使用封装
  5. 使用 Builder 模式创建一个复杂的配置类
  6. 实现一个可比较的 Book 类,按价格排序
  7. 实现深拷贝的 Person 类