Java语法-类和对象之继承与多态(中)

1. 继承

          为什么要继承?

                从生物学角度来说,继承就是把父辈的基因遗传给子代,然后子代再在细胞分裂的途中产生变异,生成比父辈更加适应环境的物种.其中很重要的就是继承给子代的基因(父类的方法和属性)和子代在父辈的基础上产生的变异(方法的重写). 比如猫和狗都是哺乳动物,是在哺乳动物的基础上发生进化和变异产生的独立的物种.它们都能吃饭和睡觉,但是他们的叫声不同.

      由该图可看出,猫和狗的类存在大量的重复,因此我们提出了继承的思想,专门用来进行共性的抽取,实现代码的复用.

        1.1 继承的概念

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

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

从继承概念中可以看出继承最大的作用就是:实现代码复用,还有就是来实现多态(后序讲)

        1.2 继承的语法

        我们使用extends关键字来实现继承

                修饰符 class 子类 extends 父类 {

                //具体内容}

        我们拿刚刚的猫和狗继承动物类的例子来说

//这个是父类
class Animal {
    //下面是俩个类共同的特点,我们把类的共性进行抽取,从而实现代码的复用效果
    //继承是 is a 的关系
    public String name;
    public int age;
    public void eat(){
        System.out.println(this.name+"正在吃饭!");
    }


    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("animal的构造方法");
    }
    static {
        System.out.println("animal的静态代码块");
    }
    {
        System.out.println("animal的实例代码块");
    }
}
//以下是动物类的子类
public class Dog extends Animal{
    public Dog(String name, int age) {
        super(name, age);
        System.out.println("Dog调用父类的构造方法,初始化成员");

    }


    public void bark(){
        System.out.println(this.name+"正在狗叫");
    }


 }

class Cat extends Animal{
     public Cat(String name, int age) {
         super(name, age);//这个是调用父类的有俩个参数的构造方法
         System.out.println("Cat调用父类的构造方法,初始化成员");
     }

     public void miao(){
         System.out.println(this.name+"正在猫叫");
     }
 

}

        1.3 访问父类和自己的成员变量和方法

                访问变量:

                如果父子类的变量名字不同,我们直接创建对象之后直接调用即可.

                如果父子类变量名字相同,那么我们优先调用子类的变量

                访问方法:

                成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。

                我们来看一段代码:

class Animal {
    //下面是俩个类共同的特点,我们把类的共性进行抽取,从而实现代码的复用效果
    //继承是 is a 的关系
    public String name = "小黑";
    public int age;
    public void eat(){
        System.out.println(this.name+"正在吃饭!");
    }

    public Animal() {
        //无参构造方法
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("animal的构造方法");
    }
  
    }
}
public class Dog extends Animal{
    public int id = 123;
    public String name = "小白";
    public Dog(String name, int age) {
        super(name, age);
        System.out.println("Dog调用父类的构造方法,初始化成员");

    }

    public Dog(String name, int age, int id) {
        super(name, age);
        this.id = id;
    }
    public Dog() {

    }

    public void bark(){
        System.out.println(this.name+"正在狗叫");
    }




    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog.name);//直接访问继承下来的name
        System.out.println(dog.id);//直接访问dog自身的属性id
        dog.eat();//使用父类继承下来的eat方法
        dog.bark();//使用dog自身的bark方法


    }
}
//执行结果:
小白
123
小黑正在吃饭!
小白正在狗叫

          1.4 super关键字

           然后提出一个问题,我们该怎怎么在子类方法中访问父类的成员?

        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()
}
}

   【注意事项】

1. 只能在非静态方法中使用

2. 在子类方法中,访问父类的成员变量和方法。

        然后我们就可以根据super来构造子类的构造方法

package Class_Object.继承;


class Base {
    public int a = 3;
    public int c;

    public Base(int a, int c) {
        this.a = a;
        this.c = c;
    }

    public void method(){
        System.out.println("Base:method");
    }
}
class Derived extends Base {

    public int a = 10;
    public int b;

    public Derived(int a, int c) {
        super(a, c);
    }

    public void method(){
        System.out.println("Derived::method");
    }
    public void test() {
        super.method();//调用的是父类的方法
        this.method();//调用的是子类的方法
        System.out.println(this.a);
        System.out.println(a);
        System.out.println(super.a);
    }
}
public class Test {
    public static void main(String[] args) {
        Derived derived = new Derived(1,2);
        //super不能在静态方法使用
        //当子类和父类有同名的成员变量的时候,先看子类自己有没有,再看父类有没有
        derived.test();
    }


}
//Base:method
Derived::method
10
10
1

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


        1.5 super和this的异同

super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那他们之间有什么区别呢?

        相同点:

        1. 都是Java中的关键字

        2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段

        3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

        不同点:

        1. this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成

        2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性

         3. 在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造 方法中出现

        4. 构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有员的引用

        1.6 再谈初始化

        在java类和对象(上)篇里面我们介绍了几个代码块,我们现在再把继承的思想融入进去,看运行结果有什么不同

        

package Class_Object.继承;

public class Dog extends Animal{
    public int id = 123;
    public String name = "小白";
    public Dog(String name, int age) {
        super(name, age);
        System.out.println("Dog调用父类的构造方法,初始化成员");

    }

    public Dog(String name, int age, int id) {
        super(name, age);
        this.id = id;
    }
    public Dog() {

    }

    public void bark(){
        System.out.println(this.name+"正在狗叫");
    }


    static {
        System.out.println("Dog的静态代码块");
    }
    {
        System.out.println("Dog的实例代码块");
    }

    public static void main(String[] args) {
//        Dog dog = new Dog();
//        System.out.println(dog.name);//直接访问继承下来的name
//        System.out.println(dog.id);//直接访问dog自身的属性id
//        dog.eat();//使用父类继承下来的eat方法
//        dog.bark();//使用dog自身的bark方法
        Dog dog = new Dog("小白",12);
        System.out.println("=============");
        Dog dog1 = new Dog("小黑",12);


    }
}
 class Cat extends Animal{
     public Cat(String name, int age) {
         super(name, age);//这个是调用父类的有俩个参数的构造方法
         System.out.println("Cat调用父类的构造方法,初始化成员");
     }

     public void miao(){
         System.out.println(this.name+"正在猫叫");
     }
     static {

     }

}
class Animal {
    //下面是俩个类共同的特点,我们把类的共性进行抽取,从而实现代码的复用效果
    //继承是 is a 的关系
    public String name = "小黑";
    public int age;
    public void eat(){
        System.out.println(this.name+"正在吃饭!");
    }

    public Animal() {
        //无参构造方法
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("animal的构造方法");
    }
    static {
        System.out.println("animal的静态代码块");
    }
    {
        System.out.println("animal的实例代码块");
    }
}
//animal的静态代码块
Dog的静态代码块
animal的实例代码块
animal的构造方法
Dog的实例代码块
Dog调用父类的构造方法,初始化成员
=============
animal的实例代码块
animal的构造方法
Dog的实例代码块
Dog调用父类的构造方法,初始化成员

通过分析执行结果,得出以下结论:

        1、父类静态代码块优先于子类静态代码块执行,且是最早执行

        2、父类实例代码块和父类构造方法紧接着执行

        3、子类的实例代码块和子类构造方法紧接着再执行

        4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行

        1.7 protected 关键字

        我们来填一下前面的坑

        protected里面如果一个父类里面一个变量被protected修饰,那么我们可以在另一个包里面创建一个类,继承这个父类,然后创建对象,就能够访问父类的变量

package Class_Object.继承;

public class Test1 {
    protected int a = 1999;//被protected修饰的变量
    final public void method(){
        System.out.println("这个是final不能被重写");
    }

}

package Class_Object.Protected;

import Class_Object.继承.Test1;

public class Test extends Test1 {//不同包的子类

    public void func() {
        System.out.println(super.a);//使用父类被protected修饰的变量
        //protected不同包中的子类
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.func();
    }


}

}

        1.8 final关键字

        在引入final之前我们先聊一下继承的方式,在java中,继承只能是单继承,不支持多继承,而且一般我们不希望出现超过三层的继承关系,这时,我们就需要final关键字了.我们可以把final放在不希望被继承的类的访问修饰限定符前面如:final public class 类名{}

        final关键可以用来修饰变量、成员方法以及类。


        1. 修饰变量或字段,表示常量(即不能修改)

  final int a = 10; a = 20; // 编译出错


        2. 修饰类:表示此类不能被继承

final public class Animal {
...
}
public class Bird extends Animal {
...
} /
/ 编译出错
Error:(3, 27) java: 无法从最终com.bit.Animal进行继

     

package Class_Object.Protected;

import Class_Object.继承.Test1;

public class Test extends Test1 {

    public void func() {
        System.out.println(super.a);
        //protected不同包中的子类
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.func();
    }

//
//    @Override
//    public void method() {
//        super.method();
//    }TODO 无法重写,因为final修饰父类的该方法,该方法变成了密封方法不能被重写
}
//TODO final的几种用法
final class TestFinall {//TODO 1.它这个类加了final表示当前类不能被继承了
    final int a = 10;//TODO 2.此时a就叫做常量,a只能初始化一次
//    a = 20;//
    //final表示不可变

}
//}
//class f extends TestFinall{
//
//}

  1.9 继承和组合的关系

        和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。

继承表示对象之间是is-a的关系,比如:狗是动物

猫是动物组合表示对象之间是has-a的关系,比如:汽车

汽车和其轮胎、发动机、方向盘、车载系统等的关系就应该是组合,因为汽车是有这些部件组成的。
 

// 轮胎类
class Tire{
// ...
} /
/ 发动机类
class Engine{
// ...
} /
/ 车载系统类
class VehicleSystem{
// ...
}
class Car{
private Tire tire; // 可以复用轮胎中的属性和方法
private Engine engine; // 可以复用发动机中的属性和方法
private VehicleSystem vs; // 可以复用车载系统中的属性和方法
// ...
} /
/ 奔驰是汽车
class Benz extend Car{
// 将汽车中包含的:轮胎、发送机、车载系统全部继承下来
}

再比如学校,学校里面由学生和老师组成的:

package Class_Object.组合;

public class School {
    //组合是has a的关系
    public Student[] students;
    public Teacher[] teachers;
    int a;
    public School() {
        this.students = new Student[10];
        this.teachers = new Teacher[10];
        this.a = a;
    }
}
class Student{

}
class Teacher{

}

      差不多是这个意思: 把各个部件设置成一个类,然后把整体再设置一个类(框架),再在整体里面创建各个部件的类来填充这个类.

2.多态

        2.1 多态的概念

                简单来说就是多种形态,即:不同对象完成某个行为的时候会产生不同的状态.

比如:一个好看的小姐姐来和你搭话,你是一个好的态度,一个大老爷们来找你的时候你是另一个态度.

        总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果


        2.2 多态的实现条件

                1. 要有继承关系(向上转型)

                2. 子类和父类有同名的 重写(覆盖) 方法

                3. 通过父类的引用 去调用这个重写方法

看个例子:

package Class_Object.多态;

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name+"正在吃东西");
    }
    public Animal test(){
        return null;
    }
}
class Dog extends Animal {

    public Dog(String name, int age) {
        super(name, age);
    }
    public void bark() {
        System.out.println(this.name + "狗叫");
    }
    @Override  //这个只是个注解 ctrl+o
    public void eat() {
        //在继承关系上,满足方法返回值,方法名字,方法的参数列表一致,那么就是方法的重写
        System.out.println(this.name+"正在吃狗粮");

    }
    @Override
    public Dog test(){
        return null;//这个返回值父类是父类类型,子类为子类类型
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
class Cat extends Animal {

    public Cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(this.name + "正在吃猫粮");
    }

    @Override
    public Cat test() {
        return null;
    }
    public void miao() {
        System.out.println(this.name+"正在喵喵叫");
    }
}

public class Test {
    //向上转型
    //子类对象给父类
    public static void fuc(Animal animal) {
//TODO 传参进行向上转型
    }
    public static Dog fuc2(){
        Dog dog = new Dog("12",2);
        return dog;//TODO 返回值进行向上转型
    }

    public static void eatFunc(Animal animal) {
        animal.eat();//TODO 多态: 当父类引用 引用的子类对象不一样的时候,调用这个重写的方法,表现出来的行为是不一样的

}
    public static void main(String[] args) {
        Dog dog = new Dog("小白",9);
        Cat cat = new Cat("大白",89);
        eatFunc(dog);
        eatFunc(cat);


    }
    public static void main1(String[] args) {
        Dog dog = new Dog("小白",9);
        dog.eat();
        dog.bark();
        Animal animal1 = dog;//animal1这个引用指向了dog所指向的对象
        System.out.println("===========");
        Animal animal = new Dog("小黑",8);//TODO 直接引用
        animal.eat();
        fuc(dog);//这个也是向上转型
        Animal animal2 = fuc2();//这个也是向上转型
        animal.eat();//这个就是动态绑定,调用的时子类的eat(eat时父子类的重写方法)
        animal.test();//此时也是动态绑定(协变)
        System.out.println(dog);
        Animal animal3 = new Cat("大白",89);
    }
}

Animal是父类,Dog是子类,我们用父类的引用指向子类的对象,也就是:

父类 对象名 = new 子类(),然后我们再通过对象名来调用子类重写的父类的方法,这个过程就叫多态

        2.3 重写

        重写(override): 也称为覆盖.重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

        【方法重写的规则】

        子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致.

        被重写的方法返回值类型可以不同,但是必须是具有父子关系

        访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected

        父类被static、private修饰的方法、构造方法都不能被重写。

        重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写.

        重写和重载的区别:

        方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

        反正记住,重写只能改内容,其他不能改,构造方法一般不进行重写.

【重写的设计原则】

        对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。

例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们不应该在原来老的类上进行修改,因为原来的类,可能还在有用户使用,正确做法是:新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我们当今的需求了。

         然后我们聊聊静态绑定和动态绑定:

        静态绑定(前期绑定/早绑定): 比如你重载了一个方法再编译的时候,就会根据实参类中具体调用哪个方法

        动态绑定(后期绑定/晚绑定): 在编译的时候不能确定方法的行为(先调用父类的),需要等到程序运行时,才能确定具体调用哪个类的方法(再确定调用子类的)

        上次我们讲的toSting来打印对象就用到了方法的重载和动态绑定,

这个Object的toString(),注意Object是所有类的父类

 因此我们没有重写toString方法来直接调用object的toString方法:

就会出现这个类似地址的东西

但是如果我们重写了toString方法

        结果是:

然后我们就能够更好的理解重写了:重写就是为了扩充这个方法内部的实现功能.

        2.4 向上转型和向下转型:

        向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。

        语法格式:父类类型 对象名 = new 子类类型()

        animal是父类类型,但可以引用一个子类对象,因为是从小范围向大范围的转换

        向上转型的优点:让代码实现更简单灵活。

        向上转型的缺陷:不能调用到子类特有的方法。

        将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。
 

        向下转型: 父类引用再还原为子类对象

    

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();
// 编译失败,编译时编译器将animal当成Animal对象处理
// 而Animal类中没有bark方法,因此编译失败
// animal.bark();
// 向上转型
// 程序可以通过编程,但运行时抛出异常---因为:animal实际指向的是狗
// 现在要强制还原为猫,无法正常还原,运行时抛出:ClassCastException
        cat = (Cat)animal;
        cat.mew();
// animal本来指向的就是狗,因此将animal还原为狗也是安全的
        dog = (Dog)animal;
        dog.bark();
    }
}

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
 

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();
        }
    }
}

        2.5 多态的实际用例:

        我们学习到这里应该已经了解了继承和多态的使用,现在写一个例子

package Class_Object.多态的应用;

abstract public class Shape {//这是个抽象类,后面下一节会讲,现在单纯理解为一个父类

    abstract public void draw();
}
class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("矩形");//重写draw方法
    }
}
class Triangle extends Shape{

    @Override
    public void draw() {
        System.out.println("三角形");//重写draw方法
    }
}
class Cycle extends Shape {
    @Override
    public void draw() {

        System.out.println("圆形");//重写draw方法
    }
}

    public static void main(String[] args) {//这个是法2
        Shape[] shapes = {new Cycle(),new Triangle(),new Rect()};//造一个shape数组,然后直接在里面new 它的子类对象
        for (Shape shape:shapes) {
            shape.draw();//直接for循环,循环到哪个就调用哪个draw方法
        }
    }
    public static void main1(String[] args) {//这个是法1
        Cycle cycle = new Cycle();
        Rect rect = new Rect();
        Triangle triangle = new Triangle();
        String[] strings = {"cycle","rect","triangle"};
        for (String x:strings){
            if(x.equals("cycle")) {
                cycle.draw();
            } else if (x.equals("rect")) {
                rect.draw();
            } else if (x.equals("triangle")) {
                triangle.draw();
            }//但是if else的大量使用会造成圈复杂度太高
        }

    }
}

看到法1我们发现圈复杂度太高(使用大量的 if - else)不利于开发

并且法二有利于对扩展

如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低
 

class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}

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

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

相关文章

了解独享IP的概念及其独特优势

在网络世界中,IP地址是用来识别和定位设备的标识符。独享IP是一种服务模式。使用代理服务器时,用户拥有一个不与其他用户共享的专用独立IP地址。与共享IP相比,独享IP为用户提供了更高的独立性和隐私保护。下面详细介绍独享IP的定义、工作原理…

什么是unix中的fork函数?

一、前言 在本专栏之前的文档中已经介绍过unix进程环境相关的概念了,本文将开始介绍unix中一个进程如何创建出新进程,主要是通过fork函数来实现此功能。本文将包含如下内容: 1.fork函数简介 2.父进程与子进程的特征 3.如何使用fork创建新进程…

C语言实现归并排序(Merge Sort)

目录 一、递归实现归并排序 1. 归并排序的基本步骤 2.动图演示 3.基本思路 4.代码 二、非递归实现 1.部分代码 2.代码分析 修正后代码: 归并过程打印 性能分析 复杂度分析 归并排序是一种高效的排序算法,采用分治法(Divide and Con…

Spring6梳理13——依赖注入之引入集合Bean属性

以上笔记来源: 尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程(源码级讲解)https://www.bilibili.com/video/BV1kR4y1b7Qc 13 依赖注入之引入集合Bean属性 13.1 创建Lesson类,student类和teacher实体类…

Ansbile-变量

文章目录 零、Ansible的事实变量和内置变量?Ansible 的内置变量Ansible 的事实变量示例 一、Ansible的事实变量有哪些(不全)1. ansible_hostname2. ansible_fqdn3. ansible_os_family4. ansible_distribution5. ansible_version6. ansible_al…

从 Shapley 到 SHAP — 数学理解

如何计算 SHAP 特征贡献的概述 假设你(玩家 1)和朋友(玩家 2)参加了一场 Kaggle 比赛,你最终赢得了 10,000 元的一等奖。现在,你想公平地分配这笔钱。你的朋友建议你平分。但是,你的超参数调整技能更出色。你相信你应该得到更大的份额,因为你为团队做出了更多贡献。考虑…

如何在Windows和Linux之间实现粘贴复制

第一步 sudo apt-get autorremove open-vm-tools第二步 sudo apt-get update第三步 sudo apt-get install open-vm-tools-desktop第四步 一直按Y,希望执行 Y第四步 重启 reboot然后可以实现粘贴复制。

MySQL连接查询解析与性能优化成本

文章目录 一、连接查询1.连接查询基础1. INNER JOIN内连接2. LEFT JOIN (或 LEFT OUTER JOIN)左外连接3. RIGHT JOIN (或 RIGHT OUTER JOIN)右外连接4. FULL OUTER JOIN 2.连接查询的两种过滤条件3.连接的原理 二、性能优化成本1.基于成本的优化2.调节成本常数(1)mysql.server_…

如何在Markdown写文章上传到wordpress保证图片不丢失

如何在Markdown写文章上传到wordpress保证图片不丢失 写文日期,2023-11-16 引文 众所周知markdown是一款nb的笔记软件,本篇文章讲解如何在markdown编写文件后上传至wordpress论坛。并且保证图片不丢失(将图片上传至云端而非本地方法) 一&…

WSL进阶体验:gnome-terminal启动指南与中文显示问题一网打尽

起因 我们都知道 wsl 启动后就死一个纯命令行终端,一直以来我都是使用纯命令行工具管理Linux的。今天看到网上有人在 wsl 中启动带图形界面的软件。没错,就是在wsl中启动带有图形界面的Linux软件。比如下面这个编辑器。 ​​ 出于好奇,我就…

Linux部署python web项目Flask + gunicorn + nginx

文章目录 一、安装python&使用虚拟环境二、python程序重要参数加密2.1 非对称加密(RSA)2.2 生成密钥对2.4 以连接数据库参数加密为例2.4.1 工具类RSA.py 三、一个简单的Flask项目四、安装配置gunicorn4.1 安装4.2 启动/配置(选择eventlet)4.2.1 命令…

vue打包exe之electron-quick-start的npm install 报错

vue打包exe之electron-quick-start的npm install 报错 1、github地址2、问题3、解决4、其他(打包exe)参考 1、github地址 https://github.com/electron/electron-quick-start2、问题 我使用的pnpm install正常安装,执行npm start提示错误 3、解决 在package.js…

【LLM多模态】文生视频综述From Sora What We Can See: A Survey of Text-to-Video Generation

note 现在很多主流的文生视频应该还是Diffusion-based 基于扩散模型的方法这篇综述将现有研究按照三个维度进行分类:进化生成器(Evolutionary Generators)、卓越追求(Excellent Pursuit)、现实全景(Realis…

【学习笔记】MIPI

MIPI介绍 MIPI是由ARM、Nokia、ST、IT等公司成立的一个联盟,旨在把手机内部的接口如存储接口,显示接口,射频/基带接口等标准化,减少兼容性问题并简化设计。 MIPI联盟通过不同的工作组,分别定义一系列手机内部的接口标…

植物大战僵尸杂交版V2.5.1下载(最新版)

2.5.1版本更新公告: 在最新的2.5.1版本中,游戏对“两面夹击”关卡进行了多项重要调整。出怪倍率和种类均有所降低,部分关卡的初始阳光量也得到了调整,以增强玩家的策略性。同时,玩家可以在这些关卡中使用投手类植物&a…

sysbench 命令:跨平台的基准测试工具

一、命令简介 sysbench 是一个跨平台的基准测试工具,用于评估系统性能,包括 CPU、内存、文件 I/O、数据库等性能。 ‍ 比较同类测试工具 bench.sh 在上文 bench.sh:Linux 服务器基准测试中介绍了 bench.sh 一键测试脚本,它对…

RabbitMQ下载安装运行环境搭建

RabbitMQ运行环境搭建 1、Erlang及RabbitMQ安装版本的选择2、下载安装Erlang2.1、下载Erlang2.2、安装Erlang2.2.1、安装Erlang前先安装Linux依赖库2.2.2、解压Erlang压缩包文件2.2.3、配置2.2.4、编译2.2.5、安装2.2.6、验证erlang是否安装成功 3、RabbitMQ下载安装3.1、下载3…

FortiGate 无线组网

无线管理与配置 FortiAP 连接 internal 接口之后自动获得 ip 地址:192.168.1.xxx/24在 FortiGate 中创建 SSIDFortiGate 自动发现 FortiAP,将 FortiAP 添加到 FortiGate将 SSID 和 FortiAP 关联创建防火墙策略 下面我们就来一起看看在 FortiGate 中该如…

MT6765/MT6762(R/D/M)/MT6761(MT8766)安卓核心板参数比较_MTK联发科4G智能模块

联发科Helio P35 MT6765安卓核心板 MediaTek Helio P35 MT6765是智能手机的主流ARM SoC,于2018年末推出。它在两个集群中集成了8个ARM Cortex-A53内核(big.LITTLE)。四个性能内核的频率高达2.3GHz。集成显卡为PowerVR GE8320,频率…

前端——js基础

一、JavaScript (简称js)——js可以给网页实现一个动态效果 1.JavaScript 组成 - 核心语法 ECMScipt 简称(es): 规范js的基本语法 1.es是js的语法规范 管理者 2.js是es的实现 操作者 - DOM > 文档对象 提供js操作 (例如…