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;
// ...
}
小结
本章我们学习了:
- 类和对象的概念
- 类的定义和对象的创建
- 封装(私有化属性、Getter/Setter)
- 构造方法重载
- this 关键字
- static 关键字(静态属性、静态方法、静态代码块)
- 初始化块(实例初始化块、静态初始化块)
- 内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
- 对象的比较(equals、Comparable、Comparator)
- 对象的克隆(浅拷贝、深拷贝)
练习
- 创建一个学生类,包含姓名、学号、成绩属性
- 创建一个银行账户类,支持存款、取款、查询余额
- 创建一个矩形类,包含长、宽属性,计算面积和周长
- 创建一个手机类,包含品牌、型号、价格,使用封装
- 使用 Builder 模式创建一个复杂的配置类
- 实现一个可比较的 Book 类,按价格排序
- 实现深拷贝的 Person 类