Java基础系列文章
Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建
Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南
Java基础(七):面向对象编程核心解析 - POP vs OOP、类与对象、变量作用域及方法特性
函数
为中心,关注解决问题的步骤(先做什么、后做什么)“执行者思维”
,适合解决简单问题。扩展能力差、后期维护难度较大计算矩形面积和周长面向过程
写法:
public class ProceduralExample {
// 数据与函数分离
public static double calculateArea(double length, double width) {
return length * width;
}
public static double calculatePerimeter(double length, double width) {
return 2 * (length + width);
}
public static void main(String[] args) {
double length = 5.0;
double width = 3.0;
// 逐步调用函数
double area = calculateArea(length, width);
double perimeter = calculatePerimeter(length, width);
System.out.println("面积: " + area + ", 周长: " + perimeter);
}
}
对象
为中心,将问题分解为相互交互的实体(对象)“设计者思维”
,适合解决复杂问题。代码扩展性强、可维护性高计算矩形面积和周长面向对象
写法:
// 封装数据和操作
class Rectangle {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
// 方法绑定到对象
public double calculateArea() {
return length * width;
}
public double calculatePerimeter() {
return 2 * (length + width);
}
}
public class OOPExample {
public static void main(String[] args) {
// 创建对象并调用方法
Rectangle rect = new Rectangle(5.0, 3.0);
System.out.println("面积: " + rect.calculateArea() + ", 周长: " + rect.calculatePerimeter());
}
}
在Java中,类(Class)
和 对象(Object)
是面向对象编程(OOP)
的核心概念。它们的关系类似于“蓝图”
与“根据蓝图建造的具体实物”
。
定义:类是描述一类对象的模板
或蓝图
。它定义了对象的属性(字段)和行为(方法)
组成:
字段(Fields)
:对象的属性(如 String name;
)方法(Methods)
:对象的行为(如 void eat() {...}
)构造器(Constructor)
:创建对象时初始化状态的特殊方法示例:
// 定义一个"Dog"类
public class Dog {
// 字段(属性)
String breed;
int age;
String color;
// 构造器(初始化对象)
public Dog(String breed, int age, String color) {
this.breed = breed;
this.age = age;
this.color = color;
}
// 方法(行为)
void bark() {
System.out.println("汪汪!");
}
void sleep() {
System.out.println("睡觉中...");
}
}
定义:对象是类的实例
(Instance),是根据类创建的具体实体
特点:
状态
(字段的值)和行为
(方法的实现)new
关键字创建对象示例:
public class Main {
public static void main(String[] args) {
// 创建Dog类的对象
Dog myDog = new Dog("拉布拉多", 3, "黄色");
// 访问对象的字段
System.out.println("品种: " + myDog.breed); // 输出: 拉布拉多
// 调用对象的方法
myDog.bark(); // 输出: 汪汪!
}
}
定义:直接声明在类内部、方法/代码块外部
的变量
分类:
static
)static
,静态变量)示例:
public class Person {
// 实例变量(属于对象)
private String name; // 无static修饰
// 类变量(属于类)
public static int count; // 有static修饰
}
特点说明:
特性 | 说明 |
---|---|
作用域 | 整个类(类变量可跨类访问) |
生命周期 | 实例变量:随对象创建而存在,随对象回收而销毁类变量:随类加载而存在,随程序结束而销毁 |
存储位置 | 堆内存(实例变量在对象内)、方法区(类变量) |
初始化 | 自动赋予默认值(如 int 默认为 0,引用类型默认为 null) |
访问方式 | 实例变量:对象.变量名类变量:类名.变量名 或 对象.变量名(不推荐) |
修饰符 | 可用 public/private/protected/static/final 等 |
定义:声明在方法、构造方法、代码块或形参列表
中的变量
分类:
示例:
public void printInfo(int age) { // age是参数(局部变量)
String message = "Age: "; // 方法局部变量
{
int temp = 10; // 代码块局部变量(仅在此块内有效)
}
System.out.println(message + age);
}
特点说明:
特性 | 说明 |
---|---|
作用域 | 从声明处开始,到所属代码块结束(如方法/循环/条件体内部) |
生命周期 | 随方法/代码块的执行而创建,执行结束后销毁 |
存储位置 | 栈内存 |
初始化 | 必须手动初始化(否则编译报错) |
访问方式 | 直接通过变量名(仅在作用域内有效) |
修饰符 | 不可用static/访问修饰符(如 public),但可用 final |
在 Java 中,所有方法的参数传递都是值传递
。这意味着方法内部获得的是参数的副本
,而非原始变量本身。理解这一点对于基本数据类型
和引用类型(对象)
的行为至关重要。
传递的是值的副本,方法内修改参数不影响原始变量
示例:
void modify(int x) {
x = 20; // 修改的是副本
}
public static void main(String[] args) {
int a = 10;
modify(a);
System.out.println(a); // 输出 10(原始值未变)
}
对象地址的副本
,方法内通过该地址修改对象属性
会影响原始对象,但重新赋值引用
不影响原始引用因副本和原始引用指向同一对象
)修改的是副本地址
)示例1:修改对象属性(原始对象被改变
)
class Person {
String name;
Person(String name) { this.name = name; }
}
void changeName(Person p) {
p.name = "Bob"; // 修改副本指向的对象属性
}
public static void main(String[] args) {
Person person = new Person("Alice");
changeName(person);
System.out.println(person.name); // 输出 "Bob"(原始对象被修改)
}
示例2:重定向引用(原始引用不变
)
void createNewPerson(Person p) {
p = new Person("Bob"); // 副本指向新对象,原始引用不变
}
public static void main(String[] args) {
Person person = new Person("Alice");
createNewPerson(person);
System.out.println(person.name); // 输出 "Alice"(原始引用未变)
}
注意⚠️:Java 只有值传递!对于引用类型,传递的是引用的值(即对象地址的副本),而非引用本身(即不是引用传递)
相同的方法名
但参数列表不同
(参数类型、个数或顺序不同)父子类
中也可重载)完全相同
的名称类型
不同(如 int vs String)个数
不同(如 method() vs method(int a))顺序
不同(如 method(int a, String b) vs method(String b, int a))返回类型
(可不同)访问修饰符
(可不同)抛出的异常
(可不同)示例:
class Calculator {
// 重载add方法
public int add(int a, int b) {
return a + b;
}
public double add(int a, double b) { // 参数类型不同
return a + b;
}
public int add(int a, int b, int c) { // 参数个数不同
return a + b + c;
}
public double add(double a, int b) { // 参数顺序不同
return a + b;
}
// public double add(int a, int b) { // 只有返回值类型不同,编译失败
// return a + b;
// }
}
调用原理:编译器在编译时
根据参数类型
和数量
决定调用哪个方法(静态绑定)
Calculator calc = new Calculator();
calc.add(2, 3); // 调用 int add(int, int)
calc.add(2.5, 3.7); // 调用 double add(double, double)
calc.add("He", "llo"); // 调用 String add(String, String)
定义:子类重新定义从父类继承的方法
,提供特定实现
目的:实现运行时多态,允许子类定制父类行为
核心特点:
方法名称一致,参数类型、个数、顺序完全一致
返回类型:可以相同,也可以是父类返回类型的 子类型
访问权限:子类方法访问修饰符大于等于
不能比父类被重写方法修饰符
// 子类对象必须能够替代父类对象使用
// 假设父类的方法是 public,那么用户通过父类引用应该可以调用该方法:
class Parent {
public void show() {
System.out.println("Parent");
}
}
class Child extends Parent {
// 错误写法:降低访问权限
protected void show() {
System.out.println("Child");
}
}
// 在这种情况下:
Parent p = new Child();
p.show(); // 编译器会找 Parent 的 public show()
// ⚠️但如果 Child 中的 show() 是 protected,Java 编译器就无法访问这个方法
异常限制:子类方法抛出的异常小于等于
父类抛出异常
// 假设父类方法声明会抛出某个异常,那么你就可以在使用父类引用时,写出对应的异常处理代码
// 如果子类重写方法却抛出了更多或更广泛的异常
// 父类引用将无法预见这些额外的异常,程序可能在运行时出现无法捕获的错误
class Parent {
public void work() throws IOException {
// ...
}
}
class Child extends Parent {
@Override
public void work() throws Exception { // ❌ 错误!Exception 比 IOException 范围大
// ...
}
}
// ⚠️违反了任何使用父类的地方都应该能透明地替换成子类
只能重写实例方法,不能重写 static、final、private 方法:
static
方法属于类,不是实例,叫做方法隐藏(不是重写)final
方法不能被重写private
方法在子类中不可见,也不能被重写示例:
class Animal {
public void makeSound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override // 注解确保正确重写
public void makeSound() { // 重写父类方法
System.out.println("Dog barks: Woof!");
}
}
调用原理:JVM在运行时
根据对象实际类型决定调用哪个方法(动态绑定)
Animal myDog = new Dog(); // 向上转型
myDog.makeSound(); // 输出 "Dog barks: Woof!"