1. Java类的基本概念与创建方法
Java作为一门面向对象的编程语言,类(Class)是其最基本的组成单元。简单来说,类就是创建对象的模板,它定义了对象应有的属性和行为。在实际开发中,我们几乎每天都要和各种类打交道。
1.1 类的声明语法
创建一个Java类的基本语法如下:
java复制[访问修饰符] class 类名 [extends 父类] [implements 接口1, 接口2...] {
// 成员变量(属性)
[访问修饰符] 数据类型 变量名;
// 构造方法
[访问修饰符] 类名(参数列表) {
// 构造方法体
}
// 成员方法
[访问修饰符] 返回类型 方法名(参数列表) {
// 方法体
}
}
这里有几个关键点需要注意:
- 访问修饰符可以是public、protected、private或默认(不写)
- 类名遵循大驼峰命名规范(如StudentInfo)
- 一个.java源文件中只能有一个public类,且文件名必须与public类名相同
1.2 类的实际创建示例
让我们看一个具体的员工类创建示例:
java复制public class Employee {
// 成员变量
private String name;
private int age;
private String department;
// 构造方法
public Employee(String name, int age, String department) {
this.name = name;
this.age = age;
this.department = department;
}
// 成员方法
public void work() {
System.out.println(name + "正在" + department + "部门工作");
}
public void introduce() {
System.out.println("大家好,我是" + name + ",今年" + age + "岁");
}
}
提示:在实际开发中,建议将成员变量设为private,通过public的getter/setter方法来访问,这符合面向对象的封装原则。
1.3 类的实例化过程
创建了类之后,我们需要实例化它才能使用:
java复制public class Main {
public static void main(String[] args) {
// 创建Employee类的实例
Employee emp1 = new Employee("张三", 25, "研发");
Employee emp2 = new Employee("李四", 30, "市场");
// 调用对象的方法
emp1.work();
emp2.introduce();
}
}
当执行new Employee()时,JVM会:
- 在堆内存中分配空间
- 为对象成员变量赋默认值
- 执行构造方法中的初始化代码
- 返回对象引用
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Java类的详细分类体系
Java中的类可以根据不同的标准进行分类,理解这些分类对于编写高质量的Java代码非常重要。
2.1 按功能用途分类
2.1.1 POJO类(Plain Old Java Object)
POJO是最简单的Java类,只有属性和对应的getter/setter方法:
java复制public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
// 其他getter/setter...
}
POJO类通常用于数据传输,不包含业务逻辑。
2.1.2 工具类(Utility Class)
工具类通常包含静态方法,提供各种实用功能:
java复制public final class StringUtils {
// 私有构造方法防止实例化
private StringUtils() {}
public static boolean isEmpty(String str) {
return str == null || str.trim().length() == 0;
}
public static String reverse(String str) {
if (str == null) return null;
return new StringBuilder(str).reverse().toString();
}
}
工具类的特点:
- 构造方法私有化
- 所有方法都是静态的
- 通常声明为final防止继承
2.1.3 业务逻辑类
这类类包含核心的业务逻辑实现:
java复制public class OrderService {
private OrderDao orderDao;
private PaymentService paymentService;
public OrderService(OrderDao orderDao, PaymentService paymentService) {
this.orderDao = orderDao;
this.paymentService = paymentService;
}
public Order createOrder(OrderRequest request) {
// 验证请求参数
validateRequest(request);
// 创建订单
Order order = buildOrder(request);
// 处理支付
paymentService.processPayment(order);
// 保存订单
return orderDao.save(order);
}
// 其他业务方法...
}
2.2 按结构关系分类
2.2.1 普通类
普通类是最常见的类形式,可以独立存在:
java复制public class Rectangle {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double getArea() {
return width * height;
}
}
2.2.2 抽象类(Abstract Class)
抽象类不能实例化,用于定义子类的通用行为:
java复制public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法,子类必须实现
public abstract double getArea();
// 具体方法,子类可以直接使用
public String getColor() {
return color;
}
}
抽象类的特点:
- 可以包含抽象方法和具体方法
- 必须用abstract关键字修饰
- 子类必须实现所有抽象方法(除非子类也是抽象类)
2.2.3 接口(Interface)
接口定义了一组行为规范:
java复制public interface Drawable {
void draw();
default void printInfo() {
System.out.println("这是一个可绘制的对象");
}
static String getVersion() {
return "1.0";
}
}
Java 8之后,接口可以包含:
- 抽象方法(默认public abstract)
- 默认方法(default修饰)
- 静态方法(static修饰)
2.2.4 枚举类(Enum)
枚举类用于定义一组常量:
java复制public enum Day {
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");
private String chineseName;
private Day(String chineseName) {
this.chineseName = chineseName;
}
public String getChineseName() {
return chineseName;
}
}
枚举类的特点:
- 实例在类加载时创建
- 构造方法自动为private
- 可以实现接口但不能继承类
2.2.5 密封类(Sealed Class)
Java 15引入的密封类可以限制哪些类可以继承它:
java复制public sealed class Shape permits Circle, Square, Rectangle {
// 公共代码
}
final class Circle extends Shape {
// 圆形特有实现
}
non-sealed class Square extends Shape {
// 方形特有实现
}
final class Rectangle extends Shape {
// 矩形特有实现
}
密封类的特点:
- 使用sealed关键字声明
- 必须使用permits子句指定允许的子类
- 子类必须是final、sealed或non-sealed
2.3 按可见性分类
2.3.1 公共类(Public Class)
java复制public class PublicClass {
// 可以被任何其他类访问
}
公共类可以被项目中任何其他类访问,一个.java文件只能有一个public类。
2.3.2 默认类(Package-Private Class)
java复制class DefaultClass {
// 只能被同一个包中的类访问
}
不写访问修饰符的类具有包级可见性。
2.3.3 内部类(Inner Class)
内部类分为四种:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
java复制public class Outer {
private int outerField = 10;
// 成员内部类
class MemberInner {
void accessOuter() {
System.out.println("访问外部类字段: " + outerField);
}
}
// 静态内部类
static class StaticInner {
void doSomething() {
System.out.println("静态内部类方法");
}
}
void method() {
// 局部内部类
class LocalInner {
void show() {
System.out.println("局部内部类");
}
}
// 匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类实现");
}
};
}
}
3. 类设计的最佳实践与常见问题
3.1 类设计原则
3.1.1 单一职责原则(SRP)
一个类应该只有一个引起它变化的原因。例如:
java复制// 违反SRP的类
class Employee {
void calculateSalary() {...}
void saveToDatabase() {...}
void generateReport() {...}
}
// 符合SRP的设计
class Employee {
void calculateSalary() {...}
}
class EmployeeRepository {
void save(Employee emp) {...}
}
class ReportGenerator {
void generate(Employee emp) {...}
}
3.1.2 开闭原则(OCP)
类应该对扩展开放,对修改关闭。可以通过抽象和继承实现:
java复制abstract class Shape {
abstract double area();
}
class Circle extends Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
class Square extends Shape {
private double side;
Square(double side) {
this.side = side;
}
@Override
double area() {
return side * side;
}
}
3.1.3 里氏替换原则(LSP)
子类应该能够替换父类而不影响程序正确性:
java复制class Bird {
void fly() {
System.out.println("鸟儿飞翔");
}
}
class Ostrich extends Bird {
@Override
void fly() {
throw new UnsupportedOperationException("鸵鸟不会飞");
}
}
// 这违反了LSP,因为Ostrich不能替换Bird
3.2 常见问题与解决方案
3.2.1 循环依赖问题
当两个类相互依赖时:
java复制class A {
private B b;
// ...
}
class B {
private A a;
// ...
}
解决方案:
- 引入接口
- 使用依赖注入
- 重构设计,消除循环依赖
3.2.2 过度使用继承
继承层次过深会导致代码难以维护:
code复制Animal -> Mammal -> Dog -> DomesticDog -> MyDog
替代方案:
- 优先使用组合而非继承
- 使用接口定义行为
- 考虑使用装饰器模式
3.2.3 大而全的上帝类
一个类做了太多事情:
java复制class GodClass {
void processOrder() {...}
void generateReport() {...}
void sendEmail() {...}
void validateInput() {...}
// 几十个其他方法...
}
重构方法:
- 按功能拆分
- 提取工具类
- 使用策略模式
3.3 性能优化建议
3.3.1 对象创建优化
- 避免在循环中创建对象
- 重用不可变对象
- 考虑使用对象池
3.3.2 内存使用优化
- 及时释放不再使用的引用
- 注意内部类对外部类的隐式引用
- 谨慎使用静态集合
3.3.3 类加载优化
- 延迟加载(懒加载)
- 合理使用静态初始化块
- 避免类加载死锁
4. Java类的高级特性与应用
4.1 泛型类
泛型类可以增加代码的类型安全性和重用性:
java复制public class Box<T> {
private T content;
public Box(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
public static <E> Box<E> createBox(E content) {
return new Box<>(content);
}
}
// 使用示例
Box<String> stringBox = new Box<>("Hello");
Box<Integer> intBox = Box.createBox(100);
4.2 注解与反射
4.2.1 自定义注解
java复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String value() default "";
int version() default 1;
}
@MyAnnotation(value = "Test", version = 2)
public class AnnotatedClass {
// ...
}
4.2.2 反射操作类
java复制Class<?> clazz = Class.forName("com.example.MyClass");
// 获取类信息
String className = clazz.getName();
int modifiers = clazz.getModifiers();
// 创建实例
Object instance = clazz.getDeclaredConstructor().newInstance();
// 调用方法
Method method = clazz.getMethod("methodName", String.class);
method.invoke(instance, "参数值");
// 访问字段
Field field = clazz.getDeclaredField("fieldName");
field.setAccessible(true);
field.set(instance, "新值");
4.3 函数式接口与Lambda
Java 8引入的函数式接口:
java复制@FunctionalInterface
public interface MyFunctionalInterface {
void doSomething(String input);
default void log(String message) {
System.out.println(message);
}
}
// 使用Lambda表达式
MyFunctionalInterface func = str -> System.out.println(str.toUpperCase());
func.doSomething("hello");
4.4 记录类(Record)
Java 14引入的记录类,用于简化数据载体类的创建:
java复制public record Point(int x, int y) {
// 编译器自动生成:
// 1. final字段x和y
// 2. 全参数构造方法
// 3. equals()和hashCode()
// 4. toString()
// 可以添加额外方法
public double distanceFromOrigin() {
return Math.sqrt(x*x + y*y);
}
}
// 使用示例
Point p = new Point(3, 4);
System.out.println(p.x()); // 自动生成的访问器方法
System.out.println(p.distanceFromOrigin());
4.5 模式匹配与switch表达式
Java 17增强的模式匹配:
java复制// instanceof模式匹配
if (obj instanceof String s) {
System.out.println(s.length());
}
// switch表达式
String formatted = switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
5. 实际项目中的类设计案例
5.1 Spring框架中的类设计
5.1.1 控制器类
java复制@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody UserDto userDto) {
User created = userService.createUser(userDto);
return ResponseEntity.created(URI.create("/api/users/" + created.getId()))
.body(created);
}
}
5.1.2 服务类
java复制@Service
@Transactional
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserServiceImpl(UserRepository userRepository,
PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
@Override
public User createUser(UserDto userDto) {
User user = new User();
user.setUsername(userDto.getUsername());
user.setPassword(passwordEncoder.encode(userDto.getPassword()));
user.setEmail(userDto.getEmail());
return userRepository.save(user);
}
}
5.2 设计模式应用案例
5.2.1 工厂模式
java复制public interface Logger {
void log(String message);
}
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("写入文件: " + message);
}
}
public class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("控制台输出: " + message);
}
}
public class LoggerFactory {
public static Logger getLogger(String type) {
if ("file".equalsIgnoreCase(type)) {
return new FileLogger();
} else {
return new ConsoleLogger();
}
}
}
// 使用
Logger logger = LoggerFactory.getLogger("file");
logger.log("测试消息");
5.2.2 观察者模式
java复制public interface Observer {
void update(String message);
}
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
public class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(news);
}
}
public void setNews(String news) {
this.news = news;
notifyObservers();
}
}
public class NewsChannel implements Observer {
private String news;
@Override
public void update(String news) {
this.news = news;
display();
}
public void display() {
System.out.println("最新消息: " + news);
}
}
// 使用
NewsAgency agency = new NewsAgency();
NewsChannel channel1 = new NewsChannel();
NewsChannel channel2 = new NewsChannel();
agency.registerObserver(channel1);
agency.registerObserver(channel2);
agency.setNews("Java 17正式发布");
5.3 领域驱动设计(DDD)中的类
5.3.1 实体类(Entity)
java复制public class Order {
private Long id;
private String orderNumber;
private Customer customer;
private List<OrderItem> items;
private OrderStatus status;
// 业务方法
public void addItem(Product product, int quantity) {
// 业务逻辑...
}
public void cancel() {
if (status != OrderStatus.NEW) {
throw new IllegalStateException("只能取消新订单");
}
this.status = OrderStatus.CANCELLED;
}
// getter/setter...
}
5.3.2 值对象(Value Object)
java复制public class Address {
private final String street;
private final String city;
private final String zipCode;
public Address(String street, String city, String zipCode) {
this.street = street;
this.city = city;
this.zipCode = zipCode;
}
// 值对象通常不可变,没有setter
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return street.equals(address.street) &&
city.equals(address.city) &&
zipCode.equals(address.zipCode);
}
@Override
public int hashCode() {
return Objects.hash(street, city, zipCode);
}
}
5.3.3 聚合根(Aggregate Root)
java复制public class ShoppingCart {
private Long id;
private Customer customer;
private List<CartItem> items = new ArrayList<>();
public void addItem(Product product, int quantity) {
// 业务逻辑验证...
items.add(new CartItem(product, quantity));
}
public void removeItem(Product product) {
items.removeIf(item -> item.getProduct().equals(product));
}
public Order checkout() {
// 复杂的业务逻辑...
return new Order(this);
}
// 其他方法...
}
在实际项目中,合理的类设计可以显著提高代码的可维护性和可扩展性。根据我的经验,类的大小应该适中,既不要太大(超过500行代码),也不要太小(只有几行代码)。一个好的经验法则是:一个类的代码应该能在一屏内完整显示(约100-300行),这样开发者可以轻松理解整个类的结构和功能。
