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

【C#学习笔记】C#特性的继承,封装,多态

在这里插入图片描述

文章目录

  • 封装
    • 访问修饰符
    • 静态类和静态方法
    • 静态构造函数
  • 继承
    • 继承原则
    • sealed修饰符
    • 里氏替换原则
    • 继承中的构造函数
  • 多态
    • 接口
      • 接口的实例化
    • 抽象类和抽象方法
      • 抽象类和接口的异同
    • 虚方法
    • 同名方法
      • new覆盖的父类方法
      • 继承的同名方法
    • 运行时的多态性
    • 编译时的多态性


照理继承封装多态应该是学习笔记中最先学习的。但是本系列不是面向新手的,基础的继承封装多态的概念应当是要被掌握的。而本文需要讲述C#中的一些继承封装多态的特性。

部分摘自C#学习笔记(二)— 封装、继承、多态

封装

封装,就是将类的属性和方法封闭起来,外部成员不可直接调用,只能通过预留的接口访问。

访问修饰符

在之前引用对象介绍class的时候,我们已经介绍过:
访问修饰符主要分为四种:

  • public:同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。(public属性可被继承)
  • private:只有同一 class 或 struct 中的代码可以访问该类型或成员。(private属性不可被继承)
  • protected:只有同一 class 或者从该 class 派生的 class 中的代码可以访问该类型或成员。(只有该类和其子类可访问)
  • internal:同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。 换句话说,internal 类型或成员可以从属于同一编译的代码中访问。

我们可以用访问修饰符来定义类的访问类型
111
默认当类未定义访问修饰符时,访问级别是internal。而其内的成员的未定义访问修饰符时默认未private。

class Manager // 在命名空间中定义,默认为internal,可被同一程序集的另一个代码文件访问
{class Parent // 在类中定义的成员类,默认为private,不可被同一程序集的另一个代码文件访问{}
}

(注意,在命名空间中,类的访问修饰符只能为internal或public,因为其他访问修饰符在命名空间中访问不了,也就没有定义的必要了)

静态类和静态方法

使用static修饰符定义的类被称为静态类。静态类基本上与非静态类相同,但存在一个差异:静态类无法实例化。 换句话说,无法使用 new 运算符创建类类型的变量。 由于不存在任何实例变量,因此可以使用类名本身访问静态类的成员。

例如,如果你具有一个静态类,该类名为 UtilityClass,并且具有一个名为 MethodA 的公共静态方法,如下面的示例所示:

static class UtilityClass
{public static int a = 1;public static void MethodA() { }
}
static void main(){UtilityClass.MethodA();
}

使用静态类,我们不用实例化对象,而是直接调用类中的public方法。其内部成员只能是静态的。(而实际上其实普通类也可以通过类名访问静态成员)
无法继承,无法实例化,静态类的主要目的是提供一个容器来组织和管理相关的静态成员。

静态构造函数

当我们第一次访问静态类的时候,会调用一次静态构造函数。而第二次之后不会,因此起到了一个初始化的功能。

static class UtilityClass
{public static int a = 1;public static void MethodA() { }static UtilityClass(){Debug.Log("我是静态类的静态构造函数");}
}
class NormalClass
{public static void MethodA() { }static NormalClass(){Debug.Log("我是普通类的静态构造函数");}public NormalClass(){Debug.Log("我是普通类的实例构造函数");}
}
void Start()
{UtilityClass.MethodA(); // 我是静态类的静态构造函数NormalClass.MethodA(); // 我是普通类的静态构造函数UtilityClass.MethodA(); // 无NormalClass.MethodA(); // 无//UtilityClass u = new UtilityClass(); 错误,静态类无法实例化NormalClass n = new NormalClass(); // 我是普通类的实例构造函数
}

而如果单独实例化一次普通类:

void Start()
{NormalClass n = new NormalClass(); // n.MethodA(); 错误,实例化对象无法访问静态方法// 先后输出两行:// 我是普通类的静态构造函数// 我是普通类的实例构造函数
}

继承

继承就是在已存在的类基础上,建立一个新类,保留原有类的属性和方法,同时又可以增加新的内容。
 已存在的类称为基类或父类,继承的类称为派生类或子类。

继承原则

在C#中只有class,struct,interface可以继承,其中class可以继承唯一的父类和其他任意数量的接口类。struct和interface只能继承接口类。

在这里插入图片描述
每一层继承可以添加一些可被继承的方法给下一层。也有一些成员不可被继承。其关系请看上面写的访问修饰符。

当访问类中的成员时,就是逐级向上访问的,如果子类和父类有同名成员优先访问子类成员。

sealed修饰符

使用sealed修饰符,是为了让该类不能再被继承

sealed class Father{
}class Son:Father{  //错误,不可被继承
}

密封类的目的是不希望一些最底层的类被继承,加强面向对象的规范性,结构性和安全性。

里氏替换原则

任何基类可以出现的地方,派生类一定可以出现。从继承的角度来看,子类是在父类的基础上扩充的,自然比父类要全面。另一方面,要遵循里氏替换原则,子类中定义的一些方法也需要父类可用。

看个例子:

//基类
public class Mouse
{public void Dig(){Debug.Log("打洞");}
}
//派生类
public class MouseSon : Mouse
{public void Dig(){Debug.Log("不会打洞");}
}
static void main()
{Mouse m1 = new Mouse();m1.Dig(); // 打洞MouseSon m2 = new MouseSon();m2.Dig(); // 不会打洞,与父类方法重名时优先访问该类中的方法
}

老鼠的儿子不会打洞,就违反了里氏替换原则。这种情况下父类能用的时候子类是不能用的,子类无法替换父类。

通常里氏替换原则有两种基本要求:

  1. 可以用子类对象代替父类对象
  2. 父类容器包含子类对象时与1实现相同
//基类
public class Mouse
{public void Dig(){Debug.Log("打洞");}
}
//派生类,变异老鼠儿子,可以飞
public class MouseSon : Mouse
{public void Fly(){Debug.Log("飞");}
}
static void main()
{Mouse m1 = new Mouse();m1.Dig(); // 打洞MouseSon m2 = new MouseSon();m2.Dig(); // 打洞m2.Fly(); // 飞Mouse m3 = new MouseSon();m3.Dig(); // 打洞// m3.Fly(); 老鼠爸爸不能飞
}

继承中的构造函数

当子类继承父类之后,如果要在子类定义构造方法,要么父类中不定义任何构造方法,要么父类定义一个无参数的构造方法:

class Parent
{// 父类无构造方法或定义下列无参数构造方法//public Parent()//{//Debug.Log("我是Parent");//}
}
class Son : Parent
{public Son(){Debug.Log("我是Son");}
}

但是如果父类中定义了带参数构造方法且没有定义无参数构造方法,则子类中定义构造方法(无论是否带参数)都报错。除非使用base关键字定义传回对应参数:

class Parent
{public Parent(int i){Debug.Log("我是Parent");}
}
class Son : Parent
{public Son(int i) : base(i){Debug.Log("我是Son");}
}

总的来说,子类的构造方法和父类的构造方法参数数量必须是对应的。如果父类构造方法至少接受一个参数,那么相应的子类构造方法需要接受参数并调用父类构造方法。


多态

接口

定义接口时我们需要用interface关键字定义,标准的接口命名格式需要在开头加上大写的I代表interface。 接口可以包含方法、属性、索引器、事件。不能包含任何其他的成员,例如:常量、字段、域、构造函数、析构函数、静态成员。

interface IHuman
{// 接口中不允许任何显式实现void Name();void Age();public int Make { get; set; }public string this[int index]{get;set;}
}

当继承接口时,也需要实现接口的所有方法,一个接口同样可以继承其他的接口,当一个接口继承多个其他接口后,这个接口被称为派生接口,其他接口被称为基接口。一个继承了派生接口的类,不仅需要实现派生接口中的所有方法,也需要实现基接口中的所有方法:

interface IBaseInterface
{void BaseMethod();
}
interface IEquatable : IBaseInterface
{bool Equals();
}
public class TestManager : IEquatable
{bool IEquatable.Equals(){throw new NotImplementedException();}void IBaseInterface.BaseMethod(){throw new NotImplementedException();}
}

接口的定义一般用于通用的行为,当多个类都需要实现这些行为,并且每个类实现该行为的方法都需要重写时,接口是十分必要的。

接口的实例化

在学习过程中,我本以为接口是无法实例化的,但事实上网络上很多博客的说法是错误的,C#中的接口是可以实例化的!

接口不能被直接实例化。它的成员通过实现该接口的任何类或者结构来实现。(MSDN)

public class SampleClass : IControl, ISurface
{void IControl.Paint(){System.Console.WriteLine("IControl.Paint");}void ISurface.Paint(){System.Console.WriteLine("ISurface.Paint");}
}SampleClass sample = new SampleClass();
IControl control = sample;
ISurface surface = sample;// The following lines all call the same method.
//sample.Paint(); // Compiler error.
control.Paint();  // Calls IControl.Paint on SampleClass.
surface.Paint();  // Calls ISurface.Paint on SampleClass.// Output:
// IControl.Paint
// ISurface.Paint

如上所示,当一个类继承了某接口,我们可以将这个类的实例隐式转换为改接口的实例。这个接口实例包含了object基类的四大方法和自身接口的方法,如果我们调用接口方法会发现接口实例的方法指向的是类重写的方法。这种方法的好处在于当一个类继承的接口拥有同名方法时,我们可以通过实例化接口来区分同名方法的调用。
当然也可以对未实现该接口的类显式转换为该接口,当然这并没有什么用,运行时是会报错的。


抽象类和抽象方法

抽象类和抽象方法的定义关键字是abstract,抽象方法必须要在抽象类中定义,并且抽象方法必须是public的。但是抽象类和接口一样不能被实例化,需要实现抽象类中所有的方法,重写抽象方法的关键词是override,抽象类也无法使用sealed进行修饰,因为它就是用于继承的目的才会被创建。

abstract class Parent
{protected int age = 1; public Parent() { }abstract public void callName();abstract public void callAge();
}
class Child : Parent
{public Child():base(){}public override void callName(){throw new NotImplementedException();}public override void callAge(){Debug.Log(age);}
}

抽象类毕竟也是类,比较特殊的是,虽然抽象类不可实例化,但它可以拥有一些实例化特性,例如属性或者构造方法等是可以不用abstract修饰的。子类也可以像继承了正常类一般使用。
如果一个抽象类继承了接口,那么它也需要实现接口中的方法,但是抽象类可以以抽象方法的形式来实现它:

    abstract class Parent:IHuman{protected int age = 1;public Parent() { }abstract public void callName();abstract public void callAge();public void Name(){throw new NotImplementedException();}abstract public void Age();}

抽象类可以实现一些具体的方法,也可以拥有具体的属性,除了可实现抽象方法外,其他的和普通的类也没有什么区别。

抽象类和接口的异同

相同点:抽象类和接口都需要继承来实现,都不可以被直接实例化,继承了它们的子类都需要实现其中的抽象(接口)方法,继承了接口的还需要实现其中的属性和索引器等
不同点:抽象类不可实例化,接口可以通过继承类的类型转换来间接实例化,抽象类可以有具体方法,接口只能定义函数头
网络上许多博客都把接口当做一个特殊的类,但我看来,接口就是接口,类就是类,这两个是完全不同的东西。甚至有些博客说什么“接口与抽象类的区别还有接口不能继承其他类,抽象类可以。”接口本来就不是类,只能继承接口,怎么继承类?

虚方法

使用virtual关键字来修改方法法、属性、索引器或事件声明,并使它们可以在派生类中被重写。 (静态属性不可使用virtual修饰符)

    class Animal{public virtual void Eat(){Debug.Log("吃素");}}class Lion:Animal{public override void Eat(){Debug.Log("吃肉");}}class Sheep:Animal{}

虚方法与使用抽象方法的区别在于:虚方法可以在任何类中使用,无论是普通类还是抽象类。而使用虚方法,我们可以灵活地决定是否需要在父类定义虚方法,而子类是否需要重写这个虚方法,这些都是自行决定的,不会有强制要求。正如同上述的例子,当需要重写时就用override重写虚方法,不需要就直接继承即可。此外,virtual关键字必须声明函数主体,这也意味着它无法用在接口或者抽象方法中。

        Lion lion = new Lion();lion.Eat(); // 吃肉Sheep sheep = new Sheep();sheep.Eat(); // 吃素Animal Cow = new Animal();Cow.Eat(); // 吃素Animal Tiger = new Lion();Tiger.Eat(); // 吃肉

同名方法

在子类中,可以使用一些同名的方法,主要是两种情形下:

  1. 覆盖父类方法时
  2. 继承的类和接口存在相同的方法名定义时

new覆盖的父类方法

举个例子:

    class Animal{public void Eat(){Debug.Log("吃素");}}class Lion:Animal{public new void Eat() // 是否使用new关键字都会覆盖,使用new来指示这是我们有意覆盖父类方法{Debug.Log("吃肉");}}class Sheep:Animal{}

根据上面继承的结构图,运行时会从子类到父类逐级查找方法,而子类new的同名方法覆盖了父类的方法,则会直接执行子类的方法。如果子类无定义则使用父类的方法:

        Lion lion = new Lion();lion.Eat(); // 吃肉Sheep sheep = new Sheep();sheep.Eat(); // 吃素Animal Cow = new Animal();Cow.Eat(); // 吃素Animal Tiger = new Lion();Tiger.Eat(); // 吃素

继承的同名方法

现在有一个如下的接口:

interface IEat
{void Eat();
}

现在我们有一个sheep类,它同时继承了AnimalIEat,定义如下:

    class Wolf : Animal, IEat{public void Eat(){Debug.Log("吃肉");}}void Start(){Wolf wolf = new Wolf();wolf.Eat(); // 吃肉IEat eat = wolf;eat.Eat(); // 吃肉}

我们发现上述情况下Eat()方法被同时重写了,Wolf类中的Eat方法覆盖了Animal类中的Eat方法,而同时也重写了接口的Eat方法。当出现同名方法时说明会同时覆写这些方法。而如果我们指定准确的方法名的话:

    class Wolf : Animal, IEat{public void Eat(){Debug.Log("吃肉");}void IEat.Eat(){base.Eat();}}void Start(){Wolf wolf = new Wolf();wolf.Eat(); // 吃肉IEat eat = wolf;eat.Eat(); // 吃素}

通过指明接口名可以准确定义不同方法。


运行时的多态性

细心的读者可能发现了:当我们用override重写虚方法时:

        Animal Tiger = new Lion();Tiger.Eat(); // 吃肉

而当我们覆盖原来的方法时:

        Animal Tiger = new Lion();Tiger.Eat(); // 吃素

在运行时,除了逐级向上查找要执行的方法(属性)之外,还会检查它是否是重写了virtual关键字,使用父类容器装子类对象时,如果虚方法已经被子类重写了,那么则会执行重写的方法。对于虚方法的执行只会执行第第一个查找到的overrider方法,talk is cheap,看看下面的例子:

    class Animal{public virtual void Eat(){Debug.Log("吃素");}}class Lion:Animal{public override void Eat(){Debug.Log("吃肉");}}class Tiger : Lion{public new void Eat(){Debug.Log("吃兔子");}}void Start(){Animal tiger = new Tiger();tiger.Eat(); // 吃肉}

上述例子中Eat()执行的是吃肉而非吃兔子,如果逐级上查的话第一个查找到的应当输出吃兔子。但是由于基类AniamlEat()是一个虚方法,所以执行的是逐级查找到的第一个被override重写的Eat()方法,所以是输出吃肉。

    class Tiger : Lion{public override void Eat() // 如果使用override再次重写{Debug.Log("吃兔子");}}void Start(){Animal tiger = new Tiger();tiger.Eat(); // 吃兔子Lion tiger = new Tiger();tiger.Eat(); // 吃兔子}

如果再次使用override重写,才会显示吃兔子,有意思的是尽管Lion类中的方法并不是virtual,我们还是重写了基类Animal的虚方法。

    class Lion:Animal{public sealed override void Eat(){Debug.Log("吃肉");}}class Tiger : Lion{public override void Eat() // 重写报错,Eat方法已经被密封了{Debug.Log("吃兔子");}}

如果我们不希望Tiger类在继承Lion后还重写Eat()方法,我们应当用sealed关键字来密封这个基类方法,保证它不会在继承Lion了之后再重写


编译时的多态性

在程序中,我们也需要用到一些同名但是不同参数的方法,这是为了方便使用同一个方法在不同情况下进行处理。我们称为重载(overload),例如:

    void Start(){HumanEat(吃点啥呢 ?);}string HumanEat(Animal meat) { return ""; }int HumanEat(Animal meat, Vegetable fruit) { return 1; }void HumanEat(Vegetable vegetable) { }

同样是人,同样是吃东西,但是不同的人吃的东西会不一样,素食主义者只吃素,大部分人荤素都吃,肉食主义者只吃肉。甚至有的时候我们需要函数的返回值也要做出区分。当我们需要调用HumanEat方法,又需要具体区分,重载是最好的选择,这样同一个函数就可以有灵活的调用,而不是把全部情况放在一个函数里,每多出一个情况,就重写原来函数,或是定义n多个方法,搞得光记个函数名都头大。


总结:本节的概念有点多,但每一个知识点都有其存在的意义,例如如果我们想要一个可以不用实例化,直接从命名空间调用的工具类,就应该使用静态类。使用静态类的静态构造函数保证初始化时的唯一调用。当使用不同的父类考虑继承的模式。当使用多态时考虑什么情况下应当使用什么样的多态?如果我们想要一个只有结构定义而没有具体实现,且不被实例化的基类就需要抽象类,当我们需要灵活的可继承的功能重写就需要接口。当我们需要多种情况下同种方法的实现就需要重载。如果希望多态性的体现,虚方法会优于覆盖方法。所有的面向对象特性都应当在实际使用时慎重考虑,设计时细心思考,根据经验来进行程序的设计。

相关文章:

【C#学习笔记】C#特性的继承,封装,多态

文章目录 封装访问修饰符静态类和静态方法静态构造函数 继承继承原则sealed修饰符里氏替换原则继承中的构造函数 多态接口接口的实例化 抽象类和抽象方法抽象类和接口的异同 虚方法同名方法new覆盖的父类方法继承的同名方法 运行时的多态性编译时的多态性 照理继承封装多态应该…...

常用的电参数

电参数根据电流的特点可以分为直流电参数和交流电参数,在电参数中有些是可以通过电参数表测得,有些参数则为通过测得的参数计算而来。 一、电参数 1.1 直接可测电参数 ——瞬时电压值 ——瞬时电流值 n——采样点数 f——频率 time——时间 其中&…...

Rabbitmq的应用场景

Rabbitmq的应用场景 一、异步处理 场景说明:用户注册后,需要发注册邮件和注册短信,传统的做法有两种 1.串行的方式 2.并行的方式 ​​串行方式​​: 将注册信息写入数据库后,发送注册邮件,再发送注册短信,以上三个任务全部完成后才返回给客户端。 这有…...

【CSS动画08--流光按钮】

CSS动画08--流光按钮 介绍HTMLCSS 介绍 流光button HTML <!DOCTYPE html> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><meta name"viewport" content"widthdevice-width,i…...

计算机视觉:比SAM快50倍的分割一切视觉模型FastSAM

目录 引言 1 FastSAM介绍 1.1 FastSAM诞生 1.2 模型算法 1.3 实验结果 2 FastSAM运行环境构建 2.1 conda环境构建 2.2 运行环境安装 2.3 模型下载 3 FastSAM运行 3.1 命令行运行 3.1.1 Everything mode 3.1.2 Text prompt 3.1.3 Box prompt (xywh) 3.1.4 Points p…...

【官方中文文档】Mybatis-Spring #目录

目录 此页面用于在GitHub上呈现索引。 NOTE: 由于链接目标是在使用maven-site-plugin转换为html的假设下指定的&#xff0c;因此在GitHub上的呈现中有一个锚点已损坏。 简介入门SqlSessionFactoryBean事务使用 SqlSession注入映射器Spring Boot使用 MyBatis APISpring Batch示…...

ardupilot开发 --- Lua脚本篇

概述 ArduPilot引入了对Lua脚本的支持&#xff1b; Lua脚本存放在 SD card 中&#xff1b; Copter-4.0 及以上版本才支持Lua脚本&#xff1b; scripting API &#xff1f; scripting applets &#xff1f; 飞控条件&#xff1a;2 MB of flash and 70 kB of memory &#xff1b…...

python35种绘图函数总结,3D、统计、流场,实用性拉满

文章目录 基础图误差线三维图等高线图场图统计图非结构坐标图 基础图 下面这8种图像一般只有两组坐标&#xff0c;直观容易理解。 函数坐标参数图形类别plotx,y曲线图stackplotx,y散点图stemx,y茎叶图scatterx,y散点图polarx,y极坐标图stepx,y步阶图barx,y条形图barhx,y横向条…...

shell脚本语句(画矩形、三角形、乘法表和小游戏)(#^.^#)

目录 一、语句 一、条件语句 一、以用户为例演示 一、显示当前登录系统的用户信息 二、显示有多少个用户 二、单分支if 一、输入脚本 二、验证结果 三、双分支if 一、输入脚本 二、验证结果 四、多分支if 一、输入脚本 二、验证 二、循环语句 一、shell版本的循环…...

vue3、react组件数据传值对比分析——父组件传递子组件,子组件传递父组件

文章目录 ⭐前言⭐react 组件传值实例&#x1f496;父组件传值给子组件&#xff08;props&#xff09;&#x1f496;子组件传递事件给父组件props绑定事件&#x1f496;父组件触发子组件的事件Ref ⭐vue3 组件传值实例&#x1f496; 父组件传递数据给子组件props&#x1f496; …...

2023国赛数学建模C题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…...

wxPython使用matplotlib绘制动态曲线

1.思路 我们创建了一个继承自wx.Frame的自定义窗口类MyFrame。在MyFrame的构造函数中&#xff0c;我们创建了一个matplotlib的Figure对象和一个FigureCanvas对象&#xff0c;用于在窗口中显示绘图结果。然后&#xff0c;我们使用numpy生成了一个包含100个点的x轴坐标数组self.…...

JVM——类的生命周期

文章目录 类加载过程加载验证准备解析初始化 卸载 一个类的完整生命周期如下&#xff1a; 类加载过程 Class 文件需要加载到虚拟机中之后才能运行和使用&#xff0c;那么虚拟机是如何加载这些 Class 文件呢&#xff1f; 系统加载 Class 类型的文件主要三步:加载->连接->…...

【Docker】docker数据卷(数据挂载)持久化

docker数据卷&#xff08;数据挂载&#xff09;持久化 一、docker对于数据的管理二、docker挂载主机目录---指定路径挂载三、docker使用数据卷Volume挂载四、数据共享--数据卷容器五、备份和恢复 docker的镜像是由多个只读的文件系统叠加在一起形成的。当我们在我启动一个容器的…...

Spring Boot实现IP地址解析

一、本地解析 如果使用本地ip解析的话&#xff0c;我们将会借助ip2region&#xff0c;该项目维护了一份较为详细的本地ip地址对应表&#xff0c;如果为了离线环境的使用&#xff0c;需要导入该项目依赖&#xff0c;并指定版本&#xff0c;不同版本的方法可能存在差异。 <d…...

小程序中通过canvas生成并保存图片

1. html <canvas class"canvas" id"photo" type"2d" style"width:200px;height: 300px;"></canvas> <button bindtap"saveImage">保存</button> <!-- 用来展示生成的那张图片 --> <image…...

Error creating bean with name ‘esUtils‘ defined in file

报错异常&#xff1a; 背景&#xff1a; esUtils在common服务中、启动media服务时候、报这个异常、后排查esUtils在启动时候发生异常引起的、在相关bean中加入try{}catch{}即可解决问题 String[] split url.split(","); HttpHost[] httpHosts new HttpHost[split.…...

Java开发面试题 | 2023

Java基础 接口和抽象类的区别&#xff1f;Java动态代理HashMap 底层实现及put元素的具体过程currenthashmap底层实现原理&#xff1f;map可以放null值吗&#xff0c;currenthashmap为什么不能放null值synchronze和reetrantlock区别&#xff1f;怎样停止一个运行中的线程&#…...

Java课题笔记~ 自定义拦截器实现权限验证

实现一个权限验证拦截器。 1、修改web.xml文件中请求路径 2、将所有的页面放入WEB-INF目录下 3、开发登录FirstController 4、开发拦截器 5、配置springmvc.xml文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.spri…...

微信小程序使用npm引入三方包详解

目录 1 前言2 微信小程序npm环境搭建2.1 创建package.json文件2.2 修改 project.config.json2.3 修改project.private.config.json配置2.4 构建 npm 包2.5 typescript 支持2.6 安装组件2.7 引入使用组件 1 前言 从小程序基础库版本 2.2.1 或以上、及开发者工具 1.02.1808300 或…...

pytest自动化框架运行全局配置文件pytest.ini

还记得在之前的篇章中有讲到Pytest是目前主要流行的自动化框架之一&#xff0c;他有基础的脚本编码规则以及两种运行方式。 pytest的基础编码规则是可以进行修改&#xff0c;这就是今日文章重点。 看到这大家心中是否提出了两个问题&#xff1a;pytest的基础编码规则在哪可以…...

视频播放实现示例Demo

学习链接 vuespringboot文件分片上传与边放边播实现 同步加载、播放视频的实现 ---- range blob mediaSource 通过调试技术&#xff0c;我理清了 b 站视频播放很快的原理 MSE (Media Source Extensions) 上手指南 浅聊音视频的媒体扩展&#xff08;Media Source Extension…...

makefile的自动化变量

一、是什么? 自动化变量:makefile依据执行的规则自动变化生成的变量 $(@) 规则的目标文件名 $(^) 所有依赖 依赖列表 $(<)第一个依赖文件名 $(*)规则中目标中%部分名 $(?)所有比目标文件更新的依赖文件列表,空格分隔 二、使用步骤 1.引入库 代码如下(示例): make …...

使用Kind搭建本地k8s集群环境

目录 1.前提条件 2.安装Kind 3.使用Kind创建一个K8s集群 3.1.创建一个双节点集群&#xff08;一个Master节点&#xff0c;一个Worker节点&#xff09; 3.2.验证一下新创建的集群信息 3.3.删除刚刚新建的集群 4.安装集群客户端 4.1.安装kubectl 4.1.1.验证kubectl 4.2.安…...

【STM32RT-Thread零基础入门】 7. 线程创建应用(多线程运行机制)

硬件&#xff1a;STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、RT-Thread相关接口函数1. 获取当前运行的线程2. 设置调度器钩子函数 二、程序设计1. 头文件包含及宏定义2. 线程入口函数定义3. main函数设…...

.net日志系统

.NET 平台提供了强大的日志记录系统,用于在应用程序中记录各种事件、错误和调试信息。最常用的日志记录库是 Microsoft.Extensions.Logging,它是一个通用的日志接口和基础框架,可以与多种日志实现集成。以下是如何使用 .NET 日志系统的基本步骤: 安装 NuGet 包:首先,您需…...

SpringCloud学习笔记(二)_Eureka注册中心

一、Eureka简介 Eureka是一项基于REST&#xff08;代表性状态转移&#xff09;的服务&#xff0c;主要在AWS云中用于定位服务&#xff0c;以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka Server。Eureka还带有一个基于Java的客户端组件Eureka Client&#xff…...

spark的eventLog日志分析

查找满足指定条件的app_id查询条件: 表名、时间、节点名时间限定: 最好适当放大, 不知道什么原因有点不准eventLog的存放路径: spark.history.fs.logDirectory 1. spark-sql 先限定时间段;数据是逐行读入的, 但 app_id要按整个文件过滤, 按每个条件打标;按app_id粒度聚合, 查…...

探究Java spring中jdk代理和cglib代理!

面对新鲜事物&#xff0c;我们要先了解在去探索事物的本质-默 目录 一.介绍二者代理模式 1.1.Jdk代理模式 1.2cglib代理模式 1.3二者区别 1.3.1有无接口 1.3.2灵活性 1.4对于两种代理模式的总结 1.4.1jdk代理模式 1.4.2cglib代理模式 二.两种代理模式应用场景 2.1jd…...

反转链表(C++)

1、迭代法的一种写法 ListNode* reverse_linkList(ListNode* head){if(head nullptr || head->next nullptr) return head;ListNode* begin nullptr;ListNode* mid head;ListNode* end head->next;while(true){mid->next begin;if(end nullptr){break;}begin …...

适配器模式:让不兼容的接口协同工作

在面向对象设计中&#xff0c;适配器模式是一种常见的结构型设计模式。它允许将不兼容的接口转换成客户端所期望的另一个接口&#xff0c;从而使不同的类协同工作。适配器模式的主要目的是解决不同接口之间的兼容性问题&#xff0c;同时也提高了代码的可重用性和灵活性。 问题…...

【1day】复现Milesight-VPNserver.js 任意文件读取漏洞

目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现 一、漏洞描述 Milesight路由器-VPN是由Milesight Technology Co., Ltd.开发的一种集成了VPN功能的路由器产品。它旨在为用户提供安全、可靠的远程访问和连接解决方案。Milesight-VPNserver.js存在任意文件读取…...

前端代码规范

1 husky husky用于绑定git hooks&#xff0c;在指定时机执行想要的命令 {"husky": {"hooks": {"pre-commit": "lint-staged" }} }需要手动修改.husky文件内容&#xff1a; . "$(dirname -- "$0")/_/husky.sh"n…...

Java接入文心一言

文章目录 文心一言应用创建接口对接接口文档代码示例依赖 常量类实体类 结束语 文心一言应用创建 首先需要先申请文心千帆大模型&#xff0c;申请地址&#xff1a;文心一言 (baidu.com)&#xff0c;点击加入体验&#xff0c;等通过审核之后就可以进入文心千帆大模型后台进行应…...

信息管理系统三级等保的一些要求

一、前言 在做一些互联网系统或面向互联网的系统时&#xff0c;需要进行备案&#xff0c;需要满足网络信息安全维护规章及有关规章制度要求&#xff0c;才能发布到互联网。所以在做系统的需求分析时&#xff0c;往往需要把信息管理系统三级等保的需求加上&#xff0c;方便开发…...

第六届“蓝帽杯”电子取证模块(初赛)解析+全资源一次性分享

前言:资源一次性分享 手机+电脑+exe+内存四个模块,我自己在网上也找了很久,才把资源找齐全,题目我也整理在这里,方便大家训练。 目录...

《Go 语言第一课》课程学习笔记(九)

常量&#xff1a;Go 在“常量”设计上的创新有哪些&#xff1f; Go 语言在常量方面的创新包括下面这几点&#xff1a; 支持无类型常量&#xff1b;支持隐式自动转型&#xff1b;可用于实现枚举。 常量 Go 语言的常量是一种在源码编译期间被创建的语法元素。这是在说这个元素…...

docker 安装nginx 和 elasticsearch ik 自定义分词

1、切换到/mydata 文件夹 创建 nginx 目录 mkdir nginx 2、运行 docker run --name nginx -p 80:80 -d nginx:1.22.0 3、复制docker 里面的nginx配置到 外面的nginx/conf 下面 docker cp nginx:/etc/nginx /mydata/nginx 4、把 /mydata/nginx下面的nginx 改…...

谈谈收音机的发展

目录 1.什么是收音机 2.收音机的工作原理 3.收音机的发展历史 4.收音机的历史作用 1.什么是收音机 收音机是一种电子设备&#xff0c;用于接收和播放广播电台的无线电信号。它是人们获取各种音乐、新闻、娱乐和其他广播节目的常用设备。 收音机通常由以下几个部分组成&…...

QTreeWidget——信号处理

文章目录 基本属性信号一、信号种类二、信号测试1、currentItemChanged、itemCollapsed、itemExpanded三个信号的测试2、itemActivated信号3、 itemChanged信号4、其余信号的测试代码&#xff08;包含以上代码&#xff09; 基本属性 信号 一、信号种类 //当前项发生变化时触…...

【Java从入门到精通|1】从特点到第一个Hello World程序

写在前面 在计算机编程领域&#xff0c;Java是一门广泛应用的高级编程语言。它以其强大的跨平台性能、丰富的库和生态系统以及易于学习的语法而备受开发者欢迎。本文将引导您逐步了解Java的特点、如何安装和配置开发环境&#xff0c;以及如何编写您的第一个Java程序。 一、Java…...

JAVA 读取jar包中excel模板

1、在resources路径下&#xff0c;新建report文件夹&#xff0c;放入excel模板 2、配置文件中的目录&#xff0c;分隔符使用 / template: /report/报告模板V1.0.xlsx3、使用getResourceAsStream()读取 XSSFWorkbook wb;try {//需要以/开始InputStream resourceAsStream this.g…...

解决方案:fatal error: openssl/bio.h: 没有那个文件或目录

出现报错如下&#xff1a; 出现该错误的原因有两个&#xff1a; 没有安装openssl或者libssl-dev库Libssl-dev版本过高&#xff0c;需要降级 一. 没有安装openssl或者libssl-dev库 使用指令安装openssl&#xff1a; 我的是已经安装完成了&#xff0c;所以再把libssl-dev的库也…...

【MySQL系列】ALTER语句详解,以及UPDATE,DELECT,TRUNCATE语句的使用+区别

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

c++关键字 =delete和=default

在C的类中&#xff0c;有四类特殊的成员函数&#xff1a;① 默认构造函数&#xff1b;② 拷贝构造函数&#xff1b;③ 拷贝赋值函数&#xff08;operator&#xff09;&#xff1b;④ 析构函数&#xff1b;它们控制着类的实例的创建、初始化、拷贝以及销毁。 &#xff08;1&…...

idea 左下角的Git(Version Control)中显示Local Changes窗口

打开Local Changes窗口来查看当前Git仓库的本地变更。 使用快捷键: - Windows: Alt9 - Mac: Cmd9 解决&#xff1a; &#xff08;1&#xff09;idea打开settings &#xff08;2&#xff09;点击Version Control窗口选项卡&#xff0c;选择Commit选项&#xff0c;对 Use.... in…...

.net老项目中Jquery访问webservice

.net老项目中Jquery访问webservice 1. xml类型返回 jQuery.ajax({type: "POST",async: false,url: "WebService/Evection.asmx/GetCheckUpApplyEForm",contentType: "application/json",data: "{lngEvectionID:" eformSNOriginal &…...

SpringBoot项目集成ElasticSearch服务

本文已收录于专栏 《中间件合集》 目录 版本介绍背景介绍优势说明集成过程1.引入依赖2.添加配置文件3.初始化 示例说明代码结果 总结提升 版本介绍 Spring boot的版本是&#xff1a; 2.3.12   ElasticSearch的版本是&#xff1a;7.6.2 背景介绍 在我们的项目中经常会遇到对于…...

2023年网络安全比赛--综合渗透测试(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.扫描目标靶机将靶机开放的所有端口,当作flag提交(例:21,22,23); 2.扫描目标靶机将靶机的http服务版本信息当作flag提交(例:apache 2.3.4); 3.靶机网站存在目录遍历漏洞,请将…...

一次网络不通“争吵“引发的思考

作者&#xff1a; 郑明泉、余凯 为啥争吵&#xff0c;吵什么&#xff1f; “你到底在说什么啊&#xff0c;我K8s的ecs节点要访问clb的地址不通和本地网卡有什么关系…” 气愤语气都从电话那头传了过来&#xff0c;这时电话两端都沉默了。过了好一会传来地铁小姐姐甜美的播报声…...