Java基础——五、继承

五、继承

简要

1、说明

继承(Inheritance)面向对象编程(OOP)的一个核心概念,它允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码重用和结构化组织。通过继承,子类可以扩展父类的功能或者对父类的方法进行重写

  1. 父类(超类、基类)
    • 父类是被继承的类,它包含子类可以使用的属性和方法
    • 在Java中,使用extends关键字来实现继承。
  2. 子类(派生类)
    • 子类是继承父类的类,它可以访问父类的公共和受保护的成员(属性和方法)
    • 子类可以添加新的属性和方法,也可以重写父类的方法
2、继承的优点
  1. 代码重用:
    • 子类可以直接使用父类中定义的属性和方法,减少代码的重复。
  2. 提高可维护性:
    • 由于子类和父类的结构化关系,系统更加模块化,修改父类的方法时,子类也会自动更新,从而提高了系统的可维护性。
  3. 实现多态:
    • 继承是实现多态(Polymorphism)的基础,通过继承和方法重写,程序可以在运行时决定调用哪个类的方法。
3、继承的实现

提供一个简单的Java继承示例:

//父类
class Animal{String name;public void eat(){System.out.println("This animal eat food.");}
}//子类
class Dog extend Animal{public void bark(){Sytem.out.println("The dog barks.");}public void eat(){System.out.println("The dog eats dog food.");}
}public class Main{public static void main(String[] args){Dog dog = new Dog();dog.name = "Buddy";//调用重写的方法。dog.eat();//调用子类特有的方法。dog,bark();}
}
4、继承的类型
  1. 单继承:
    • 一个子类只能继承一个父类。Java中不支持多继承(即一个子类继承多个父类),但是可以通过接口来实现,类似多继承的效果。
  2. 多层继承:
    • 一个类继承另一个类,该类又继承另一个类,形成继承链。例如:类C继承类B,类B继承类A。
组合
1、组合 VS 继承

继承:

  • 是一种是一个(is-a)关系。例如,Dog继承自Animal,表示Dog是一个Animal
  • 子类继承父类的所有属性和方法,但这也导致子类与父类之间的耦合度较高。
  • 如果子类发生变化,子类可能需要进行相应的修改。
  • 继承层次过深可能导致代码复杂性增加。

组合:

  • 是一种有一个(has - a)关系。例如,Car有一个Engine,表示car包含一个Engine对象。
  • 通过将一个类的实例作为成员变量引入到另一个类中,来实现类之间的协作。
  • 组合的类之间的耦合度较低,一个类的改变不会直接影响另一个类。
  • 组合更灵活,可以在运行时动态改变组合对象的行为。
2、组合的示例

假设我们有一个场景,需要定义一个交通工具(Vehicle),每种交通工具有不同的移动方式(MoveStrategy)。我们可以使用组合来实现不同交通工具的行为,而不是通过继承。

定义接口和实现类:

package base.inheritance.assembly;/*** @author: LiHao* @program: interview* @description: 叙述组合的示例(用于对比继承)* @Date: 2024-06-10-17:34:10* thinking:*/
interface MoveStrategy {/*** 移动对象。* <p>* 该方法定义了对象的移动行为,但没有指定移动的方式或方向。* 具体的移动逻辑应在方法体内实现,这里没有提供实现是因为示例的限制。** @see #move(int, int) 如果需要更精确的控制移动距离和方向,可以使用带参数的移动方法。*/void move();
}/*** 具体的移动策略实现:开车*/
class DriveStrategy implements MoveStrategy {/*** 实现移动方法。* 该方法具体实现了车辆在道路上的行驶行为。通过打印信息来模拟车辆的移动过程。* 由于这是一个抽象类的抽象方法的具体实现,所以这里使用了@Override注解来标明此方法是对父类抽象方法的实现。*/@Overridepublic void move() {System.out.println("Driving on the road.");}
}/*** 具体的移动策略实现:飞行*/
class FiyStrategy implements MoveStrategy {@Overridepublic void move() {System.out.println("Flying in the sky.");}
}/*** 具体的移动策略实现:行走*/
class WalkStrategy implements MoveStrategy {@Overridepublic void move() {System.out.println("Walking on the ground.");}
}/*** 交通工具类*/
class Vehicle {private MoveStrategy moveStrategy;/*** 构造函数,用于初始化车辆对象。** @param moveStrategy 移动策略对象,车辆将使用该策略来进行移动。*                     通过传入不同的移动策略,车辆可以实现不同的移动方式,*                     提供了策略模式中的策略对象。*/public Vehicle(MoveStrategy moveStrategy) {this.moveStrategy = moveStrategy;}/*** 设置移动策略。** 本方法用于更换对象的移动策略,允许对象在运行时根据需要动态调整其移动方式。* 通过传入不同的移动策略实例,对象可以实现不同的移动行为,从而提高代码的灵活性和可扩展性。** @param moveStrategy 移动策略对象,用于定义对象的移动行为。*/public void setMoveStrategy(MoveStrategy moveStrategy){this.moveStrategy = moveStrategy;}/*** 实现移动操作。* 通过策略模式,调用指定的移动策略来执行移动操作。* 此方法的目的是为了封装移动行为,具体的移动方式由包含的移动策略对象决定。*/public void move() {moveStrategy.move();}/*** 使用组合来实现不同的行为* @param args*/public static void main(String[] args) {//创建不同的移动策略MoveStrategy driveStrategy = new DriveStrategy();MoveStrategy fiyStrategy = new FiyStrategy();MoveStrategy walkStrategy = new WalkStrategy();//创建交通工具并设置移动策略Vehicle car = new Vehicle(driveStrategy);car.move();//动态改变交通工具的移动策略car.setMoveStrategy(fiyStrategy);car.move();//创建另一个交通工具并设置不同的移动策略Vehicle person = new Vehicle(walkStrategy);person.move();}
}

输出:

Driving on the road.
Flying in the sky.
Walking on the ground.
3、组合的优点
  1. 灵活性:
    • 可以在运行时动态改变对象的行为,而无需修改类的层次结构。
    • 可以通过组合不同的策略对象来实现多种行为。
  2. 低耦合:
    • 组合的类之间的耦合度较低,一个类的改变不会直接影响另一个类。
    • 更容易维护和扩展系统,添加新的策略不需要修改现有的类。
  3. 遵循单一职责原则:
    • 每一个类只需要关注一个特定的功能,职责更加准确。

通过理解和应用组合的模式,可以创建更灵活、易维护的系统,特别是在需求频繁变化的场景下,组合模式的优势更加明显。

5、注意事项
  1. 访问控制

    • 父类的private成员不能被子类直接访问,但protectedpublic成员可以被子类访问。
  2. 构造方法

    • 构造方法不能被继承,但子类可以调用父类的构造方法(使用super关键字)。
  3. 组合优于继承

    • 在某些情况下,使用组合(即在一个类中包含另一个类的实例)可能比继承更合适,因为它可以提供更好的灵活性和减少耦合度。

通过理解和应用继承,可以创建更简洁、可维护性强且扩展性好的代码结构,这是面向对象编程不可或缺的一部分。

访问权限

Java 中有三个访问权限修饰符:private、protected 以及 public

  • 如果不加访问修饰符,表示包级可见。可以对类或类中的成员(字段和方法)加上访问修饰符。

  • 类可见表示其它类可以用这个类创建实例对象

  • 成员可见表示其它类可以用这个类的实例对象访问到该成员

protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。

设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问

如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例去代替,也就是确保满足里氏替换原则。

**字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。**例如下面的例子中,AccessExample 拥有 id 公有字段,如果在某个时刻,我们想要使用 int 存储 id 字段,那么就需要修改所有的客户端代码

public class AccessExample {public String id;
}

可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。

public class AccessExample {private int id;public String getId() {return id + "";}public void setId(String id) {this.id = Integer.valueOf(id);}
}

但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。

public class AccessWithInnerClassExample {private class InnerClass {int x;}private InnerClass innerClass;public AccessWithInnerClassExample() {innerClass = new InnerClass();}public int getValue() {return innerClass.x;  // 直接访问}
}

抽象类与接口

一、抽象类
1.定义

抽象类是不能被实例化的类,它用来作为其它类的基类。抽象类可以包含抽象方法(没有具体的方法)和具体方法(有方法体的方法)。

抽象类为什么不能被实例化?

设计目的:

  1. 不完整的实现:抽象类是用了作为其它类型的基类的,它包含抽象方法,这些方法没有实现。因为抽象类本身并没有提供所有方法的实现,它不完整,所以不能被实例化。实例化一个不完整的对象是没有意义的。

特征与语言规范:

  1. 强制子类实现:抽象类中的抽象方法定义了子类必须实现的行为,这是一种设计模式,确保所有子类都提供具体实现。如果允许实例化对抽象类,那么这些抽象方法在没有实现的情况下就会被调用,导致错误。
  2. 语法和编译器要求:在Java语言规范中,抽象类被定义为不能被实例化。如果尝试实例化一个抽象类,编译器会报错。这是为了确保编译时就能发现设计上的错误。

示例代码:

abstract class Animal {abstract void makeSound(); // 抽象方法,没有方法体void eat() {System.out.println("This animal is eating.");}
}class Dog extends Animal {@Overridevoid makeSound() {System.out.println("Bark");}
}public class Main {public static void main(String[] args) {// Animal animal = new Animal(); // 编译错误:Animal是抽象的;不能实例化Dog dog = new Dog();dog.makeSound(); // 输出:Barkdog.eat(); // 输出:This animal is eating.}
}

在上述示例中:

  • Animal类是一个抽象类,包含一个抽象方法makeSound(),没有方法体。
  • Dog类继承自Animal并实现了makeSound()方法。
  • 试图实例化Animal类会导致编译错误,因为Animal是抽象的,不能直接创建其实例。

总结:

抽象类不能实例化的原因主要是:

  1. 不完整实现:抽象类本身不完整,包含未实现的方法。
  2. 设计模式:确保子类实现必要的方法,强制制定的设计模式。
  3. 语言规范:Java语言规范和编译器的要求,防止设计错误。

通过这些机制,抽象类可以正确地作为其它类的基类,确保代码的健壮性和设计的一致性。

2.关键字

使用abstract关键字类定义一个抽象类的抽象方法。

3.特点
  1. 部分实现:抽象类可以包含具体的方法实现,也可以包含抽象方法。子类可以继承抽象类并实现未实现的方法。
  2. 构造方法:可以有构造方法,但不能实例化对象。构造方法通常被用于子类的实例化过程中调用。
  3. 字段和方法:可以包含字段和方法(即可以是抽象的也可以是具体的)。
  4. 继承:一个类可以继承一个抽象类(单继承)。
  5. 访问修饰符:可以使用各种访问修饰符(public,protected,private)。

抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类

抽象类和普通类最大的区别是:抽象类不能被实例化,只能被继承

public abstract class AbstractClassExample {protected int x;private int y;public abstract void func1();public void func2() {System.out.println("func2");}
}
public class AbstractExtendClassExample extends AbstractClassExample {@Overridepublic void func1() {System.out.println("func1");}
}
// AbstractClassExample ac1 = new AbstractClassExample(); // 'AbstractClassExample' is abstract; cannot be instantiated
AbstractClassExample ac2 = new AbstractExtendClassExample();
ac2.func1();

2. 接口

接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。

从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类,让它们都实现新增的方法

接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。从 Java 9 开始,允许将方法定义为 private,这样就能定义某些复用的代码又不会把方法暴露出去。

接口的字段默认都是 static 和 final 的

public interface InterfaceExample {void func1();default void func2(){System.out.println("func2");}int x = 123;// int y;               // Variable 'y' might not have been initializedpublic int z = 0;       // Modifier 'public' is redundant for interface fields// private int k = 0;   // Modifier 'private' not allowed here// protected int l = 0; // Modifier 'protected' not allowed here// private void fun3(); // Modifier 'private' not allowed here
}
public class InterfaceImplementExample implements InterfaceExample {@Overridepublic void func1() {System.out.println("func1");}
}
// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
InterfaceExample ie2 = new InterfaceImplementExample();
ie2.func1();
System.out.println(InterfaceExample.x);

3. 比较

  • 从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系

  • 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类

  • 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制

  • 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限

4. 使用选择

使用接口:

  • 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Comparable 接口中的 compareTo() 方法;
  • 需要使用多重继承

使用抽象类

  • 需要在几个相关的类中共享代码
  • 需要能控制继承来的成员的访问权限,而不是都为 public。
  • 需要继承非静态和非常量字段

在很多情况下,接口优先于抽象类。因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。

  • Abstract Methods and Classes(opens new window)
  • 深入理解 abstract class 和 interface(opens new window)
  • When to Use Abstract Class and Interface(opens new window)
  • Java 9 Private Methods in Interfaces(opens new window)

super

  • 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。应该注意到,子类一定会调用父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果子类需要调用父类其它构造函数,那么就可以使用 super() 函数。
  • 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
public class SuperExample {protected int x;protected int y;public SuperExample(int x, int y) {this.x = x;this.y = y;}public void func() {System.out.println("SuperExample.func()");}
}
public class SuperExtendExample extends SuperExample {private int z;public SuperExtendExample(int x, int y, int z) {super(x, y);this.z = z;}@Overridepublic void func() {super.func();System.out.println("SuperExtendExample.func()");}
}
SuperExample e = new SuperExtendExample(1, 2, 3);
e.func();
SuperExample.func()
SuperExtendExample.func()

Using the Keyword super

重写与重载

1. 重写(Override)

存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。

为了满足里式替换原则,重写有以下三个限制:

  • 子类方法的访问权限必须大于等于父类方法;
  • 子类方法的返回类型必须是父类方法返回类型或为其子类型。
  • 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。

使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。

下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:

  • 子类方法访问权限为 public,大于父类的 protected。
  • 子类的返回类型为 ArrayList,是父类返回类型 List 的子类。
  • 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
  • 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
class SuperClass {protected List<Integer> func() throws Throwable {return new ArrayList<>();}
}class SubClass extends SuperClass {@Overridepublic ArrayList<Integer> func() throws Exception {return new ArrayList<>();}
}

在调用一个方法时:

  1. 先从本类中查找看是否有对应的方法
  2. 如果没有再到父类中查看,看是否从父类继承来。
  3. 否则就要对参数进行转型,转成父类之后看是否有对应的方法。总的来说,方法调用的优先级为:
  • this.func(this)
  • super.func(this)
  • this.func(super)
  • super.func(super)
/*A|B|C|D*/class A {public void show(A obj) {System.out.println("A.show(A)");}public void show(C obj) {System.out.println("A.show(C)");}
}class B extends A {@Overridepublic void show(A obj) {System.out.println("B.show(A)");}
}class C extends B {
}class D extends C {
}
public static void main(String[] args) {A a = new A();B b = new B();C c = new C();D d = new D();// 在 A 中存在 show(A obj),直接调用a.show(a); // A.show(A)// 在 A 中不存在 show(B obj),将 B 转型成其父类 Aa.show(b); // A.show(A)// 在 B 中存在从 A 继承来的 show(C obj),直接调用b.show(c); // A.show(C)// 在 B 中不存在 show(D obj),但是存在从 A 继承来的 show(C obj),将 D 转型成其父类 Cb.show(d); // A.show(C)// 引用的还是 B 对象,所以 ba 和 b 的调用结果一样A ba = new B();ba.show(c); // A.show(C)ba.show(d); // A.show(C)
}

2. 重载(Overload)

存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同

应该注意的是,返回值不同,其它都相同不算是重载

class OverloadingExample {public void show(int x) {System.out.println(x);}public void show(int x, String y) {System.out.println(x + " " + y);}
}
public static void main(String[] args) {OverloadingExample example = new OverloadingExample();example.show(1);example.show(1, "2");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/37707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于docker安装redis服务

Redis是我们在项目中经常需要使用的缓存数据库&#xff0c;安装redis的方式也有很多&#xff0c;本文主要是给大家讲解如何基于docker进行redis服务的安装&#xff0c;主要介绍&#xff0c;如何拉取redis镜像、如何挂载redis的数据以及使用redis的配置文件和开启认证等功能&…

steam社区载入失败、加载不出来、打不开?

随着steam夏季大促的到来&#xff0c;最近steam在线用户越来越多了&#xff0c;很多玩家在自己喜欢的游戏社区里看最新的玩法、攻略和玩家的游戏心得。不过有不少玩家表示有时候会打不开游戏社区或是社区加载失败等问题。根据大家遇到的问题&#xff0c;这里总结了几种解决方法…

构建现代医疗:互联网医院系统源码与电子处方小程序开发教学

本篇文章&#xff0c;笔者将探讨互联网医院系统的源码结构和电子处方小程序的开发&#xff0c;帮助读者更好地理解和掌握这些前沿技术。 一、互联网医院系统源码结构 互联网医院系统通常由多个模块组成&#xff0c;每个模块负责不同的功能。以下是一个典型的互联网医院系统的主…

基于C语言的Jacobi迭代和Gauss-Seidel迭代的方程组求解实现

文章目录 Jacobi迭代方法介绍Gauss-Seidel迭代方法介绍具体代码实现示例题目实现效果 Jacobi迭代方法介绍 Jacobi迭代法是一种简单的迭代求解方法&#xff0c;适用于严格对角占优矩阵。其基本思想是利用当前迭代步的已知解来更新下一个迭代步的解。在C语言实现中&#xff0c;我…

商协会小程序如何提升商协会形象?

商协会小程序在提升商协会形象方面扮演着重要角色。以下是关于商协会小程序如何提升商协会形象的一些场景分析&#xff1a; 1、数字化名片与品牌形象展示 小程序可以作为商协会的数字名片&#xff0c;通过展示商会文化、活动信息和会员服务&#xff0c;有效提升商会的品牌形象…

链表反转的两种方式

链表反转的两种方式 1.头插法 先创建一个新的链表&#xff0c;然后不断遍历我们想要反转的链表&#xff0c;再一个一个使用头插法插入到我们新建立的链表中&#xff0c;这样链表就倒置了。 LinkList Reverse(LinkList re) {LinkList n;n (LinkList)malloc(sizeof(LNode));n…

C语言代码风格

程序文件的说明&#xff0c;一般放在文件头部注释。 用来描述文件的作用、作者、日期等信息。一般格式如下&#xff1a; /** 文件名&#xff1a;filename.c* 功能&#xff1a;简要描述文件的功能或作用* 作者&#xff1a;作者姓名* 日期&#xff1a;创建日期或最近修改日期*/…

Textual Learning2 -- 使用时的小问题

1、出现的问题&#xff1a; 在vscode里面直接运行函数会显示报错&#xff1a; 我尝试在vscode中含textual库的环境下运行&#xff0c;但仍然报错 2、解决方案&#xff1a; 在命令行中运行&#xff1a; 首先按winR&#xff0c;输入cmd打开命令行 或在已经安装的conda环境&a…

古人的智慧结晶——水铳:揭秘明清时期的消防神器

明代的《奇器图说》是一本记录了当时各种奇巧机械的著作&#xff0c;而水铳则是书中记载的一项令人惊叹的发明&#xff0c;它不仅展示了古人对物理原理的深刻理解&#xff0c;更是早期消防技术的一个缩影。 水铳&#xff0c;这个名字听起来似乎有些陌生&#xff0c;但在古代&am…

在数据库水平扩展中,名人问题(Celebrity Problem)也被称为热点键问题(Hotspot Key Problem)。

在数据库水平扩展中&#xff0c;名人问题&#xff08;Celebrity Problem&#xff09;也被称为热点键问题&#xff08;Hotspot Key Problem&#xff09;。这是指某些特定的键&#xff08;例如名人或非常受欢迎的内容&#xff09;会导致某个分片&#xff08;shard&#xff09;被过…

电脑文件kernel32.dll缺失要怎么处理?怎么才能一键修复kernel32.dll文件

关键系统文件kernel32.dll的缺失&#xff0c;这种情况不仅会导致系统运行不稳定&#xff0c;甚至可能完全无法启动某些应用程序。kernel32.dll 是一个至关重要的动态链接库文件&#xff0c;它与Windows操作系统的多个基本操作相关联&#xff0c;包括内存管理、进程和线程的控制…

dledger原理源码分析系列(二)-心跳

简介 dledger是openmessaging的一个组件&#xff0c; raft算法实现&#xff0c;用于分布式日志&#xff0c;本系列分析dledger如何实现raft概念&#xff0c;以及dledger在rocketmq的应用 本系列使用dledger v0.40 本文分析dledger的心跳 关键词 Raft Openmessaging 心跳/…

C++中的常成员函数

2024年6月29日&#xff0c;周日下午 例如&#xff0c;以下是一个常成员函数的示例&#xff1a; class MyClass { public:int getValue() const {return value;} private:int value; };常成员函数是C中一种特殊的成员函数&#xff0c;它具有以下特点&#xff1a; 不可修改对象…

Flink Window DEMO 学习

该文档演示了fink windows的操作DEMO 环境准备&#xff1a; kafka本地运行&#xff1a;kafka部署自动生成名字代码&#xff1a;随机名自动生成随机IP代码&#xff1a;随机IPFlink 1.18 测试数据 自动向kafka推送数据 import cn.hutool.core.date.DateUtil; import com.alibab…

技术赋能教育:校园3D电子地图与AR导航解决方案

随着高考的落幕&#xff0c;又一批新鲜血液即将注入大学校园。面对陌生的环境&#xff0c;如何快速适应、准确找到目标地点&#xff0c;成为新生们的一大难题。同时&#xff0c;对于学校而言&#xff0c;如何向报考人员直观展示校园环境&#xff0c;提供沉浸式参观体验&#xf…

Mybatis-Plus学习|快速入门CRUD、主键生成策略(雪花算法、主键自增等)、自动填充、乐观锁、分页插件、逻辑删除

MyBatisPlus概述 为什么要学习它呢?MyBatisPlus可以节省我们大量工作时间&#xff0c;所有的CRUD代码它都可以自动化完成! JPA、tk-mapper、MyBatisPlus 偷懒的! MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff…

Pytorch学习之torch.nn.functional.pad()函数

PyTorch学习之torch.nn.functional.pad函数 一、简介 torch.nn.functional.pad 是 PyTorch 中用于对张量进行填充操作的函数。填充操作在处理图像、序列数据等任务时非常常见&#xff0c;它可以在张量的指定维度两端添加一定数量的元素&#xff0c;填充方式多样&#xff0c;包…

Git的基本使用方法

Git的基本使用方法 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨Git的基本使用方法&#xff0c;Git作为目前最流行的版本控制系统之一&…

Day 48 消息队列集群RabbitMQ

消息队列集群-RabbitMQ 一、消息中间件 中间件 tomcat java web中间件 web容器 mysql php php mysql uwsgi python mysql mycat 数据库中间件 rabbitMQ 消息中间件 1、简介 MQ 全称为&#xff08;Message Queue消息队列&#xff09;。是一种应用程序对应用程序的通信方…

【全球首个开源AI数字人】DUIX数字人-打造你的AI伴侣!

目录 1. 引言1.1 数字人技术的发展背景1.2 DUIX数字人项目的开源意义1.3 DUIX数字人技术的独特价值1.4 本文目的与结构 2. DUIX数字人概述2.1 定义与核心概念2.2 硅基智能与DUIX的关系2.3 技术架构2.4 开源优势2.5 应用场景2.6 安全与合规性 3. DUIX数字人技术特点3.1 开源性与…