当前位置: 首页 > article >正文

类和对象(4)——多态:方法重写与动态绑定、向上转型和向下转型、多态的实现条件

目录

1. 向上转型和向下转型

1.1 向上转型

1.2 向下转型

1.3 instanceof关键字

2. 重写(overidde)

2.1 方法重写的规则

2.1.1 基础规则

2.1.2 深层规则

2.2 三种不能重写的方法

final修饰

private修饰 

static修饰

3. 动态绑定

3.1 动态绑定的概念

3.2 动态绑定与静态绑定

4. 多态

4.1 多态的实现场景

1. 基类形参方法 

2. 基数组

4.2 多态缺陷

1. 属性(字段)没有多态性 

2. 向上转型不能使用子类特有的方法

3. 构造方法没有多态性


上一篇文章中,我们深度学习了继承的概念与实现。在继承篇中,我们最重要的就是“弄清楚通过子类实例变量来访问与父类相同的成员会怎么样”;而在多态篇中,最核心的内容就是“弄清楚通过父类实例变量来访问与子类相同的方法会怎么样”。

1. 向上转型和向下转型

在了解多态之前,我们还要补充几个知识点,这首先就是向上转型和向下转型。

1.1 向上转型

向上转型是指将一个子类对象的引用赋值给一个父类类型的实例变量

语法格式:

父类类型 对象名 = new 子类类型();

//例如 Animal animal = new Cat("小咪", 2);

animal是父类类型的实例变量,但引用的是一个子类Cat对象,因为这是从小范围向大范围的转换。类似基础数据类型中的隐式类型转换(例如长整形long接收整形int的数据)


向上转型的3种使用场景:

  1. 直接赋值:子类对象的引用直接赋值给父类类型的实例变量
  2. 方法传参:子类对象的引用作为参数,传递给方法中的父类类型的形参
  3. 方法返回:方法的返回类型是父类类型返回的值是子类类型

例如:

public class TestAnimal {// 2. 方法传参:形参为父类型引用,可以接收任意子类的对象public static void eatFood(Animal a){a.eat();}// 3. 作返回值:返回任意子类对象public static Animal buyAnimal(String var){if("狗".equals(var) ){return new Dog("狗狗",1);}else if("猫" .equals(var)){return new Cat("猫猫", 1);}else{return null;}}public static void main(String[] args) {Animal cat = new Cat("元宝",2);   // 1. 直接赋值:子类对象赋值给父类对象Dog dog = new Dog("小七", 1);eatFood(cat);eatFood(dog);Animal animal = buyAnimal("狗");animal.eat();animal = buyAnimal("猫");animal.eat();}}

1.2 向下转型

向下转型是将父类对象强制转换为子类对象的过程,需要用到类型转换运算符( ) 。

【注意】

  • 只能对已向上转型的对象进行向下转型:不能直接将一个父类对象强制转换为子类对象,除非这个父类对象实际上是子类对象的向上转型。也就是说,必须先创建一个子类对象,然后将其向上转型为父类对象,最后再进行向下转换。
  • 向上转型的子类类型 与 向下接收的子类类型必须一致

例如:

先看父类和子类的具体代码:

public class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃东西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗粮");}//Dog类的专属方法public void bark(){System.out.println(name+"在汪汪叫");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃猫粮");}//Cat类的专属方法public void mew(){System.out.println(name+"在喵喵叫");}
}

测试1:父类实例animal是Dag类的向上转型,再让animal向下转型传给子类实例dog。

public class Test {public static void main(String[] args) {Animal animal = new Dog("旺财");Dog dog;dog = (Dog) animal;dog.bark();}
}

运行成功


测试2:父类实例animal是Dag类的向上转型,再让animal向下转型传给子类实例cat。(向上转型的子类与向下接收的子类不一致

public class Test {public static void main(String[] args) {Animal animal = new Dog("旺财");Cat cat;cat = (Cat) animal;//抛出异常}
}

抛出异常


1.3 instanceof关键字

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了instanceof关键字。

语法:

        Object  instanceof  ClassName

其中,object 是要测试的对象或实例变量,ClassName 是要测试的类名。

作用和返回值:

如果 object 是 ClassName 的实例其子类的实例,则表达式返回 true;否则返回 false

有了instanceof,我们向下转型就可以更安全了:

public class TestAnimal {public static void main(String[] args) {Cat cat = new Cat("元宝",2);Dog dog = new Dog("小七", 1);// 向上转型Animal animal = cat;animal.eat();animal = dog;animal.eat();if(animal instanceof Cat){    //检查类型cat = (Cat)animal;cat.mew();}if(animal instanceof Dog){    //检查类型dog = (Dog)animal;dog.bark();}}}

animal最后是Dog类的引用,所以通过了第2个检查,由dog接收animal的向下转型。

2. 重写(overidde)

2.1 方法重写的规则

2.1.1 基础规则

方法重写:也称为方法覆盖,即外壳不变,核心重写。

  1. 子类在重写父类的方法时,一般必须与父类的方法原型一致【返回值类型、方法名、参数列表完全一致】。 
  2. 重写的方法,可以在子类方法头的上一行使用“ @Override ”注解来显式指定。有了这个注解能帮我们进行一些合法性校验(例如不小心将方法名字拼写错了,比如eat写成 aet,那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写)

例如:

如果显示指定@overidde,但方法与父类原型不一致的话,系统会报错:

2.1.2 深层规则

  1. 返回值类型:其实子类重写的方法返回类型也可以与父类不一样,但是必须是具有父子关系的。       
    1.  该要求其实隐藏了一个情况,那就是此时的方法返回值类型是类类型的。
    2.  对于这种情况的方法重写,父类方法的返回值类型 必须是 子类方法的返回值类型基类
  2. 访问限定符:访问权限不能比父类中被重写的方法的访问权限更低。(即子类重写的方法访问权限可以更宽松,不能更严格)

对于“返回值类型”要求的举例:

​class Parent {public Number display() {return 42; // 返回一个Integer类型的值}
}class Child extends Parent {// 重写父类的display方法,并改变返回类型为Double,这是允许的,因为Double是Number的子类型@Overridepublic Double display() {return 42.0;}
}public class Test {public static void main(String[] args) {Parent parent = new Parent();System.out.println(parent.display()); // 输出: 42Child child = new Child();System.out.println(child.display()); // 输出: 42.0}
}

Parent类的display方法的返回类型是Number类,Child类的display方法的返回类型是Double类。其中Parent类是Child类的父类,Number类又是Double类和Interger类的父类,这符合方法重写的深层规则。

如果该例子中的 方法返回值类型的父子关系反过来 会报错:


对于“访问限定符”要求的举例:


关于方法重写还有更深层更严格的规定,这些规定与异常、线程等有关。本章重点是继承与多态,所以不再具体展开。

2.2 三种不能重写的方法

如果父类方法被final、private或static修饰,则子类不能重写该方法。

final修饰

final:

final修饰成员方法时,就是用来防止该方法被子类重写 或者 不想让该方法被重写。

例如:


private修饰 

private:

父类的方法被private修饰时,说明这个方法是父类私有的,子类也没有办法去访问该方法。

  • 如果private修饰了父类的方法,子类又写了一个与父类方法原型一样的方法,系统并不会报错
    (因为系统检查方法重写时,会自动把父类的私有方法忽略掉)
  • 如果private修饰了子类的方法,父类又有一个与子类方法原型一样的非private方法,那么系统会报错
    (此时系统会认为你想要让子类重写父类方法,又因为重写后的方法是私有的而父类的方法非私有,所以会提醒你“分配了更低的访问权限”并报错)

例1:

父类方法是私有的,build没有问题

例2:

子类方法是私有的,父类方法原型与子类一致。系统认为你要重写,但子类的方法权限更低,所以报错:


static修饰

static:

静态方法是在类加载时就绑定到类本身,而不是在运行时绑定到具体的对象实例,所以static修饰的方法不能被重写。即静态方法不能实现动态绑定,也就不能被覆盖(重写)。

例如:

虽然静态方法是可以被继承的,但如果子类定义了一个与父类相同签名的静态方法这只是对父类静态方法的一种隐藏,而非真正意义上的重写。

  • 子类对象向上转型后,当通过父类实例变量引用调用该方法时,仍然会执行父类的静态方法,而不是子类的静态方法。

例如:

class Parent {static void display() {System.out.println("Parent display method");}
}class Child extends Parent {static void display() {System.out.println("Child display method");}
}public class Test {public static void main(String[] args) {Parent parent1 = new Parent();parent1.display();  //调用父类静态方法Child child = new Child();child.display();   //调用子类静态方法Parent parent2 = new Child();   //向上转型parent2.display();  //调用父类静态方法}
}

3. 动态绑定

3.1 动态绑定的概念

刚刚在解释static修饰方法时,我们提到了一个词叫动态绑定。下面让我们看看什么是动态绑定。

概念:

动态绑定也叫后期绑定,是指在运行时根据对象的实际类型来确定调用哪个方法,而不是在编译时就决定。当一个父类引用指向其子类的对象,并且通过该引用调用一个被重写的方法时,会在运行时根据对象的实际类型来调用相应的方法实现,这就是重写方法的动态绑定。

动态绑定重写方法的实现条件:

  1. 存在继承关系必须有一个基类(父类)和至少一个派生类(子类),子类继承自父类。
  2. 方法重写子类要实现父类中至少一个方法的重写。
  3. 向上转型在程序中存在向上转型的情况,即把子类对象的引用赋值给父类的实例变量

例如:

class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃东西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗粮");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃猫粮");}
}public class Test {public static void main(String[] args) {Animal animal = new Animal("动物");//animal动态绑定到Animal类animal.eat();animal = new Dog("小狗");//animal动态绑定到Dog类animal.eat();animal = new Cat("小猫");//animal动态绑定到Cat类animal.eat();}
}

3.2 动态绑定与静态绑定

静态绑定也称为早期绑定:是指在程序编译时就已经确定了方法调用的具体对象和方法实现。与动态绑定相对应,静态绑定不需要运行时进行额外的判断和查找来确定调用哪个方法。

静态绑定的适用情况

  • 基本数据类型的方法调用(可重载的方法):对于基本数据类型的操作方法,如数学运算等,通常是静态绑定。例如,int a = 5; int b = 10; int c = a + b; 中 + 运算符对应的加法方法是在编译时就确定的。
  • 私有方法、静态方法和 final 方法:这些方法不能被重写或具有特殊的性质,所以它们的调用可以在编译时确定。例如,class Example { private void privateMethod() {...} static void staticMethod() {...} final void finalMethod() {...} } 中的私有方法、静态方法和 final 方法都是静态绑定的。
  • 构造方法:构造方法在创建对象时被调用,每个类都有特定的构造方法,且在编译时就可以确定是哪个类的构造方法会被调用。例如,new Example() 会调用 Example 类的构造方法,这是在编译时就已经决定的。

方法重载(静态绑定)是一个类的多态性表现【例如工具类Arrays】,而方法重写(动态绑定)是子类与父类间的多态性的表现。

4. 多态

多态的概念:

去完成某个行为时,当不同的对象去完成时会产生出不同的状态。又或者同一件事情,发生在不同对象身上,就会产生不同的结果

打个比方,语文老师要求同学们背一首诗,同学A背了一首李白的诗、同学B背了一首杜甫的诗、同学C背了一首李清照的诗……每个同学背的诗都不同,但不管怎么说他们都完成了“背一首诗”的任务,这就是多态。

4.1 多态的实现场景

在java中要实现多态,必须要满足如下几个条件,缺一不可:

  1. 必须在继承体系下 
  2. 子类必须要对父类中方法进行重写 
  3. 通过父类的引用调用

下面我来介绍两种常见的多态实现。

1. 基类形参方法 

基类形参方法:指的是形参数据类型为基类类型的方法。

该方法的形参的类型是父类类型,我们一般在该方法中使用被重写的方法。不同的子类实例变量传参进去并发生向上转型,该基类形参方法就能够通过动态绑定来调用不同的重写方法,从而实现多态。

例如:

//有继承关系的类
public class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃东西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗粮");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃猫粮");}
}
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
//含基类形参方法的类
public class Test {public void eat(Animal animal){ //基类形参方法animal.eat();}public static void main(String[] args) {Test test = new Test();    //如果Test的eat方法是静态方法,那么可以不用new一个Test对象test.eat(new Animal("小动物"));test.eat(new Dog("小狗"));test.eat(new Cat("小猫"));}
}


这种方法有点类似C语言中的函数指针和回调函数的用法。详细请看《指针之旅(4)—— 指针与函数:函数指针、转移表、回调函数》

2. 基数组

基数组:指的是数组元素的类型都是基类类型。

由于可以向上转型,在基数组中可以存放子类对象,从而实现多态。

(有点类似C语言中的函数指针数组)

例如:

​//Animal类、Dog类和Cat类的内容如上面的一致
public class Test {public static void main(String[] args) {//基数组animalsAnimal[] animals = {new Animal("小动物"), new Dog("小狗"), new Cat("小猫")};for(Animal x: animals){x.eat();    //临时变量x通过动态绑定实现多态}}
}

如果有新的动物增加,我们可以在基数组animals中添加,这就是多态的好处,十分便捷。

如果不基于多态来实现刚刚的代码内容,我们需要多个if-else语句,如下:

在这种情况下,如果要增加一个动物,不仅字符串数组animals要变,而且在for-each循环中还要加多一条else-if语句,十分不便。

4.2 多态缺陷

1. 属性(字段)没有多态性 

当父类和子类都有同名属性的时候,通过父类实例变量引用只能引用父类自己的成员属性

例如:

public class Parent {public String str = "parent";
}public class Child extends Parent{public String str = "child";
}public class Test {public static void main(String[] args) {Parent parent = new Parent();System.out.println(parent.str);//打印parentChild child = new Child();System.out.println(child.str);//打印childparent = child;     //向上转型System.out.println(parent.str);//属性没有多态性,打印的还是父类的str}
}

2. 向上转型不能使用子类特有的方法

方法调用在编译时进行类型检查,编译器只检查引用变量类型中定义的方法,而不考虑实际对象的类型

例如,这里子类Dog比父类Animal类多了一个特殊方法bark()。如果用Animal类型的实例变量来接收Dog类的对象,我们会发现无法通过该实例变量调用bark方法:

3. 构造方法没有多态性

父类的构造方法中调用一个被重写的方法时,实际执行的是子类中的实现。然而,此时子类可能还未完成初始化,其成员变量尚未赋值或处于默认状态,这就可能导致程序行为不确定,甚至引发错误。

父类构造方法中如果调用了被重写的方法,那么该重写的方法使用的是子类的方法

我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func:

​
class B {public B() {// do nothingfunc();}public void func() {System.out.println("B.func()");}
}class D extends B {private int num = 10;@Overridepublic void func() {System.out.println("D.func() " + num);}
}public class Test {public static void main(String[] args) {D d = new D();}
}​

  • 构造 D 对象的同时,会调用 B 的构造方法.
  • B 的构造方法中调用了 func 方法, 此时会触发动态绑定,会调用到 D 中的 func 。此时 D 对象自身还没有构造,此时 num 处在未初始化的状态,值为 0.
  • 如果具备多态性,num的值应该是10.

结论: "用尽量简单的方式使对象进入可工作状态", 尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触 发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题。


本期分享完毕,感谢大家的支持Thanks♪(・ω・)ノ

相关文章:

类和对象(4)——多态:方法重写与动态绑定、向上转型和向下转型、多态的实现条件

目录 1. 向上转型和向下转型 1.1 向上转型 1.2 向下转型 1.3 instanceof关键字 2. 重写(overidde) 2.1 方法重写的规则 2.1.1 基础规则 2.1.2 深层规则 2.2 三种不能重写的方法 final修饰 private修饰 static修饰 3. 动态绑定 3.1 动态绑…...

系统思考—问题分析

很多中小企业都在面对转型的难题:市场变化快,资源有限,团队协作不畅……这些问题似乎总是困扰着我们。就像最近和一位企业主交流时,他提到:“我们团队每天都很忙,但效率始终没见提升,感觉像是在…...

第24篇:Python开发进阶:掌握Python编程中的调试技巧

第24篇:调试技巧 内容简介 在软件开发过程中,调试是确保代码正确性和稳定性的关键步骤。有效的调试技巧不仅能帮助开发者快速定位和修复错误,还能提升代码的整体质量和可维护性。本篇文章将探讨如何使用Python内置的调试工具pdb进行调试&am…...

Midscene.js:重新定义UI自动化的新时代工具

前言 Midscene.js 是一个创新的、面向开发者的 UI 自动化解决方案,并通过人工智能技术简化自动化脚本的编写与维护。 它提供了三种核心方法——交互(.ai, .aiAction)、提取(.aiQuery)和断言(.aiAssert&am…...

go单元测试和基准测试

1、单元测试和基准测试 单元测试和基准测试代码开发中的重要环节,良好的单元测试和基准测试,能提升开发质量,对整体开发有非常重要的重要,下面介绍单元测试和基准测试的写法。 2、单元测试和基准测试写法 以排序基本排序算法&a…...

Nuxt:利用public-ip这个npm包来获取公网IP

目录 一、安装public-ip包1.在Vue组件中使用2.在Nuxt.js插件中使用public-ip 一、安装public-ip包 npm install public-ip1.在Vue组件中使用 你可以在Nuxt.js的任意组件或者插件中使用public-ip来获取公网IP。下面是在一个Vue组件中如何使用它的例子&#xff1a; <template…...

day7手机拍照装备

对焦对不上&#xff1a;1、光太暗&#xff1b;2、离太近&#xff1b;3、颜色太单一没有区分点 滤镜可以后期P 渐变灰滤镜&#xff1a;均衡色彩&#xff0c;暗的地方亮一些&#xff0c;亮的地方暗一些 中灰滤镜&#xff1a;减少光差 手机支架&#xff1a;最基本70cm即可 手…...

vue3中Teleport的用法以及使用场景

1. 基本概念 Teleport 是 Vue3 提供的一个内置组件&#xff0c;它可以将组件的内容传送到 DOM 树的任何位置&#xff0c;而不受组件层级的限制。这在处理模态框、通知、弹出菜单等需要突破组件层级限制的场景中特别有用。 1.1 基本语法 <template><teleport to&quo…...

LLM - 大模型 ScallingLaws 的指导模型设计与实验环境(PLM) 教程(4)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145323420 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…...

【Linux网络编程】传输层协议

目录 一&#xff0c;传输层的介绍 二&#xff0c;UDP协议 2-1&#xff0c;UDP的特点 2-2&#xff0c;UDP协议端格式 三&#xff0c;TCP协议 3-1&#xff0c;TCP报文格式 3-2&#xff0c;TCP三次握手 3-3&#xff0c;TCP四次挥手 3-4&#xff0c;滑动窗口 3-5&#xf…...

salesforce 可以 outbound profile 吗

在 Salesforce 中&#xff0c;Profile&#xff08;配置文件&#xff09; 通常不能直接通过标准的Change Set&#xff08;变更集&#xff09; 或 Outbound Migration&#xff08;外部迁移工具&#xff09; 进行完整的迁移&#xff0c;但可以通过以下方法来实现部分或全部迁移&am…...

FreeRtos的使用教程

定义&#xff1a; RTOS实时操作系统, (Real Time Operating System), 指的是当外界事件发生时, 能够有够快的响应速度,调度一切可利用的资源, 控制实时任务协调一致的运行。 特点&#xff1a; 支持多任务管理&#xff0c; 处理多个事件&#xff0c; 实现更复杂的逻辑。 与计算…...

windows系统如何检查是否开启了mongodb服务

windows系统如何检查是否开启了mongodb服务&#xff01;我们有很多软件开发&#xff0c;网站开发时候需要使用到这个mongodb数据库&#xff0c;下面我们看看&#xff0c;如何在windows系统内排查&#xff0c;是否已经启动了本地服务。 在 Windows 系统上&#xff0c;您可以通过…...

windows蓝牙驱动开发-生成和发送蓝牙请求块 (BRB)

以下过程概述了配置文件驱动程序生成和发送蓝牙请求块 (BRB) 应遵循的一般流程。 BRB 是描述要执行的蓝牙操作的数据块。 生成和发送 BRB 分配 IRP。 分配BRB&#xff0c;请调用蓝牙驱动程序堆栈导出以供配置文件驱动程序使用的 BthAllocateBrb 函数。&#xff1b;初始化 BRB…...

基于Ubuntu交叉编译ZLMediaKit

一、确保基于虚拟机VMVare的Ubuntu能正常上网 1、设置WIFI硬件无线网卡上网 菜单栏的“编辑”->选择“虚拟网络编辑器”&#xff0c;在弹出的窗口中&#xff0c;点击桥接模式的VMnet0&#xff0c;然后在下方选择“桥接模式”&#xff0c;网卡下拉栏&#xff0c;选择你目前…...

【PyTorch][chapter 29][李宏毅深度学习]Fine-tuning LLM

参考&#xff1a; https://www.youtube.com/watch?veC6Hd1hFvos 目录&#xff1a; 什么是 Fine-tune 为什么需要Fine-tuning 如何进行Fine-tune Fine-tuning- Supervised Fine-tuning 流程 Fine-tuning参数训练的常用方案 LORA 简介 示例代码 一 什么是 Fine-tune …...

git回退

git回退 1、未使用 git add 缓存代码时 git checkout –- filepathname 放弃单个文件的修改 git checkout . 放弃所有的文件修改 此命令用来放弃掉所有还没有加入到缓存区&#xff08;就是 git add 命令&#xff09;的修改&#xff1a;内容修改与整个文件删除。但是此命令不…...

数字图像处理:实验七

uu们&#xff01;这是我们目前数字图像系列的最后一张&#xff0c;之后有关人工智能结合的数字图像处理咸鱼哥正在学习和创作中&#xff0c;所以还请大家给咸鱼哥点时间&#xff0c;同时也提前预祝大家2025年新春快乐&#xff01;&#xff08;咸鱼哥真诚的祝愿每一个人&#xf…...

网易前端开发面试题200道及参考答案 (下)

阐述如何实现 img 按照原比例最大化放置在 div 中? 要让 img 按照原比例最大化放置在 div 中,可通过以下几种方式实现: 使用 object - fit 属性 object - fit 是 CSS 中用于规定如何调整替换元素(如 <img>、<video>)的内容以适应其容器的属性。 object - fit…...

通义灵码插件保姆级教学-IDEA(安装及使用)

一、JetBrains IDEA 中安装指南 官方下载指南&#xff1a;通义灵码安装教程-阿里云 步骤 1&#xff1a;准备工作 操作系统&#xff1a;Windows 7 及以上、macOS、Linux&#xff1b; 下载并安装兼容的 JetBrains IDEs 2020.3 及以上版本&#xff0c;通义灵码与以下 IDE 兼容&…...

利用双指针一次遍历实现”找到“并”删除“单链表倒数第K个节点(力扣题目为例)

Problem: 19. 删除链表的倒数第 N 个结点 文章目录 题目描述思路复杂度Code 题目描述 思路 1.欲找到倒数第k个节点&#xff0c;即是找到正数的第n-k1、其中n为单链表中节点的个数个节点。 2.为实现只遍历一次单链表&#xff0c;我们先可以使一个指针p1指向链表头部再让其先走k步…...

2025美赛倒计时,数学建模五类模型40+常用算法及算法手册汇总

数学建模美赛倒计时&#xff0c;对于第一次参加竞赛且没有相关基础知识的同学来讲&#xff0c;掌握数学建模常用经典的模型算法知识&#xff0c;并熟练使用相关软件进行建模是关键。本文将介绍一些常用的模型算法&#xff0c;以及软件操作教程。 数学建模常用模型包括&#xf…...

sql中INNER JOIN、LEFT JOIN、RIGHT JOIN

INNER JOIN 的作用 INNER JOIN 只会将相关联表匹配到的数据进行展示 假设我们有两个表&#xff1a;sys_user和 sys_user_role SELECT s1.* from sys_user s1 INNER JOIN sys_user_role s2 on s1.id s2.user_id 这样只会展示s1.id s2.user_id相匹配到的数据&#xff0c;其他数…...

二十三种设计模式-享元模式

享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在通过共享相同对象来减少内存使用&#xff0c;尤其适合在大量重复对象的情况下。 核心概念 享元模式的核心思想是将对象的**可共享部分&#xff08;内部状态&#xff09;提取出来进行共…...

前端【10】jQuery DOM 操作

目录 jquery捕获查取 获得内容 - text()、html() 以及 val() 获取属性 - attr() ​编辑 jQuery 修改/设置内容和属性 设置内容 - text()、html() 以及 val() 设置属性 - attr() jQuery添加元素 jQuery - 删除元素 前端【9】初识jQuery&#xff1a;让JavaScript变得更简…...

Day34:字符串的替换

在 Python 中&#xff0c;字符串替换是一个非常常见的操作&#xff0c;主要用于修改字符串中的某些部分。字符串的替换操作通常不修改原始字符串&#xff0c;因为字符串在 Python 中是不可变的&#xff0c;而是返回一个新的字符串。 Python 提供了 str.replace() 方法来执行替…...

汇编的使用总结

一、汇编的组成 1、汇编指令&#xff08;指令集&#xff09; 数据处理指令: 数据搬移指令 数据移位指令 位运算指令 算术运算指令 比较指令 跳转指令 内存读写指令 状态寄存器传送指令 异常产生指令等 2、伪指令 不是汇编指令&#xff0c;但是可以起到指令的作用&#xff0c;伪…...

力扣【347. 前 K 个高频元素】Java题解(堆)

TopK问题&#xff0c;我们直接上堆。 首先遍历一次然后把各个数字的出现频率存放在哈希表中便于后面堆的操作。 因为是出现频率前 k 高&#xff0c;所以用小顶堆&#xff0c;当我们遍历的频率值大于堆顶值时就可以替换堆顶。 代码&#xff1a; class Solution {public int[] …...

【计算机网络】host文件

host文件的主要功能&#xff1a; 域名解析 本地映射&#xff1a;host文件的主要功能是将**域名映射到相应的 IP 地址**。当计算机需要访问一个网站或服务时&#xff0c;它会首先在 host文件中查找该域名对应的 IP 地址。如果在 host文件中找到了匹配的域名和 IP 地址映射&…...

git如何设置pull的时候有些文件不pull

在 Git 中&#xff0c;没有直接的方法在 git pull 时排除特定文件&#xff0c;但可以通过以下方式实现类似效果&#xff1a; 方法 1: 使用 .gitignore .gitignore 文件可以忽略未跟踪的文件&#xff0c;但对已跟踪的文件无效。如果你希望某些文件不被拉取&#xff0c;可以先将…...