Java入门级教程6——动态绑定,方法重写和方法重载

#王者杯·14天创作挑战营·第5期#

目录

1. 动态绑定

1.1 定义

1.2 为什么需要动态绑定?

1.3 静态绑定 vs 动态绑定

1.4 示例

1.4.1 静态绑定

1.4.2 动态绑定

1.5 从不同角度分析动态绑定

1.5.1 从面向对象的角度:

1.5.2 从面向函数式编程的角度:

2. 方法重写与方法重载

2.1 定义与目的

2.2 方法重写的条件

2.3 关键区别对比

2.4 示例代码

2.4.1 方法重写示例

2.4.2 方法重载示例

2.5 常见混淆点


1. 动态绑定

1.1 定义

 动态绑定(Dynamic Binding)是面向对象编程中实现多态性的核心机制,它允许在运行时根据对象的实际类型(而非引用类型)来决定调用哪个方法。Java 通过动态绑定实现了方法重写(Override)的运行时行为。

1.2 为什么需要动态绑定?

 动态绑定解决了继承体系中方法调用的灵活性问题,主要目的是:

支持多态性:允许父类引用指向子类对象,并在运行时调用子类重写的方法。

遵循开闭原则:对扩展开放,对修改关闭。当新增子类时,无需修改现有代码即可实现新行为。

代码复用与扩展性:通过统一接口(父类方法)处理不同子类的特殊实现。

1.3 静态绑定 vs 动态绑定

维度静态绑定(Static Binding)动态绑定(Dynamic Binding)
绑定时机编译时运行时
依据变量的静态类型(声明类型)对象的实际类型(实例化类型)
适用场景方法重载(Overload)、私有方法、静态方法方法重写(Override)
灵活性低(编译后无法改变)高(可根据运行时对象类型动态调整)

1.4 示例

1.4.1 静态绑定

class Person {
    // 静态方法(静态绑定)
    public static void staticTalk() {
        System.out.println("Person的静态talk");
    }
    
    // 成员属性(静态绑定)
    public String name = "Person的名字";
}

class Teacher extends Person {
    // 静态方法(隐藏父类方法,不是重写)
    public static void staticTalk() {
        System.out.println("Teacher的静态talk");
    }
    
    // 成员属性(隐藏父类属性,不是重写)
    public String name = "Teacher的名字";
}

// 测试类
public class BindingTest {
    public static void main(String[] args) {
        // 父类引用指向子类对象(和之前多态语法一样)
        Person p = new Teacher();
        
        // 1. 调用静态方法:静态绑定,看引用声明类型(Person)
        p.staticTalk(); // 输出:Person的静态talk(不是Teacher的!)
        
        // 2. 访问成员属性:静态绑定,看引用声明类型(Person)
        System.out.println(p.name); // 输出:Person的名字(不是Teacher的!)
    }
}

1.4.2 动态绑定

class Person {
    // 非静态、非final、非private方法(可重写,动态绑定)
    public void talk() {
        System.out.println("人说");
    }
}

class Teacher extends Person {
    // 重写父类talk()(满足重写条件)
    @Override
    public void talk() {
        System.out.println("老师说");
    }
}

class Boss extends Person {
    // 重写父类talk()
    @Override
    public void talk() {
        System.out.println("老板说");
    }
}

// 测试类
public class BindingTest {
    public static void main(String[] args) {
        Person p; // 父类引用(声明类型固定为Person)
        
        // 1. p实际指向Teacher对象(运行时确定)
        p = new Teacher();
        p.talk(); // 动态绑定,看对象类型(Teacher)→ 输出:老师说
        
        // 2. p实际指向Boss对象(运行时改变)
        p = new Boss();
        p.talk(); // 动态绑定,看对象类型(Boss)→ 输出:老板说
    }
}

1.5 从不同角度分析动态绑定

1.5.1 从面向对象的角度:

动态绑定指的是:一个类指向多个实现子类

1.5.2 从面向函数式编程的角度:

动态绑定指的是:一个函数式接口可以指向多个函数表达式(符合参数列表相同,返回值类型相同)

  • 例1:
package com.hy.demo3;

//函数式接口注解(强制检查:仅允许一个抽象方法)
@FunctionalInterface
public interface Convert {
	
	// 抽象方法:定义“int转String”的行为标准
	public  String  intToString(int num);
	
}
package com.hy.demo3;

public class Operator {
	
	// 静态方法:实现“int转String”的具体逻辑
	public static String changeType(int num) {
		// 核心逻辑:调用JDK方法将int转为String
		return String.valueOf(num);
	}

}
package com.hy.demo3;

public class Test {
    // 核心方法:show(行为参数化的载体)
    // 参数1:num(要转换的数字,数据)
    // 参数2:c(Convert接口对象,代表“int转String”的行为)
    public static void show(int num, Convert c) {
        // 执行行为:调用Convert接口的方法,传入数据num,打印结果
        System.out.println(c.intToString(num));
    }

    public static void main(String[] args) {
        // 调用方式1:Lambda表达式(自定义行为,忽略传入的num)
        Test.show(100, (int n) -> { return "200"; });
        
        // 调用方式2:Lambda表达式(调用Operator的静态方法,使用传入的num)
        Test.show(100, (int n) -> { return Operator.changeType(n); });
        
        // 调用方式3:方法引用(简化方式2的Lambda,格式:类名::静态方法)
        Test.show(100, Operator::changeType);
    }
}

输出结果:

200
100
100

  • 例2:
package com.hy.demo4;

// 函数式接口注解:强制校验“仅包含一个抽象方法”
@FunctionalInterface
public interface Operator {
    // 抽象方法:定义“二元运算”的标准
    // 参数:a、b(两个待运算的int);返回值:运算结果(int)
    public int operatorNum(int a, int b);
}
package com.hy.demo4;

public class Test {
    // 核心方法:show(实现“数据+行为”的绑定)
    // 参数1/2:a、b(待运算的具体数据)
    // 参数3:op(Operator接口对象,代表“要执行的运算行为”)
    public void show(int a, int b, Operator op) {
        // 执行运算:调用Operator接口的抽象方法,传入数据a、b,得到结果
        int result = op.operatorNum(a, b);
        System.out.println("result值为:" + result);
    }

    public static void main(String[] args) {
        // 1. 创建Test实例(非静态方法show需要实例调用)
        Test t = new Test();
        
        // 2. 第一次调用show:传递“加法行为”(Lambda表达式)
        t.show(10, 20, (a, b) -> { return a + b; });
        
        // 3. 第二次调用show:传递“除法行为”(Lambda表达式)
        t.show(10, 20, (a, b) -> { return b / a; });
    }
}

输出结果:

result值为:30
result值为:2

2. 方法重写与方法重载

2.1 定义与目的

  • 方法重写(Override)
    发生在父子类之间,子类重新实现父类中已有的同名、同参数、同返回值类型的方法,用于修改或扩展父类行为。
    核心目的:实现多态性(运行时动态绑定)。

  • 方法重载(Overload)
    发生在同一个类中(或父子类中),多个方法具有相同名称但参数列表不同
    核心目的:通过参数的差异化提供相似功能的多种实现方式。

2.2 方法重写的条件

 方法重写,也叫运行时多态,在继承关系中,满足以下三个条件的方法叫做方法重写

① 子类和父类具有相同的方法名

② 相同的参数列表(包含相同的参数)

③ 相同的返回值类型

package com.hy.chapter5;

// 父类
public class Person {
	public void talk() {
		System.out.println("人说");
	}
}
// 子类
public class Boss extends Person{
    // 方法重写
	public void talk() {
		System.out.println("老板说");
	}
}

public class Teacher extends Person{
    // 方法重写
	public void talk() {
		System.out.println("老师说");
	}
}
package com.hy.chapter5;

public class BindObject {
	public void bindTalk(Person p) {
		p.talk();
	}

}
package com.hy.chapter5;

public class Test {
	public static void main(String[] args) {
//		Person p = new Boss();
//		p.talk();
//		p = new Teacher();
//		p.talk();
		BindObject bindObject = new BindObject();
		bindObject.bindTalk(new Teacher());
		bindObject.bindTalk(new Boss());
		//方法重写(运行机制),就是在运行期间,根据实际产生的对象,来决定调用那个重写方法
	}

}

2.3 关键区别对比

维度方法重写(Override)方法重载(Overload)
发生范围父子类之间同一个类中(或父子类中)
方法签名必须与父类方法完全相同(名称、参数、返回值方法名称相同,但参数列表必须不同(类型、顺序或数量)
返回值类型必须与父类方法相同(或协变类型,Java 5+)可以不同
访问修饰符子类方法不能比父类方法更严格(如父类protected,子类不能是private)无限制
异常声明子类方法不能抛出比父类更多的异常(子类异常≤父类异常无限制
调用机制运行时根据对象实际类型决定(动态绑定)编译时根据参数类型和数量决定(静态绑定)

2.4 示例代码

2.4.1 方法重写示例

class Animal {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {  // 重写父类方法
        System.out.println("Meow");
    }
}

2.4.2 方法重载示例

class Calculator {
    public int add(int a, int b) {  // 两个整数相加
        return a + b;
    }
    
    public double add(double a, double b) {  // 两个小数相加
        return a + b;
    }
    
    public int add(int a, int b, int c) {  // 三个整数相加
        return a + b + c;
    }
}

2.5 常见混淆点

  • 重写 vs 重载
    重写是 “父子类的垂直关系”,重载是 “同类的水平关系”。

  • 参数列表不同
    重载要求参数类型、数量或顺序至少有一项不同,仅返回值不同无法构成重载。例如:

    public void method(int a) {}
    public int method(int a) { return a; }  // 编译错误:仅返回值不同
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值