什么是多态?一文彻底搞懂!

news2024/12/27 0:22:33

什么是多态

面向对象程序设计有三要素:封装、继承(或组合)、多态,前两者较好理解,多态总让人困惑,不知道具体有什么作用,更不知道为什么要用多态。今天就来详细分析下什么是多态,以及多态有哪些好处,为什么要用多态?

多态.png

多态是指同一行为作用于不同对象时,可以表现出多种不同的形式和结果来。例如,子类继承父类并覆盖其方法后,用父类引用指向子类对象并调用该方法时,实际执行的是子类的方法。

这种根据对象实际类型而非声明类型来确定执行方法的行为,就是多态性的体现。多态主要通过继承和接口实现,允许同一接口有多种不同的实现方式。

多态的分类

  • 编译时多态,又称静态绑定,是指编译器在编译时通过检查引用类型的方法是否存在,来定位到相应的类及其方法,而不检查实际对象是否支持该方法。编译时多态主要体现在方法重载上,即根据参数类型、数量和顺序,在编译时确定要执行的方法。

  • 运行时多态,又称动态绑定,是指程序在运行时根据对象的实际类型来确定调用哪个方法,而不是在编译时确定。这意味着方法的具体实现取决于对象的实际类型,而非其声明类型。父类引用可以指向不同的子类对象,使得相同方法调用产生不同的行为结果。通过运行时确定具体执行的方法,代码具有更好的扩展性和可维护性。

多态的实现方式

编译时多态,方法重载(Overloading):

重载指在同一个类中可以有多个方法,这些方法名称相同但参数列表不同(参数数量或类型不同)。

编译器在编译阶段就能确定具体的方法。以下是一个重载示例,展示了多个同名方法,但参数个数或类型不同。重载的好处是简化接口设计,不需要为不同类型编写多个方法名。

// OverloadExample.java  全部源码见文档链接
/**
 * 重载示例,同名方法,参数个数或类型不同。
 * 编译器在编译时确定具体的调用方法。
 */
class Calculator {
    public int add(int num1, int num2) {
        return num1 + num2;
    }

    public int add(int... nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        return sum;
    }
}

运行时多态,方法重写(Override)与转型(Casting):

运行时多态是在程序运行时确定实际要执行的方法。

当子类继承父类并覆盖同名方法时,这称为重写。使用父类引用来声明子类对象时,子类会向上转型为父类类型。调用该对象的方法时,实际执行的是子类的方法,而不是父类的方法。

向上转型是指使用父类引用声明子类对象,使子类对象的实际类型变为父类。通过父类引用调用子类的方法,使代码更加通用,处理一组相关对象时无需知道它们的具体类型。

向下转型则是将父类引用转换为子类引用,这需要显式进行,并且在转换前需要使用 instanceof 关键字进行类型检查。

// OverrideExample.java 全部源码见文档链接
/**
 * 重写示例,子类覆盖父类同名方法,体现多态。
 * 子类向上转型为父类型,父类强制向下转型为子类型。
 */
class Shape {
  void draw() {
    System.out.println("Shape->draw");
  }

  void drawShape() {
    System.out.println("Shape->drawShape");
  }
}

class Circle extends Shape {
  @Override
  void draw() {
    System.out.println("Circle->draw");
  }

  void drawCircle() {
    System.out.println("Circle->drawCircle");
  }
}

class Square extends Shape {
  @Override
  void draw() {
    System.out.println("Square->draw");
  }

  void drawSquare() {
    System.out.println("Square->drawSquare");
  }
}

public class OverrideExample {
  public static void main(String[] args) {
    // 用父类引用声明子类对象,向上转型
    Shape shape1 = new Circle();
    Shape shape2 = new Square();

    // 子类有同名方法,动态绑定到子类,实质执行的是Circle.draw(),体现多态
    shape1.draw();

    // 报错,编译时按声明类型检查,Shape类中没有drawCircle方法
    // shape1.drawCircle();

    // 执行父类方法,输出 "Shape->drawShape"
    shape1.drawShape();

    if (shape2 instanceof Square) {
      // 向下转型,用子类重新声明,成为子类型了
      Square mySquare = (Square) shape2;

      // 输出 "Square->draw"
      mySquare.draw();

      // 输出 "Square->drawSquare"
      mySquare.drawSquare();

      // 报错。若强转为父类型,则无法调用drawSquare方法
      // ((Shape) mySquare).drawSquare();

      // 继承父类,输出 "Shape->drawShape"
      mySquare.drawShape();
    }
  }
}

多态三个必要条件:

严格来说,多态需要具备以下三个条件。重载不属于严格意义上的多态,因为重载在编译阶段就确定了。我们主要探讨运行时的多态,即针对某个类型的方法调用,实际执行的方法取决于运行时的对象,而不是声明时的类型。

  1. 继承:子类继承父类或实现接口。
  2. 重写:子类覆盖父类的方法。
  3. 父类声明子类:使用父类引用来声明子类对象。

// 父类
class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

// 子类继承并重写同名方法
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Test {
    public static void main(String[] args) {
         // 父类引用声明子类
        Animal myAnimal = new Dog();
         // 运行时对象为子类,故输出"Dog barks"
        myAnimal.makeSound();
    }
}

如何理解父类声明子类 Parent child = new Child(); ?

  • 解释:用 Parent 类声明了一个 child 引用变量(变量存于栈中),并赋值为 Child 实例对象(对象存于堆中)。变量 child 的类型为 Parent(向上转型),它的值是一个 Child 类型的实例对象。

  • 加载执行顺序:
    编译时:JVM 编译时检查类的关系和对应方法(包括重载),确定变量的类型并定位相关方法名称,生成字节码。
    运行时

    1. JVM 加载 Parent 和 Child 类。
    2. 根据 Parent 和 Child 的大小分配堆内存。
    3. 初始化 new Child() 并返回对象引用。
    4. 分配栈内存给变量 child。
    5. 将对象引用赋值给 child。
  • 总结:
    编译时根据引用类型(不是实例对象)确定方法的名称和参数(包括重载)。
    运行时如果子类覆盖了父类的方法,则调用子类(实例引用类型)的方法;如果没有覆盖,则执行父类(变量引用类型)的方法。

多态的好处,为什么要用多态?

在面向对象设计中,“开闭原则”是非常重要的一条。即系统中的类应该对扩展开放,而对修改关闭。这样的代码更可维护和可扩展,同时更加简洁与清晰。

延续上面的例子,假设业务需要扩充更多子类,我们可以通过以下步骤来体现开闭原则:

  1. 新增子类:根据业务需求,新增符合现有类层次结构的子类,例如增加AnotherChild。

  2. 继承和重写:新的子类应该继承自适当的父类,并根据需要重写父类的方法或添加新的方法。

  3. 不需要修改现有的代码:遵循开闭原则,我们不修改现有的 Parent 和 Child 类的代码。

  4. 使用多态:通过父类引用来声明子类,例如 Parent child = new AnotherChild();,这样代码中现有的逻辑不需要改变。

  5. 编译时不变性:编译时确定方法调用的特性不改变,仍然根据引用类型来确定方法的名称和参数,子类随意增加,只要覆盖父类同名方法即可。

  6. 运行时多态性:运行时根据实际对象的类型来决定要执行的方法,这使得代码具有良好的可扩展性和可维护性。

// 定义一个通用Animal类
class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

// 定义Dog类,它是动物的子类
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
}

// 定义Cat类,它是动物的子类
class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Cat meows");
    }

    // Cat自有方法
    void meow() {
        System.out.println("Cat is meowing...");
    }
}

// 定义一个动物园类,管理不同的动物
class Zoo {
    // 传入的是抽象父类或接口,方便扩展
    void letAnimalMakeSound(Animal animal) {
        animal.makeSound();
    }
}

public class AnimalExample {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();

        Animal myDog = new Dog(); // 向上转型
        Animal myCat = new Cat(); // 向上转型
        ((Cat)myCat).meow(); // 向下强转,打印自有方法

        // 通过多态性,动物园可以使用相同的方法处理不同种类的动物
        zoo.letAnimalMakeSound(myDog); // 输出 "Dog barks"
        zoo.letAnimalMakeSound(myCat); // 输出 "Cat meows"
    }
}

要增加新的动物(如鸟类,Bird),只需扩展 Animal 类,而无需修改现有 Zoo 类中的方法。

class Bird extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bird chirps");
    }
}

public class AnimalExample {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();

        Animal myDog = new Dog(); // 向上转型
        Animal myCat = new Cat(); // 向上转型
        Animal myBird = new Bird(); // 向上转型

        // 通过多态性,动物园可以使用相同的方法处理不同种类的动物
        zoo.letAnimalMakeSound(myDog); // 输出 "Dog barks"
        zoo.letAnimalMakeSound(myCat); // 输出 "Cat meows"
        zoo.letAnimalMakeSound(myBird); // 输出 "Bird chirps"
    }
}

这种设计:

  • 允许新增 Animal 的子类,保持对扩展开放;
  • 无需修改依赖 Zoo 的 letAnimalMakeSound 方法,实现对修改封闭。

我们的业务总在不停变化,如何使得代码底层不用大概,而表层又能跟随业务不停变动,这就显得十分重要。通过这种方式,我们在不修改现有代码的情况下,可以轻松地引入新的子类并扩展系统功能,同时保持现有代码的稳定性和可靠性。

其他语言如何实现多态?

不同语言因为语言特性的不同,在实现多态上也略有不同。不过总的概念是一致的,即达到“开闭原则”的目标。

Go语言例子

在Go语言中,虽然没有传统意义上的类继承、父类声明子类和方法重载,但通过结构体(struct)和接口(interface)以及匿名组合等方式实现类似的功能。这样也能实现代码的组织和复用,同时保持了灵活性和简洁性。

package main

import (
  "fmt"
)

// 定义一个Animal接口
type Animal interface {
  MakeSound()
}

// 定义一个 Dog 类型
type Dog struct{}

// 实现 Animal 接口的 MakeSound 方法
func (d Dog) MakeSound() {
  fmt.Println("Dog barks")
}

// 定义一个 Cat 类型
type Cat struct{}

// 实现 Animal 接口的 MakeSound 方法
func (c Cat) MakeSound() {
  fmt.Println("Cat meows")
}

// Cat自有方法
func (c *Cat) Meow() {
  fmt.Println("Cat is meowing...")
}

// 定义一个 Zoo 类型,用于管理动物
type Zoo struct{}

// 定义一个方法,让动物发出声音
func (z Zoo) LetAnimalMakeSound(a Animal) {
  a.MakeSound()
}

func main() {
  zoo := Zoo{}
  myDog := Dog{}
  // 接口断言
  var myCat Animal = &Cat{}
  // 类型断言,打印自有方法
  (myCat.(*Cat)).Meow()

  // 使用多态性,通过接口类型处理不同的具体类型
  zoo.LetAnimalMakeSound(myDog) // 输出 "Dog barks"
  zoo.LetAnimalMakeSound(myCat) // 输出 "Cat meows"
}

当需要增加Bird类型时,直接增加即可。同样无需修改Zoo类里面的LetAnimalMakeSound方法。

type Bird struct{}

// 实现 Animal 接口的 MakeSound 方法
func (b Bird) MakeSound() {
    fmt.Println("Bird chirps")
}

func main() {
  zoo := Zoo{}
  myDog := Dog{}
  var myCat Animal = &Cat{}
  (myCat.(*Cat)).Meow()
  myBird := Bird{}

  // 使用多态性,通过接口类型处理不同的具体类型
  zoo.LetAnimalMakeSound(myDog)  // 输出 "Dog barks"
  zoo.LetAnimalMakeSound(myCat)  // 输出 "Cat meows"
  zoo.LetAnimalMakeSound(myBird) // 输出 "Bird chirps"
}

严格的多态概念,包括子类继承父类、方法重写以及父类声明子类等,这些特性在Go语言中无法实现。Go语言没有class概念,虽然它的struct可以包含方法,看起来像class,但实际上没有继承和重载的支持,它们本质上仍是结构体。

Go语言摒弃了传统面向对象语言中的class和继承概念,我们需要用新的视角来理解和实践面向对象编程在Go中的应用方式

JavaScript语言例子

JavaScript是一种动态弱类型的基于对象的语言,其一切皆是对象。它通过对象的原型链来实现面向对象编程。尽管JavaScript具有class和继承的能力,但由于缺少强类型系统,因此无法实现传统意义上的多态。

当然,JavaScript作为动态语言,具有天然的动态性优势。这使得它在灵活性和扩展性方面更具优势。

// 定义一个通用Animal类
class Animal {
    makeSound() {
        console.log("Animal makes a sound");
    }
}

// 定义Dog类,它是动物的子类
class Dog extends Animal {
    makeSound() {
        console.log("Dog barks");
    }
}

// 定义Cat类,它是动物的子类
class Cat extends Animal {
    makeSound() {
        console.log("Cat meows");
    }
    // Cat自有函数
    meow() {
        console.log("Cat is meowing...", this);
    }
}

// 定义一个动物园类,管理不同的动物
class Zoo {
    // JS没有严格类型,出原始数据类型外,其他均是Object
    // 说出传入的对象只要有makeSound方法即可。
    letAnimalMakeSound(animal) {
        animal.makeSound();
    }
}

// 测试代码
const zoo = new Zoo();
// JS没有父类定义子类概念,直接声明即可,无需向上转型
// 通过instanceof类型判断时可得到子类和父类类型
const myDog = new Dog();
const myCat = new Cat();

// 直接调用自有函数
myCat.meow();

// 可以动态给对象设置函数并绑定对象 
myDog.meow = myCat.meow.bind(myDog); 
myDog.meow();

// 动物园可以使用相同的方法处理不同种类的动物
// 当需要增加其他动物时,直接建立新的类继承Animal,而无需修改Zoo。
zoo.letAnimalMakeSound(myDog); // 输出 "Dog barks"
zoo.letAnimalMakeSound(myCat); // 输出 "Cat meows"

可以看出JS要实现Java意义的多态是做不到的,但JavaScript更加灵活方便,声明对象无需类型,还可以动态添加函数和绑定对象。

Python语言例子

# 定义一个通用Animal类  
class Animal:  
    def make_sound(self):  
        print("Animal makes a sound")  
  
# 定义Dog类,继承Animal
class Dog(Animal):  
    name = "Dog"
    def make_sound(self):  
        print("Dog barks")  
  
# 定义Cat类,继承Animal
class Cat(Animal):  
    name = "Cat"
    def make_sound(self):  
        print("Cat meows")  
  
    # Cat自有方法  
    def meow(self):  
        print(self.name + " is meowing...")  
  
# 定义Bird类,它是动物的子类  
class Bird(Animal):  
    def make_sound(self):  
        print("Bird chirps")  

# 定义管理类
class Zoo:  
    # python与js一样为动态语言,使用duck typing,不需要显式声明接口
    def let_animal_make_sound(self, animal):  
        animal.make_sound()  
  
# 测试代码
if __name__ == "__main__":
    zoo = Zoo()

    # 直接创建实例,Python中不需要向上转型
    my_dog = Dog()
    my_cat = Cat()
    my_bird = Bird()

    # 直接调用自有方法
    my_cat.meow()

    # Python中可直接给对象设置方法,self不会改变
    my_dog.meow = my_cat.meow
    my_dog.meow()

    # 动物园可以使用相同的方法处理不同种类的动物
    zoo.let_animal_make_sound(my_dog)  # 输出 "Dog barks"
    zoo.let_animal_make_sound(my_cat)  # 输出 "Cat meows"
    zoo.let_animal_make_sound(my_bird)  # 输出 "Bird chirps"

Python是一种动态语言,它使用 self 参数来引用实例,无需像其他语言那样使用 new 关键字来实例化对象。Python没有严格的接口概念,不需要像其他语言那样显示声明对象的接口。Python通过继承和方法重写来实现多态概念,但不支持传统意义上的父类声明子类和方法重载。

因此,Python在多态性上的表现与JavaScript相似,都是基于动态语言特性,灵活而动态,通过继承和重写实现对象行为的多样性。

Java多态实例全面剖析

理解Java多态的实例可以帮助澄清其原理和执行过程。以下是一个简单而详尽的例子,帮助你全面理解Java中多态的工作机制。

// PolymorphismSimple.java
// 父类A
class A {
    public String show(D object) {
        return ("A and D");
    }

    public String show(A object) {
        return ("A and A");
    }

    // 默认注释掉。可开关注释测试下
    // public String show(B object) {
    // return ("A and B");
    // }
}

// 子类B
class B extends A {
    public String show(B object) {
        return ("B and B");
    }

    public String show(A object) {
        return ("B and A");
    }
}

// 孙子类C
class C extends B {
}

// 孙子类D
class D extends B {
}

// 测试验证
public class PolymorphismSimple {
    public static void main(String[] args) {
        // 父类声明自己
        A a = new A();
        // 父类声明子类
        A ab = new B();
        // 子类声明自己
        B b = new B();
        C c = new C();
        D d = new D();

        // 1) A and A。b的类型是B,也是B的实例,A里没有show(B)方法,但有show(A)方法。B的父类是A,因此定位到A.show(A)。
        System.out.println("1) " + a.show(b));

        // 2) A and A。c的类型是C,也是C的实例,C继承B,B继承A。A里没有show(C)方法,也没有show(B)方法,最后指向A.show(A)。
        System.out.println("2) " + a.show(c));

        // 3) A and D, d的类型是D,也是D的实例,D继承B,B继承A。A里有show(D)方法,直接定位到A.show(D)。
        System.out.println("3) " + a.show(d));

        // 4) B and A, ab是B的实例,但用A声明,即向上转型得到的类型是A,运行时才能确定具体该调用哪个方法。
        // ab是B的实例对象,但引用类型是A。类型是在编译时确定,因此从类型开始定位方法。
        // A类中没有show(B)方法,但有show(A)方法,因为A是B的父类,ab也是A的实例,于是定位到A.show(A)方法。
        // 由于B是A的子类,且B重写了A的show(A),A的方法被覆盖了,于是定位到B.show(A),这就是动态绑定。
        // 虽然B中有show(B)方法,但是因为ab的类型是A,编译时根据类型定位到A的方法,而不是B。

        // 以下几种可开关打开/注释代码测试下。
        // -
        // 若A里有show(A)和show(B),B里有show(B)有show(A),则编译时关联到A.show(B),因B覆盖了A.show(B),动态绑定到B.show(B)。
        // -
        // 若A里有show(A)和show(B),B里无show(B)有show(A),则编译时关联到A.show(B),因B无覆盖,则直接调用A.show(B)。
        // -
        // 若A里有show(A)无show(B),B里无show(B)有show(A),则编译时关联到A.show(A),因B覆盖了A.show(A),动态绑定到B.show(A)。
        // -
        // 若A里有show(A)无show(B),B里无show(A)有show(B),则编译时关联到A.show(A),因B无覆盖,则直接调用A.show(A)。
        // 查找顺序为:编译时根据引用类型确定所属类 -> 根据重载参数类型定位(类型按子->父->祖逐级往上查找)到类的具体方法(包括继承的方法) ->
        // 运行时实例对象覆盖(覆盖只有子->父一层)了引用类型的同名方法 -> 定位到实例对象的方法。
        System.out.println("4) " + ab.show(b));

        // 5) B and A。ab是B的实例,类型是A。从A类没找到show(C)方法,也没找到A.show(B)方法,找到A.show(A)方法。A.show(A)被B.show(A)覆盖,因此调用B.show(A)。
        System.out.println("5) " + ab.show(c));

        // 6) A and D。A里面有show(D)的方法,直接定位到。
        System.out.println("6) " + ab.show(d));

        // 7) B and B。B里面有show(B)的方法,直接定位到。
        System.out.println("7) " + b.show(b));

        // 8) B and B。B没有show(c)方法,但有show(B)方法。C继承自B,父类型是B,因此调用B.show(B)。
        System.out.println("8) " + b.show(c));

        // 9) A and D。B中没有show(D)方法,B继承A,A里有show(D), 故调用A.show(D)方法。
        System.out.println("9) " + b.show(d));

        // 10) B and A。父类声明子类,存在向上转型。A里有show(A),被B.show(A)覆盖了,因此定位到B.show(A)。
        System.out.println("10) " + ab.show(a));

    }
}

总结

多态包括编译时多态和运行时多态。编译时多态,即静态绑定,通常通过方法重载实现。运行时多态则是在代码运行时确定具体调用的方法。

从Java的角度看,严格意义上的多态需要满足三个条件:继承、方法覆盖和父类引用子类对象。Java完全符合这些要求,实现了严格意义上的多态。

尽管Go语言、Python和JavaScript不完全符合严格意义上的多态,它们仍能够实现多态效果。多态的核心在于动态确定运行的方法,从而使代码更加灵活、易于维护和扩展。

Go语言虽然没有继承和方法重载,但仍能实现多态效果。Python和JavaScript作为动态语言,没有接口和显式类型声明,但由于其灵活性,同样能很好地实现多态。

各语言完整示例

https://github.com/microwind/design-pattern/tree/main/programming-paradigm/oop/polymorphism

简单示例

PolymorphismSimple.java
PolymorphismSimple.go
polymorphism_simple.c
PolymorphismSimple.cpp
PolymorphismSimple.js
PolymorphismSimple.py
PolymorphismSimple.ts

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

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

相关文章

运筹系列93:VRP精确算法

1. MTZ模型 MTZ是Miller-Tucker-Zemlin inequalities的缩写。除了定义是否用到边 x i j x_{ij} xij​外,还需要定义一个 u i u_i ui​用来表示此时车辆的当前载货量。注意这里x变量需要定义为有向。 这里定义为pickup问题,代码为: using Ju…

【CentOS7】Linux安装Docker教程(保姆篇)

文章目录 查看是否已安装卸载(已安装过)docker安装友情提示 更多相关内容可查看 注:本篇为Centos7安装Docker,若为其他系统请理性参考 查看是否已安装 如果已安装,请卸载重新安装 docker --version这里显示已安装 …

Web网页端IM产品RainbowChat-Web的v7.0版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址) 的产品级移动端IM系统)。 ► 详细介绍:http://www.52im.net/thread-2…

基于Java医院药品交易系统详细设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…

AI大模型战争:通用与垂直,谁将领跑未来?

文章目录 📑引言一、通用大模型:广泛适用,实力不容小觑1.1 强大的泛化能力1.2 广泛的适用场景 二、垂直大模型:专注深度,精准解决问题2.1 深度专注,精准度高2.2 快速落地与普及 三、通用与垂直:…

SFP4006-ASEMI无人机专用SFP4006

编辑:ll SFP4006-ASEMI无人机专用SFP4006 型号:SFP4006 品牌:ASEMI 封装:TO-247 最大平均正向电流(IF):40A 最大循环峰值反向电压(VRRM):600V 最大正向…

SVN学习(004 subversive操作和解决冲突)

尚硅谷SVN高级教程(svn操作详解) 总时长 4:53:00 共72P 此文章包含第42p-第p43的内容 操作 新建一个teacher类 添加到版本库(也可以忽略这步 直接提交) 资源-》右键-》team-》提交 另一个用户进行更新 资源-》右键-》team-》更新 解决冲突 用…

HTML【介绍】

HTML【介绍】 一、Web认知 1.网页组成 文字、图片、音频、视频、超链接 2.五大浏览器 IE浏览器、火狐浏览器(Firefox)、谷歌浏览器(Chrome)、Safari浏览器、欧朋浏览器(Opera) 3.Web标准的构成 HTML…

上海医疗学术会议小程序开发的优势与主要功能

现如今,随着互联网科技的进步与发展,越来越的医务工作者开始组织参加医疗学术会议,而同大数据相结合,出现的上海医疗学术会议小程序开发则为医疗学术会议带来了新的活力,使其组织流程更加规范,便捷、呈现效…

性能升级,这波够带劲!高性价比首选:18位高速多功能同步数据采集卡

PXIe9752系列是一款高性能、多功能的数据采集卡,其中包含了模拟输入、模拟输出、数字量输入输出以及计数器。专为复杂的测试和测量应用设计,为用户提供更多的功能选择和灵活性。 主要参数 产品优势 高精度:能够捕捉微小信号变化,提高测量分辨率。 高…

[职场] 提升学历考研再就业有必要吗 #其他#知识分享

提升学历考研再就业有必要吗 有很多人觉得自己学历不够高,求职第一关可能就通过不了。因此想要继续攻读,最近有人问小编提升学历考研有必要吗?“硕士学历和三年的工作经验哪个更重要?” 这个还是要针对具体岗位而言。综合类型的岗位往往不需…

VsCode-PlatformIO 开发环境搭建

在VScode中搜索PlatformIO,然后点击install 安装即可 安装后重新打开vscode,会出现如下界面。

益百分4.0版益生君重磅来袭,为您保驾护航

益百分4.0版益生君重磅来袭,为您保驾护航 暑期来临,很多人们终于等来了一年中最幸福的时刻,三五成群、结伴旅游成为他们选择欢度暑假的方式。 全国各地的旅游景点也迎来了旺季,各大旅游公司也推出了各种各样的旅游团购活动&#x…

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

基于图扑 HT for Web 实现拓扑关系图

拓扑结构在计算机网络设计和通信领域中非常重要,因为它描述了网络中的设备(即“点”)如何相互连接(即通过“线”)。这种结构不仅涉及物理布局,即物理拓扑,还可以涉及逻辑或虚拟的连接方式&#…

苹果手机备忘录怎么长截屏或者导出

在快节奏的生活中,手机备忘录已成为我们随时记录重要信息和灵感的得力助手。然而,当我们想要保存或分享备忘录中的长内容时,苹果手机的截屏功能似乎就显得有些捉襟见肘了。 那么,苹果手机备忘录如何进行长截屏或者导出呢&#xf…

每日热榜资源

获取更多资源,请关注公众号:阿宇的编程之旅,回复‘书签’获取 划水摸鱼官网 网站名称:划水摸鱼官网网址:划水摸鱼官网介绍:提供休闲放松的内容,让你在忙碌之余享受片刻的宁静。 鱼塘热榜 网…

谷歌浏览器截图

一 右击,然后点击检查; 二 然后ctrlshiftp,运行命令; 三 3.1搜索截图: 如果你设置为中文,搜索截图,选择你想要的截图类型; 如果你是在英文情况下: 输入capture full size 来过滤…

驾照减分考试搜题软件?分享四个可以搜答案的软件 #其他#笔记#经验分享

大学生们可以通过使用搜题软件,快速找到自己遇到的问题的答案,提高学习效率,以下分享各类型的供大家学习。 1.彩虹搜题 这是个微信公众号 学生或者是成年人使用非常广的一款学习应用软件,里面包含了各行各业的海量题库&#xf…