万字详解Java的三大特性:封装 | 继承 | 多态

前言:面向对象程序设计的三大特征就是:封装,继承,多态。在前文介绍了类和对象后,我们就可以继而学习什么是封装,怎么用类的子类来实现继承和多态 


目录

一.面向对象的特性

1.封装性

2.继承性 

3.多态性

二.封装 

三.继承

1.为什么要有继承

2.继承概念

3.继承的语法 

4.父类成员访问

子类中访问父类的成员变量

子类中访问父类的成员方法

5.super 关键字

6.子类构造方法

7.继承方式

四.多态

1.多态的概念

2.多态的实现条件

向上转型

第一种方式:直接赋值

第二种方式:通过传参 

第三种方式:通过返回值

重写

3.多态的实现

直接赋值实现多态

通过传参实现多态 

4.多态的优缺点 

优点:

缺点:


一.面向对象的特性

面向对象编程是一种先进的编程思想,基于对象的编程更符合人的思维模式,编写的程序可以更加健壮和强大,更容易解决复杂的问题,面向对象编程主要体现下面三个特性:

1.封装性

         面向对象编程的核心思想质疑就是想数据和对数据的操作封装在一起,通过抽象,从具体的示例中抽取共同的性质形成一般的概念,而类的概念也是基于此的具体体现。
        比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。

2.继承性 

继承体现了一种先进的编程模式。子类可以继承父类的属性和功能,即继承了父类具有的数据和数据上的操作,同时又可以增添子类独有的数据和数据上的操作。就比如人类继承了哺乳类的一般属性和特征,但同时又有属于人类自己的属性和特征。

3.多态性

多态有俩种含义:一种是操作名称的多态,也就是说有多个操作有相同的名字,但这些操作所接收的信息类型不同,所谓的操作名称的多态是指可以向操作传递不同的信息,以便让对象根据相对于收到的消息产生一定的行为。另一种多态是和继承相关的多态,是指同一个操作被不同类型对象调用的时候产生的不同的行为,例如猫和狗都是哺乳动物,都具备哺乳动物“喊叫”的功能,但狗和猫对于喊叫这个操作产生的具体行为是不同的,狗的喊叫是“汪汪汪”,猫的喊叫是“喵喵喵”


二.封装 

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

         public 可以理解为一个人的外貌特征,谁都可以看见, default 是包访问权限,是什么都不写的默认访问权限, protected 一般主要是用在继承当中, private 是只有自己知道,其他人都不知道自己的信息。
        我们希望类要尽量做到封装,隐藏内部实现细节,只暴露必要的信息给类的使用者,因此我们在使用的时候尽可能的使用必要严格的访问权限,如果一个方法能用 private 就尽量不要用  public ,一般来说,我们将类中的字段设为 private 将方法设为 public ,但具体的使用还是得结合实际情况认真选择,尽量避免滥用访问权限。
public class Student {
    private String name;
    private String gender;
    private int age;

    public void printStu() {
        this.name = "jake";
        this.age = 12;
        this.gender = "man";
        System.out.println("name:"+this.name);
        System.out.println("age:"+this.age);
        System.out.println("gender:"+this.gender);
    }
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.initStu();
    }
}

就比如我们上面这段代码,我们定义的姓名,年龄,性别都是 private 的,但是在类外,我们可以通过定义的 public 的方法来访问 private 的字段,这样可以使我们的程序更具健全性和安全性


三.继承

1.为什么要有继承

如果我们要用Java来描述猫和狗的话,那我们就需要设计俩个类

class Dog {
    public String name;//名字
    public int age;//年龄
    public float weight;//重量
    // 狗的行为
    public void eat() {
        System.out.println(name + "正在吃...");
    }
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
    public void barks() {
        System.out.println(name + ": 旺旺旺~~~");
    }
}

class Cat {
    public String name;//名字
    public int age;//年龄
    public float weight;//重量
    // 猫的行为
    public void eat() {
        System.out.println(name + "正在吃...");
    }
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
    void mew(){
        System.out.println(name + "喵喵喵~~~");
    }
}

但是我们会发现在俩个类中有许多相同的字段和方法,如果对于这些重复的部分,如果每一次都要重新编写的话,是不利于我们编程效率的,那我们能不能将这些共性抽取出来呢?为了解决此类问题,我们就引出了继承的概念

2.继承概念

        继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称为 子类或者派生类,原有的类我们称为 父类或者基类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是: 共性的抽取,实现代码复用
例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用

上述图示中,Dog和Cat都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可

3.继承的语法 

在Java中如果要表示类之间的继承关系,需要借助 extends 关键字,具体如下:

修饰符 class 子类 extends 父类 {
        // ... 
}

我们可以对于刚才的例子进行继承的操作:

class Animal {
    public String name;//名字
    public int age;//年龄
    public float weight;//重量
    public void eat() {
        System.out.println(name + "正在吃饭");
    }
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
}
class Dog extends Animal {
    public void barks() {
        System.out.println(name + ": 旺旺旺~~~");
    }
}

class Cat extends Animal{
    void mew() {
        System.out.println(name + "喵喵喵~~~");
    }
}

我们可以发现,代码整体比之前精简了许多,但是完成的功能却是一样的 

注意:

  • 子类会将父类中的成员变量或者成员方法继承到子类中了
  • 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

4.父类成员访问

在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?

子类中访问父类的成员变量

1. 子类和父类不存在同名成员变量:

public class Base {
    int a;
    int b;
}
public class Derived extends Base{
    int c;
    public void method(){
        a = 10; // 访问从父类中继承下来的a
        b = 20; // 访问从父类中继承下来的b
        c = 30; // 访问子类自己的c
    }
}

在这种情况下,我们是可以正常访问我们想访问的字段的

2. 子类和父类成员存在变量同名:
public class Base {
    int a;
    int b;
    int c;
}
public class Derived extends Base{
    int a; // 与父类中成员a同名,且类型相同
    char b; // 与父类中成员b同名,但类型不同
    public void method(){
        a = 100; // 访问子类自己新增的a
        b = 101; // 访问子类自己新增的b
        c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
        // d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
    }
}

在这种情况下,优先访问子类新增的变量,或者新赋值的变量,如果子类没有,再去父类中寻找,有就访问父类的变量,要是子类父类都没有,就编译失败,因此,我们做出以下总结:

在子类方法中 或者 通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的
  • 成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找

子类中访问父类的成员方法

1. 成员方法名字不同

public class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
}
public class Derived extends Base{
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC(){
        methodB(); // 访问子类自己的methodB()
        methodA(); // 访问父类继承的methodA()
        // methodD(); // 编译失败,在整个继承体系中没有发现方法methodD()
    }
}

在这种情况下,我们完全可以正常访问,成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错

2. 成员方法名字相同

public class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
    public void methodB(){
        System.out.println("Base中的methodB()");
    }
}
public class Derived extends Base{
    public void methodA(int a) {
        System.out.println("Derived中的method(int)方法");
    }
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC(){
        methodA(); // 没有传参,访问父类中的methodA()
        methodA(20); // 传递int参数,访问子类中的methodA(int)
        methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
    }
}

在这种情况下:通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错

5.super 关键字

        由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了 super 关键字,该关键字主要作用:在子类方法中访问父类的成员。

public class Base {
    int a;
    int b;
    public void methodA() {
        System.out.println("Base中的methodA()");
    }
    public void methodB() {
        System.out.println("Base中的methodB()");
    }
}
public class Derived extends Base {
    int a; // 与父类中成员变量同名且类型相同
    char b; // 与父类中成员变量同名但类型不同
    // 与父类中methodA()构成重载
    public void methodA(int a) {
        System.out.println("Derived中的method()方法");
    }
    // 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
    public void methodB() {
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC() {
// 对于同名的成员变量,直接访问时,访问的都是子类的
        a = 100; // 等价于: this.a = 100;
        b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从基类继承下来的部分
        super.a = 200;
        super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
        methodA(); // 没有传参,访问父类中的methodA()
        methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
        methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
        super.methodB(); // 访问基类的methodB()
    }
}

在子类方法中,如果想要明确访问父类中成员时,借助 super 关键字即可,需要注意的一点是, super 和 this 一样,只能在非静态方法中使用

6.子类构造方法

父子父子,先有父再有子,即:子类对象构造时,需要先调用父类构造方法,然后执行子类的构造方法

public class Base {
    public Base(){
        System.out.println("Base()");
    }
}
public class Derived extends Base{
    public Derived(){
        super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
                 // 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
                 // 并且只能出现一次
        System.out.println("Derived()");
    }
}
public class Test {
    public static void main(String[] args) {
        Derived d = new Derived();
    }
}

输出结果:

这里用户没有写 super()的话,编译器也会自动添加,因此输出结果也是一样的

PS:(在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句)

在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法,因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整

7.继承方式

在实际生活中,继承的概念不只是单一的一对一的继承,往往是有多种继承方式的,诸如下图的动物类继承:

在Java中,我们也支持多种继承方式,但是值得注意的是,与 C++ 不同的是,Java不允许多继承的方式存在,也就是说,在Java中,一个类,不允许同时继承多个类;即便是允许多层继承,我们一般也不建议进行超过3层的继承,就像递归一样,多层的嵌套往往是不利于我们编程效率的,在遇见这种情况的时候,我们一般就得思考别的办法对代码进行重构


四.多态

1.多态的概念

我们一般常说的多态大多是在继承的基础上而讲的,当一个操作被不同类型对象调用后产生的不同的行为,我们就将其叫做多态,比如下面的打印机这个例子,对于打印这个操作,我们用不同的对象(彩色打印机,黑白打印机)调用的时候,产生的结果就不一样,彩色打印机打印出来的是彩色的,黑白打印机打印出来的是黑白的,而这种不同的结果,就是多态的体现

又比如吃食物这个概念,在猫和狗的身上上就会有不一样的体现,猫吃猫粮,狗吃狗粮,总的来说,对于同一件事,发生在不同对象身上,就会有不同的结果

2.多态的实现条件

在Java中要实现多态,必须满足以下几个条件:

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

而我们要理解多态,就要理解下面俩个点:

  • 理解向上转型:
  • 理解重写: 

向上转型

向上转型可以分为3种方式

第一种方式:直接赋值

我们这里以Animal类举例,并且有一个Cat类来继承他

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
}

在这种情况下,我们用父类对象直接引用子类对象就叫做向上转型

    public static void main(String[] args) {
        Cat cat = new Cat("布偶",3);
        Animal animal1 = cat;
        animal1.eat();
        
        Animal animal2 = new Cat("橘猫",2);
        animal2.eat();
    }

我们可以看见输出结果,俩个对象都访问的是父类中的eat方法,都是吃食物

第二种方式:通过传参 

我们在原有的代码上再加入一个Dog类

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Dog extends Animal {
    //构造方法
    public Dog(String name,int age) {
        super(name,age);
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
}

我们新建一个方法,传入一个动物类型,然后调用eat方法,我们需要的参数是父类Animal,但是我们传入的子类对象Cat或者Dog中的对象也可以完成我们的传参,这种我们也称之为向上转型

    public static void fun(Animal animal) {
        animal.eat();
    }
    
    public static void main(String[] args) {
        Cat cat = new Cat("布偶",3);
        Dog dog = new Dog("哈士奇",2);
        fun(cat);
        fun(dog);
    }

我们可以看见输出结果,俩个对象都访问的是父类中的eat方法,都是吃食物

第三种方式:通过返回值

我们再这里新建俩个方法

    public static Animal fun1(Animal animal) {
        return new Cat("布偶",3);
    }
    public static Animal fun2(Animal animal) {
        return new Dog("哈士奇",2);
    }

我们的返回值是父类Animal但是我们返回的却是Animal的子类Cat或者Dog,这也算是向上转型

重写

        当我们的子类继承了父类后,我们对父类中的方法不改变其方法名,参数列表,返回值,我们只改变方法内部的细节,通过这种操作后,我们得到的方法就叫做重写的方法,而这样的操作就叫做重写

这里有些需要注意的地方:

  • 子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
  • 被重写的方法返回值类型可以不同,但是必须是具有父子关系的
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected
  • 父类被static、private修饰的方法、构造方法都不能被重写
  • 重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心
  • 将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写

我们就拿刚才的动物类进行举例,我们对继承的eat方法进行重写:

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Dog extends Animal {
    //构造方法
    public Dog(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃狗粮~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃猫粮~~~");
    }
}

3.多态的实现

在简单理解了向上转型重写后,我们就可以充分理解多态了,将不同的向上转型的方式和重写进行结合,我们就可以实现多态了

直接赋值实现多态
    public static void main(String[] args) {
        
        Animal animal1 = new Dog("哈士奇",2);
        animal1.eat();
        Animal animal2 = new Cat("橘猫",2);
        animal2.eat();

    }

我们观察输出结果,我们会发现,与刚才的结果是完全不同的,我们这一次不再是访问量父类对象中的eat方法,我们访问的子类中的方法eat

我们对于同样的eat方法,用在不同的对象上的结果是完全不一样的,用在Dog对象上就是吃狗粮,用在Cat对象上就是吃猫粮,而这就是我们多态的体现

通过传参实现多态 
    public static void fun(Animal animal) {
        animal.eat();
    }
    public static void main(String[] args) {
        Animal animal1 = new Dog("哈士奇",2);
        Animal animal2 = new Cat("橘猫",2);
        fun(animal1);
        fun(animal2);
    }

我们观察输出结果,同样可以实现多态

4.多态的优缺点 

优点:

  1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else
  2. 可扩展能力更强

什么叫 "圈复杂度" ?
圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂.因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 "圈复杂度".如果一个方法的圈复杂度太高, 就需要考虑重构.

 假如我们有个画图形的要求

class Shape {
    //属性....
    public void draw() {
        System.out.println("画图形!");
    }
}
class Rect extends Shape{
    @Override
    public void draw() {
        System.out.println("♦");
    }
}
class Cycle extends Shape{
    @Override
    public void draw() {
        System.out.println("●");
    }
}
class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}

如果是按照一般方式,我们要连续按照顺序打印多个图像,我们可能会如下设计,整体略显臃肿

    public static void drawShapes() {
        Rect rect = new Rect();
        Cycle cycle = new Cycle();
        Flower flower = new Flower();
        String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
        for (String shape : shapes) {
            if (shape.equals("cycle")) {
                cycle.draw();
            } else if (shape.equals("rect")) {
                rect.draw();
            } else if (shape.equals("flower")) {
                flower.draw();
            }
        }
    }

但如果是使用多态的话,我们就可以提高很高的效率,也方便我们阅读

    public static void drawShapes() {
    // 我们创建一个 Shape 对象的数组.
        Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),
                new Rect(), new Flower()};
        for (Shape shape : shapes) {
            shape.draw();
        }
    }

缺点:

  • 代码的运行效率降低,当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性
  • 构造方法没有多态性

 在我们实现多态的过程中,如果我们只实现向上转型而不实现重写的话,那我们就只能调用父类中的方法,无法实现多态,相对的,如果只实现重写,不实现向上转型的话,虽然可以调用子类的方法,但是不能实现多态的概念

因此我们总结如下:如果我们要实现多态,就需要在继承体系之下并且子类必须要对父类中的方法进行重写,然后通过父类的引用调用重写的方法




 本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Find My行李箱|苹果Find My技术与行李箱结合,智能防丢,全球定位

行李箱,亦称旅行箱、拉杆箱。是出门时所携带用以放置物品的箱子,它是行李的其中一种类型。通常行李箱是用来放置旅途上所需要的衣物、个人护理用品、纪念品和贵重物品。旅游出差我们离不开行李箱,可是一旦行李箱丢失将造成很大不便&#xff0…

蓝桥杯双周赛算法心得——串门(双链表数组+双dfs)

大家好,我是晴天学长,树和dfs的结合,其邻接表的存图方法也很重要。需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪 1) .串门 2) .算法思路 串门(怎么存图很关键&#xf…

基于springboot学生心理咨询评估系统的设计与实现 全套代码 全套文档 附带视频知道教程

springboot学生心理咨询评估系统,springboot vue mysql (毕业论文10784字以上,共30页,程序代码,MySQL数据库) 代码下载: 链接:https://pan.baidu.com/s/1MjiwuWdkVHFQ4toPP1vVrA?pwd4eck 提取码:4eck 【运行环境】 IDEA, JDK1.8, Mysql, Node, Vue …

阿里云服务器ECS经济型e实例和u1有什么区别?

阿里云服务器ECS经济型e实例和通用算力型u1实例有什么区别?如何选择?ECS经济型e实例是共享型云服务器,通用算力型u实例是企业级独享型云服务器,e实例性价比高,现在2核2G3M带宽一年99元,云服务器u1价格相对要…

浅析SR隧道路径批量构造方法

为什么要仿真PCE LSP下发隧道路径? 在大型的多区域网络中,路径计算非常复杂。在某些场景下,为了完成路径计算,需要在控制器上部署特殊的计算组件,并需要不同区域中的节点之间协作。这使得网元在进行路径计算时效率低&…

直播实时数仓基于DataLeap开放平台在发布管控场景的业务实践

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 背景 业务背景 随着字节业务的高速增长,业务场景越来越丰富,业务基于数据做的决策也越来越多,对数据的时效性要求也越来越高。…

layui table合计 totalRow 保留4位小数\ 异步请求数据的表格 新增行之后 如何更新数据

layui table合计 totalRow 保留4位小数: 例: totalRowMethod:(column: any, dataSource: any[]) > { let total 0; dataSource.forEach((item) > { total total Number(item[column.key]); …

Vite依赖预构建

本文使用的包管理工具是 npm 开发工具是 vscode 本文作为对 vite的了解性内容即可,实际开发中并不会做太多的工作 依赖预构建干了啥 首先vite会找到对应的依赖, 然后调用 esbuild(对js语法进行处理的一个库), 将其他规范的代码转换成 esmodu…

Web前端—CSS高级(定位、高级技巧、CSS修饰属性、综合案例:购物网站轮播图)

版本说明 当前版本号[20231108]。 版本修改说明20231107初版20231108对知识点(圆点)进行补充 目录 文章目录 版本说明目录day08-CSS高级01-定位相对定位绝对定位定位居中固定定位堆叠层级 z-index定位总结 02-高级技巧CSS精灵案例-京东服务HTML结构CS…

API是什么?解密API背后的奥秘

API,全称Application Programming Interface,是一种用于不同应用程序间通信的接口,它允许不同的应用程序之间交换数据和功能。API可以理解为应用程序提供给其他应用程序或开发者的接口,通过这个接口,其他应用程序或开发…

将 Ordinals 与比特币智能合约集成:第 4 部分

控制 BSV-20 代币的分配 在上一篇文章中,我们展示了智能合约可以在铸造后控制 BSV-20 代币的转移。 今天,我们演示如何控制此类代币的分发/发行。 无Tick模式 BSV-20 在 V2 中引入了无Tick模式,并采用了与 V1 不同的方法。 部署 (Deploy) …

openinstall携手途虎养车,赋能汽车服务数字化

近日,openinstall与中国领先的一站式汽车服务平台途虎养车再次续约,双方将开启第三年合作。过去两年,途虎在建设线上线下一体化数字平台的过程中,深度结合openinstall传参归因与渠道统计技术,打造出了一套高效的渠道来…

聚焦千兆光模块和万兆光模块的测试技术及设备

千兆光模块和万兆光模块的测试技术涉及多个方面,如光学性能测试、电气性能测试、动态性能测试、温度测试、环境和耐久性测试等。不同的测试技术可以验证不同的光模块的性能和稳定性,从而确保光模块在各种应用场景下的可靠性,下面将介绍一些常…

PSP - 蛋白质复合物结构预测 模版配对(Template Pair) 逻辑的特征分析

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/134328447 在 蛋白质复合物结构预测 的过程中,模版 (Template) 起到重要作用,提供预测结果的关于三维结构的先验信息&…

Ubuntu2004字体不清晰,排查流程

昨天一早来发现平时用的Ubuntu2004物理机的字体变得很模糊,之前还是好好的,这里记录一下解决方案。 解决方案 通过显示器物理按键设置“自适应”解决,我的显示器是长城的,“自适应”按钮是右边从下往上数第二个。 排查流程 我先…

WordPress Modown 6.2付费下载资源/付费查看内容 wp主题模板+erphpdown11.7

模板简介: 自适应响应式设计,兼容主流浏览器 网格样式与瀑布流样式任意切换 内置SEO优化 自带与主题UI完美兼容搭配的erphpdown前端用户中心页面(此功能若单独找我们定制也需要几百) 收费付费下载资源、付费查看内容、付费观看…

GoLong的学习之路(二十一)进阶,语法之并发(go最重要的特点)(协程的主要用法)

并发编程在当前软件领域是一个非常重要的概念,随着CPU等硬件的发展,我们无一例外的想让我们的程序运行的快一点、再快一点。Go语言在语言层面天生支持并发,充分利用现代CPU的多核优势,这也是Go语言能够大范围流行的一个很重要的原…

【Delphi】Android 开发HTTP请求出错解决方案

目录 一、故障现象 二、原因及解决方案 一、故障现象 在android内建的WebBrowser浏览器中通过http访问一个网站(注意不是https),出现如下错误提示: 在使用ntfy的时候,访问http定义的服务器地址(注意不是…

MySQL模糊查询/模式匹配(Pattern Match)

使用SQL查询数据时,时常会遇到这种情况,我们并不需要精确的匹配,而是要查找具有某类特点的数据。这种场景我们就要用到模糊查询。MySQL中常用的模糊查询方法有2种: like语句模糊查询regexp正则表达式模式匹配 目录 一、使用like模…

大厂面试题-为什么索引要用B+树来实现呢,而不是B树?

首先,常规的数据库存储引擎,一般都是采用B树或者B树来实现索引的存储。 (如图)因为B树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度会相比二叉树来说,会矮很多。 而对于数据库来说,所有的…