一、类与对象的复习
在Java世界里,类就像一个模板,定义了一类事物的共同特征和行为;而对象则是这个模板的具体实例。比如"汽车"是一个类,而你家的那辆红色小轿车就是一个对象。
包的作用
包(Package)就像文件夹,主要作用是:
- 避免类名冲突
- 便于管理大量类
- 控制访问权限
定义包的语法很简单:
package com.example.myapp; // 通常是公司域名倒写+项目名
成员变量的分类
特性 | 静态变量(类变量) | 实例变量(对象变量) |
---|---|---|
修饰符 | 有static | 无static |
存储位置 | 方法区 | 堆内存 |
初始化时机 | 类加载时 | 创建对象时(new) |
访问方式 | 类名.变量名 | 对象.变量名 |
示例:
public class Student {
// 静态变量(所有学生共享的学校名称)
public static String schoolName = "阳光中学";
// 实例变量(每个学生独有的属性)
public String name; // 姓名
public int age; // 年龄
}
使用方式:
// 访问静态变量
System.out.println(Student.schoolName);
// 访问实例变量
Student student = new Student();
student.name = "张三";
System.out.println(student.name);
成员方法的分类
特性 | 静态方法 | 实例方法 |
---|---|---|
修饰符 | 有static | 无static |
能否用this | 不能 | 能 |
访问成员 | 只能访问静态成员 | 可访问所有成员 |
调用方式 | 类名.方法名() | 对象.方法名() |
示例:
public class Calculator {
// 静态方法(工具方法)
public static int add(int a, int b) {
return a + b;
}
// 实例方法(需要对象状态的方法)
private int result;
public void accumulate(int num) {
this.result += num; // 使用this访问实例变量
}
}
二、构造器:对象的"出生证明"
构造器是一种特殊的方法,专门用于创建对象时初始化对象。
构造器的特点
- 名称必须与类名完全相同(包括大小写)
- 没有返回值类型(连void都不能写)
- 当你没写任何构造器时,编译器会自动生成一个无参构造器
- 一旦手动编写了构造器,默认的无参构造器就会消失
构造器示例
package com.example.oop;
public class Book {
private String title; // 书名
private String author; // 作者
private double price; // 价格
// 无参构造器
public Book() {
// 可以在这里设置默认值
this.title = "未知书名";
this.author = "未知作者";
}
// 有参构造器
public Book(String title, String author) {
this.title = title;
this.author = author;
}
// 全参构造器
public Book(String title, String author, double price) {
this.title = title;
this.author = author;
this.price = price;
}
// getter和setter方法
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
// 其他getter和setter省略...
public String getInfo() {
return "《" + title + "》 作者:" + author + " 价格:" + price + "元";
}
}
使用构造器创建对象:
public class TestBook {
public static void main(String[] args) {
// 使用无参构造器
Book book1 = new Book();
System.out.println(book1.getInfo());
// 使用有参构造器
Book book2 = new Book("Java编程思想", "Bruce Eckel");
book2.setPrice(108.0);
System.out.println(book2.getInfo());
// 使用全参构造器
Book book3 = new Book("深入理解Java虚拟机", "周志明", 89.0);
System.out.println(book3.getInfo());
}
}
三、封装:对象的"隐私保护"
封装是面向对象的三大特征之一,就像我们用快递盒包装物品一样,隐藏内部细节,只暴露必要的接口。
为什么需要封装?
- 保护数据安全,防止不合理的修改
- 隐藏实现细节,便于维护
- 控制访问权限,明确边界
四种权限修饰符
Java提供了四种权限修饰符,控制类和成员的可见范围:
修饰符 | 本类 | 本包其他类 | 其他包的子类 | 其他包的非子类 |
---|---|---|---|---|
private | √ | × | × | × |
缺省(默认) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
封装的实现方式
- 将属性私有化(使用private修饰)
- 提供公共的getter和setter方法
示例:
package com.example.encapsulation;
public class BankAccount {
// 属性私有化
private String accountNumber; // 账号
private double balance; // 余额
// 构造器
public BankAccount(String accountNumber) {
this.accountNumber = accountNumber;
this.balance = 0.0; // 新账户初始余额为0
}
// 存款方法(带业务逻辑的setter)
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("存款成功!存入:" + amount + "元,当前余额:" + balance + "元");
} else {
System.out.println("存款金额必须大于0!");
}
}
// 取款方法
public void withdraw(double amount) {
if (amount <= 0) {
System.out.println("取款金额必须大于0!");
return;
}
if (amount > balance) {
System.out.println("余额不足!当前余额:" + balance + "元");
return;
}
balance -= amount;
System.out.println("取款成功!取出:" + amount + "元,当前余额:" + balance + "元");
}
// getter方法(只允许获取,不允许直接修改)
public String getAccountNumber() {
return accountNumber;
}
public double getBalance() {
return balance;
}
}
使用示例:
public class TestBankAccount {
public static void main(String[] args) {
BankAccount account = new BankAccount("6222021234567890123");
// 尝试直接访问私有属性(编译错误)
// System.out.println(account.balance);
// 通过公共方法操作
account.deposit(1000);
account.withdraw(300);
account.withdraw(800); // 余额不足的情况
account.deposit(-500); // 存入负数的情况
System.out.println("账号:" + account.getAccountNumber());
System.out.println("最终余额:" + account.getBalance() + "元");
}
}
四、标准JavaBean:规范的Java类
JavaBean是一种遵循特定规范的Java类,就像生产标准零件一样,让类的使用更加统一和方便。
JavaBean规范
- 属性私有化(private)
- 提供公共的无参构造器
- 为每个属性提供公共的getter和setter方法
- 重写toString()方法(方便打印)
- 重写equals()和hashCode()方法(方便比较)
示例:
package com.example.bean;
import java.util.Objects;
public class User {
// 属性私有化
private Long id;
private String username;
private String email;
private int age;
private boolean vip;
// 无参构造器
public User() {
}
// 有参构造器(可选)
public User(String username, String email) {
this.username = username;
this.email = email;
}
// 全参构造器(可选)
public User(Long id, String username, String email, int age, boolean vip) {
this.id = id;
this.username = username;
this.email = email;
this.age = age;
this.vip = vip;
}
// getter和setter方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
// 其他getter和setter省略...
// 注意:boolean类型的getter通常以is开头
public boolean isVip() {
return vip;
}
public void setVip(boolean vip) {
this.vip = vip;
}
// 重写toString()方法
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", age=" + age +
", vip=" + vip +
'}';
}
// 重写equals()方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age &&
vip == user.vip &&
Objects.equals(id, user.id) &&
Objects.equals(username, user.username) &&
Objects.equals(email, user.email);
}
// 重写hashCode()方法
@Override
public int hashCode() {
return Objects.hash(id, username, email, age, vip);
}
}
使用示例:
public class TestUser {
public static void main(String[] args) {
User user1 = new User();
user1.setId(1L);
user1.setUsername("张三");
user1.setEmail("zhangsan@example.com");
user1.setAge(25);
user1.setVip(true);
User user2 = new User(1L, "张三", "zhangsan@example.com", 25, true);
User user3 = new User(2L, "李四", "lisi@example.com", 30, false);
System.out.println(user1); // 自动调用toString()
System.out.println("user1和user2是否相等:" + user1.equals(user2));
System.out.println("user1和user3是否相等:" + user1.equals(user3));
}
}
五、对象数组:批量管理对象
对象数组就是存储对象引用的数组,就像一个存放多个对象的容器。
对象数组的创建和使用
package com.example.objectarray;
public class Product {
private String id;
private String name;
private double price;
public Product() {
}
public Product(String id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
// getter和setter方法省略...
@Override
public String toString() {
return "商品ID:" + id + ",名称:" + name + ",价格:" + price + "元";
}
public double getPrice() {
return price;
}
}
使用对象数组:
public class TestProductArray {
public static void main(String[] args) {
// 1. 静态初始化
Product[] products1 = {
new Product("p001", "笔记本电脑", 5999.0),
new Product("p002", "智能手机", 3999.0),
new Product("p003", "平板电脑", 2999.0)
};
// 2. 动态初始化
Product[] products2 = new Product[3];
products2[0] = new Product("p004", "无线鼠标", 99.0);
products2[1] = new Product("p005", "机械键盘", 299.0);
products2[2] = new Product("p006", "蓝牙耳机", 499.0);
// 3. 遍历对象数组
System.out.println("所有商品:");
for (int i = 0; i < products1.length; i++) {
System.out.println(products1[i]);
}
for (Product p : products2) { // 增强for循环
System.out.println(p);
}
// 4. 对象数组排序(按价格从低到高)
System.out.println("\n按价格排序后:");
Product[] allProducts = new Product[products1.length + products2.length];
// 合并数组
System.arraycopy(products1, 0, allProducts, 0, products1.length);
System.arraycopy(products2, 0, allProducts, products1.length, products2.length);
// 冒泡排序
for (int i = 0; i < allProducts.length - 1; i++) {
for (int j = 0; j < allProducts.length - 1 - i; j++) {
if (allProducts[j].getPrice() > allProducts[j + 1].getPrice()) {
// 交换对象引用
Product temp = allProducts[j];
allProducts[j] = allProducts[j + 1];
allProducts[j + 1] = temp;
}
}
}
// 打印排序结果
for (Product p : allProducts) {
System.out.println(p);
}
}
}
总结
本文介绍了Java面向对象编程的几个重要概念:
- 构造器:用于初始化对象,是创建对象的重要途径
- 封装:通过权限修饰符和getter/setter方法保护数据
- JavaBean:规范的Java类,便于统一管理和使用
- 对象数组:用于批量管理对象,提高代码效率
这些概念是Java面向对象编程的基础,掌握它们有助于编写更规范、更安全、更易维护的代码。在实际开发中,我们会大量使用这些概念,特别是JavaBean和对象数组,它们在处理数据和业务逻辑时非常有用。