C#基础加强(8)之委托和事件

委托

简介

委托是一种可以声明出指向方法的变量的数据类型

声明委托的方式

格式: delegate <返回值类型> 委托类型名(参数) ,例如:

delegate void MyDel(string str) 。
// 注意:这里除了前面的 delegate 关键字,剩下部分和声明一个函数相同,但是 MyDel 不是函数名,而是委托类型名。

创建委托类型变量

声明委托变量的方式与声明变量相同,都是通过 new 关键字,例:

MyDel sayHello = new MyDel(SayHello);
/** SayHello 是一个方法句柄,并且它的返回值需要与 MyDel 的参数返回值相同;* sayHello 这个委托变量就指向 SayHello 方法*/

还有一种简化的写法:

MyDel sayHello = SayHello;
/** 反编译查看如下:*     MyDel sayHello = new MyDel(SayHello);* 即其实与原始写法相同*/

委托的使用

要使用委托可以直接使用 <委托变量名>() 的方式调用委托指向的方法,如果有参数就传递参数,例:

using System;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class Tests{delegate void MyDel(string str);void SayHello(string name){Console.WriteLine("hello " + name);}[Test]public void Test(){MyDel sayHello = SayHello;sayHello("张三");/** hello 张三*/}}
}
MyTests.Tests

委托变量之间可以互相赋值,其实就是一个传递方法指针的过程,如:

using System;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class Tests{delegate void MyDel(string str);void SayHello(string name){Console.WriteLine("hello " + name);}void SayName(string name){Console.WriteLine(name);}[Test]public void Test(){MyDel sayHello = SayHello;sayHello = SayName; // sayHello 本来指向 SayHello 方法,这一行让其指向了 SayName 方法sayHello("张三"); // 所以实际执行的是 SayName 方法/** 张三*/}}
}
MyTests.Tests

案例一:获取最大值

先从一个简单的需求开始,如果我们需要编写一个获取 int 数组中最大值的方法,很简单如下:

1 int GetMaxNum(int[] nums)
2 {
3     int max = nums[0];
4     for (var i = 1; i < nums.Length; i++)
5     {
6         if (nums[0] > max) max = nums[0];
7     }
8     return max;
9 }

假如又有一个要求,我们定义一个获取 string 数组中最大值(每个 string 变量都可转型为 int 变量)的方法,显示上述方法就不适用了。那有没有什么方法能够让其通用起来呢?

如果我们要获取 string 数组中的最大值,显然我们需要先将其中每个元素转换到 int 类型,然后再进行比较,即重点就是我们要如何定义它的比较规则?

上述代码的比较规则是在第 6 行的 if 块中,我们要做的就是让那个这个 if 块中的内容动态起来,此时委托就派上用场了,看如下代码:

/*** 获取数组中的最大值*/
object GetMax(object[] nums,CompareFunc compareFunc)
{object max = nums[0];for (var i = 1; i < nums.Length; i++){if (compareFunc(nums[i],max))max = nums[i];}return max;
}/*** 如果 obj1 比 obj2 大,则返回 true,否则返回 false*/
delegate bool CompareFunc(object obj1, object obj2);

上述我们新定义了一个 GetMax 方法,它的返回值为 object 类型,第一个参数为 object 数组类型,第二个参数则是 CompareFunc 委托变量。而 CompareFunc 委托的作用就是对比较规则一个定义,即我们要做的就是传入对应数组参数的同时也一起传入响应的比较规则的实现。

定义比较规则:

/*** 比较规则*/
bool CompareInt(object num1, object num2)
{return Convert.ToInt32(num1) > Convert.ToInt32(num2);
}

再看此时我们如何获取 int 数组的最大值:

[Test]
public void Test()
{object[] numArr = {32, 445, 65, 321, 4};var max = GetMax(numArr, CompareInt);Console.WriteLine(max);/** 445*/
}

而我们如果要获取一个 string 数组中的最大值,不用做修改,直接传入 string 类型数组即可:

[Test]
public void Test()
{object[] numArr = {"32", "445", "65", "321", "4"};var max = GetMax(numArr, CompareInt);Console.WriteLine(max);/** 445*/
}

此时来了一个新需求,有如下实体类:

namespace MyTests.Entities
{public class User{public User(){}public User(int id, string name, int age){this.id = id;this.name = name;this.age = age;}private int id;private string name;private int age;public int Id{get { return id; }set { id = value; }}public string Name{get { return name; }set { name = value; }}public int Age{get { return age; }set { age = value; }}public override string ToString(){return string.Format("Id: {0}, Name: {1}, Age: {2}", id, name, age);}}
}
MyTests.Entities.User

我们需要定义一个方法能够返回该实体对象数组中年龄最大的对象,很简单,我们只需要单独为 User 的实例定义一个它的比较规则即可,如下:

[Test]
public void Test()
{object[] userArr ={new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)};var max = GetMax(userArr, CompareUser);Console.WriteLine(max);/** Id: 1, Name: 张三, Age: 34*/
}bool CompareUser(object user1, object user2)
{return (user1 as User).Age > (user2 as User).Age;
}

委托最大的价值在于可以让我们在编写代码时不用考虑委托变量指向哪一个方法,只需要按照声明委托时的约定传入参数即可。其实有点类似于接口的作用,我们不需要了解它的具体实现就可以直接使用它。

泛型委托

自定义泛型委托

泛型委托的定义其实与泛型方法的定义相似,格式如下:

delegate <返回值类型> <方法名><泛型名称1, 泛型名称2, ...>(参数1, 参数2,...);

通过泛型委托上述案例可以修改如下:

using System;
using MyTests.Entities;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class GetMaxNumTest{[Test]public void Test(){User[] userArr ={new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)};var max = GetMax<User>(userArr, CompareUser);Console.WriteLine(max);/** Id: 1, Name: 张三, Age: 34*/}/*** 比较规则*/bool CompareUser(User user1, User user2){return user1.Age > user2.Age;}/*** 泛型方法*/T GetMax<T>(T[] nums, CompareFunc<T> compareFunc){T max = nums[0];for (var i = 1; i < nums.Length; i++){if (compareFunc(nums[i], max))max = nums[i];}return max;}/*** 泛型委托*/delegate bool CompareFunc<T>(T obj1, T obj2);}
}
MyTests.GetMaxNumTest

内置的泛型委托

.Net 中内置两个泛型委托 Func 和 Action ,日常开发中基本不用自定义委托类型了。 Func 是有返回值的委托,而 Action 是没有返回值的委托。使用如下:

using System;
using MyTests.Entities;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class Test1{void SayHello(string name){Console.WriteLine("hello " + name);}bool CompareUser(User user1, User user2){return user1.Age > user2.Age;}[Test]public void Test(){// 无返回值的委托Action<string> sayHello = SayHello;sayHello("张三");// 有返回值的委托Func<User, User, bool> compareUser = CompareUser;// 如果是有返回值的委托,那么最后一个泛型参数为返回值类型var isGt = compareUser(new User(1, "张三", 32), new User(2, "李四", 43));Console.WriteLine(isGt);/*hello 张三False*/}}
}
MyTests.Test

而上述的案例也可以修改为如下:

using System;
using MyTests.Entities;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class GetMaxNumTest2{[Test]public void Test(){User[] userArr ={new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)};var max = GetMax<User>(userArr, CompareUser);Console.WriteLine(max);/** Id: 1, Name: 张三, Age: 34*/}/*** 比较规则*/bool CompareUser(User user1, User user2){return user1.Age > user2.Age;}/*** 泛型方法 使用内置泛型委托*/T GetMax<T>(T[] nums, Func<T, T, bool> compareFunc){T max = nums[0];for (var i = 1; i < nums.Length; i++){if (compareFunc(nums[i], max))max = nums[i];}return max;}}
}
MyTests.GetMaxNumTest

匿名方法

匿名方法,就是没有名字的方法。使用委托的很多时候没必要定义一个普通方法,因为这个方法只有这个委托会用,并且只用一次,这个时候使用匿名方法最为合适。以将 SayHello 方法的指针赋给委托为例:

using System;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class Tests{#region 普通方法方式void SayHello(string name){Console.WriteLine("hello " + name);}public void TestOld(){Action<string> sayHello = SayHello;}#endregion#region 匿名方法方式[Test]public void TestNew(){Action<string> sayHello = delegate(string name) { Console.WriteLine("hello " + name); };}#endregion}
}

将最大值哪个案例使用匿名方法重构后如下:

using System;
using MyTests.Entities;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class GetMaxNumTest2{[Test]public void Test(){User[] userArr ={new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)};// 使用匿名方法var max = GetMax<User>(userArr, delegate(User user1, User user2) { return user1.Age > user2.Age; });Console.WriteLine(max);/** Id: 1, Name: 张三, Age: 34*/}/*** 泛型方法 使用内置泛型委托*/T GetMax<T>(T[] nums, Func<T, T, bool> compareFunc){T max = nums[0];for (var i = 1; i < nums.Length; i++){if (compareFunc(nums[i], max))max = nums[i];}return max;}}
}
MyTests.GetMaxNumTest

lambda表达式

使用

lambda 表达式其实是对匿名方法使用的一个再度简化,看如下示例:

Action<string> a1 = delegate(string s) { Console.WriteLine(s); };

上面是将一个匿名方法指针赋值给一个委托变量,通过 lambda 表达式可简化如下:

Action<string> a2 = (string s) => { Console.WriteLine(s); };

还可以省略参数类型,编译器会自动根据委托类型推断:

Action<string> a3 = (s) => { Console.WriteLine(s); };

如果只有一个参数,还可以省略小括号:

Action<string> a3 =  s => { Console.WriteLine(s); };

如果委托有返回值,并且方法体只有一行代码,这一行代码还是返回值,那么就可以连方法的大括号和 return 都省略:

Func<int,int,int> a4 = (i, j) => i + j;

 => 可读作“goes to”。

练习

1、将下面代码尽可能简化:

Action<string, bool > a1 = delegate(string s, bool b)
{if (b) { Console.WriteLine("true" + s); }else { Console.WriteLine("false" + s); }
};
Action<string, bool> a1 = (s, b) =>
{if (b) Console.WriteLine("true" + s);else Console.WriteLine("false" + s);
};
result
Func<string, int> f1 = delegate(string str) { return Convert.ToInt32(str);};
Func<string, int> f1 = str => Convert.ToInt32(str);
result

2、把下面的代码还原成匿名方法形式:

Action<string, int> a1 = (s, i) => { Console.WriteLine("s=" + s + ",i=" + i); };
Action<string, int> a1 = delegate(string s, int i) { Console.WriteLine("s=" + s + ",i=" + i); };
result
Func<int, string> f2 = n => (n + 1).ToString();
Func<int, string> f2 = delegate(int n) {return (n + 1).ToString();};
result
Func<int, int> f3 = n => n * 2;
Func<int, int> f3 = delegate(int n) { return n * 2; };
result

3、写出下面一个 lambda 表达式的委托类型及非匿名函数形式:

n => n > 0;
委托类型为 Func<int, bool>
非匿名函数形式:
public bool IsGtZero(int n)
{return n > 0;
}
result

4、使用 lambda 表达式修改获取最大值案例:

using System;
using MyTests.Entities;
using NUnit.Framework;namespace MyTests
{[TestFixture]public class GetMaxNumTest2{[Test]public void Test(){User[] userArr ={new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)};// 使用匿名方法var max = GetMax<User>(userArr, (User user1, User user2) => user1.Age > user2.Age);Console.WriteLine(max);/** Id: 1, Name: 张三, Age: 34*/}/*** 泛型方法 使用内置泛型委托*/T GetMax<T>(T[] nums, Func<T, T, bool> compareFunc){T max = nums[0];for (var i = 1; i < nums.Length; i++){if (compareFunc(nums[i], max))max = nums[i];}return max;}}
}
result

案例二:扩展集合的Where方法

通过上面学习到的内容,我们可以为集合做一个扩展方法,这个方法的功能是可以根据我们传入的 lambda 表达式过滤出我们需要的元素集合。

1、编写扩展方法:

using System;
using System.Collections.Generic;namespace MyTests.Ext
{/*** 集合扩展方法类*/public static class EnumerableExt{public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> data, Func<T, bool> filter){var list = new List<T>();foreach (var obj in data){if (filter(obj)){list.Add(obj);}}return list;}}
}
MyTests.Ext.EnumerableExt

2、使用:

User[] userArr =
{new User(1, "张三", 34),new User(2, "李四", 23),new User(3, "王五", 34)
};
// 获取 name 中包含 "张" 的元素集合
var list = userArr.MyWhere(p => p.Name.Contains(""));
foreach (var user in list)Console.WriteLine(user);
/*Id: 1, Name: 张三, Age: 34*/
test

委托的组合

委托是可以使用“+”号来进行组合的,组合后会生成一个新的委托对象,调用这个新的委托对象时,会按顺序将组合进来的委托依次执行。看如下示例:

using System;
using NUnit.Framework;namespace 委托的组合
{[TestFixture]public class Tests{[Test]public void Test1(){Action<string> a1 = SayHello1;Action<string> a2 = SayHello2;Action<string> a3 = SayHello3;// 组合Action<string> a4 = a1 + a2 + a3;a4("张三");/*hello 张三 from SayHello1hello 张三 from SayHello2hello 张三 from SayHello3*/}public void SayHello1(string name){Console.WriteLine("hello " + name + " from SayHello1");}public void SayHello2(string name){Console.WriteLine("hello " + name + " from SayHello2");}public void SayHello3(string name){Console.WriteLine("hello " + name + " from SayHello3");}}
}
委托的组合.Tests

还可以通过“-”号从委托对象中将已组合进来的委托对象移除,如下:

using System;
using NUnit.Framework;namespace 委托的组合
{[TestFixture]public class Tests{[Test]public void Test1(){Action<string> a1 = SayHello1;Action<string> a2 = SayHello2;Action<string> a3 = SayHello3;// 组合Action<string> a4 = a1 + a2 + a3;// 移除 a2 委托对象a4 = a4 - a2;a4("张三");/*hello 张三 from SayHello1hello 张三 from SayHello3*/}public void SayHello1(string name){Console.WriteLine("hello " + name + " from SayHello1");}public void SayHello2(string name){Console.WriteLine("hello " + name + " from SayHello2");}public void SayHello3(string name){Console.WriteLine("hello " + name + " from SayHello3");}}
}
委托的组合.Tests

委托如果有返回值则有一些特殊,不过委托的组合一般是给事件使用,普通情况很少使用,这里就不再深究。

事件

定义

给委托添加上 event 关键字它就是一个事件,格式如下:

[访问修饰符] event <委托类型> <事件名称>;

案例三:本命年事件

1、修改 User 实体类,定义一个事件,让其在本命年时触发:

using System;namespace MyTests.Entities
{public class User{public User(){}public User(int id, string name, int age){this.id = id;this.name = name;this.age = age;}private int id;private string name;private int age;public int Id{get { return id; }set { id = value; }}public string Name{get { return name; }set { name = value; }}public int Age{get { return age; }set{if (age % 12 == 0) OnBirthYear(this.name);age = value;}}public override string ToString(){return string.Format("Id: {0}, Name: {1}, Age: {2}", id, name, age);}public event Action<string> OnBirthYear; // 定义一个本命年触发的事件
    }
}
MyTests.Entities.User

2、使用:

var user1 = new User();
var user2 = new User();
var user3 = new User();
// 给每一个 User 对象通过 += 注册事件
user1.OnBirthYear += (name, age) => { Console.WriteLine(name + age + "岁了,本命年到了,喝稀饭"); };
user2.OnBirthYear += (name, age) => { Console.WriteLine(name + age + "岁了,本命年到了,吃馒头"); };
user3.OnBirthYear += (name, age) => { Console.WriteLine(name + age + "岁了,本命年到了,大鱼大肉"); };user1.Id = 1;
user1.Name = "张三";
user1.Age = 23;            user2.Id = 2;
user2.Name = "李四";
user2.Age = 24;user3.Id = 3;
user3.Name = "王五";
user3.Age = 36;
/*李四24岁了,本命年到了,吃馒头
王五36岁了,本命年到了,大鱼大肉*/

注册事件触发的方法时方法的参数及返回值要与事件的委托一致。

事件原理

事件的注册和移除实际上是通过事件的 add 和 remove 方法完成,在这两个方法中维护了同一个委托对象,且事件不可为 null。上述实体类也可修改如下:

using System;namespace MyTests.Entities
{public class User{public User(){}public User(int id, string name, int age){this.id = id;this.name = name;this.age = age;}private int id;private string name;private int age;public int Id{get { return id; }set { id = value; }}public string Name{get { return name; }set { name = value; }}public int Age{get { return age; }set{age = value;if (age % 12 == 0){if (_OnBirthYear != null){_OnBirthYear(this.name,this.age);}}}}public override string ToString(){return string.Format("Id: {0}, Name: {1}, Age: {2}", id, name, age);}private Action<string, int> _OnBirthYear; // 定义一个本命年触发的事件public event Action<string, int> OnBirthYear{add { _OnBirthYear += value; }remove { _OnBirthYear -= value; }}}
}
MyTests.Entities.User

委托与事件总结

委托的作用

占位,在不知道将来要执行方法的具体逻辑时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要确定)。在实际调用之前,需要为委托赋值。

事件的作用

事件的作用域委托变量一样,只是在功能上相对委托变量有更多的限制,比如:

  • 只能通过 "+=" 或 "-=" 来绑定方法(事件处理程序)。
  • 只能在类的内部调用(触发)事件。

事件和委托的关系

反编译会发现,事件是由一个私有的委托变量、 add_* 和 remove_* 方法组成,而事件的非简化写法就是声明一个私有的委托变量和  add 、 remove 方法。

相关面试题

1、说一下事件和委托的关系?

网上有很多答案说事件就是委托,这个肯定是错误的。只能说事件的实现依赖于委托,因为事件是由一个私有的委托变量、 add_* 和 remove_* 方法组成。

2、接口中可以定义事件吗?那索引器和属性呢?

首先,接口中只可以定义方法的签名,事件、索引器、属性本质上都是方法,所以是可以定义的。

看如下示例:

using System;
using System.Collections.Generic;namespace MyTests
{public interface Interface1{// 属性List<int> list { get; set; }// 索引器long this[int index] { get; set; }// 事件event Action<string, int> OnEvent;}
}
MyTests.Interface1

对应反编译文件为:

.class public interface abstract auto ansi Interface1
{.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = { string('Item') }.event [mscorlib]System.Action`2<string, int32> OnEvent{.addon instance void MyTests.Interface1::add_OnEvent(class [mscorlib]System.Action`2<string, int32>).removeon instance void MyTests.Interface1::remove_OnEvent(class [mscorlib]System.Action`2<string, int32>)}.property instance int64 Item{.get instance int64 MyTests.Interface1::get_Item(int32).set instance void MyTests.Interface1::set_Item(int32, int64)}.property instance class [mscorlib]System.Collections.Generic.List`1<int32> list{.get instance class [mscorlib]System.Collections.Generic.List`1<int32> MyTests.Interface1::get_list().set instance void MyTests.Interface1::set_list(class [mscorlib]System.Collections.Generic.List`1<int32>)}}
MyTests.Interface1 反编译 IL 内容

可以看到接口中定义事件实际上是声明了 add_* 和 remove_* 方法的签名,定义索引器实际上是声明了 set_Item 和 get_item 方法的签名,而定义属性实际上是声明了 set_* 和 get_* 方法的签名。

转载于:https://www.cnblogs.com/zze46/p/10702364.html

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

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

相关文章

模板类的析构函数如何写_顶尖文案如何写?这6大模板、29个方法,奥美大咖都在用!|优惠最后1天...

敲黑板划重点&#xff1a;《顶尖文案训练营》第5期将于2月20日(正月十六)开班&#xff0c;现在报名享受春节特惠8折优惠&#xff0c;今天是优惠最后1天&#xff01;先到先得&#xff0c;速速报名抢位&#xff5e;马上就是2.14情人节了&#xff0c;馒火火在这里提前祝大家情人节…

ubuntu 查看日历,日期

cal 查看当前月日历 cal -y 2008 查看2008年日历 cal -y 2008 > 123.txt 打印到123.txt date 当前日期具体时间 date “%y年%m月%d日”

有效的Java –所有对象通用的方法

所有对象共有的方法&#xff08;第3章&#xff09; 这是Joshua Blochs的《 有效的Java》第3章的简短摘要。我仅包括与自己相关的项目。 一般 等值合约将等价关系描述为&#xff1a; x.equals(null) false 自反 – x.equals(x) true 对称 –如果x.equals(y) true则y.equa…

几种页面置换算法

地址映射过程中&#xff0c;若在页面中发现所要访问的页面不再内存中&#xff0c;则产生缺页中断。当发生缺页中断时操作系统必须在内存选择一个页面将其移出内存&#xff0c;以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。常见的置换算法有&…

win7摄像头怎么开_win7网络连接不可用怎么办

win7网络连接不可用怎么办&#xff1f;网络出现故障最常见的就是网络明明连接上&#xff0c;但是依然提示网络连接不可用&#xff0c;小白系统遇到最常见的就是使用win7系统的用户反馈的&#xff0c;下面让小白系统教你解决win7网络连接不可用的问题吧。首先我们判断网络状态是…

cmake--安装

一&#xff0c; 目录结构 ├── cmake-examples.conf├── CMakeLists.txt├── include│ └── installing│ └── Hello.h└── src ├── Hello.cpp └── main.cpp * link:CMakeLists.txt[] - Contains the CMake commands yo…

ubuntu 关机重启

关机&#xff0c;重启 reboot &#xff08;重启&#xff09; shutdown -h now &#xff08;立刻关机&#xff09; shutdown -h 10 &#xff08;10min后立刻关机&#xff09; shutdown -h 20:05 &#xff08;今天20:05立刻关机&#xff09;

excel合并两列内容_excel新手问题:怎么把两列数据合并到一起?用这个公式

今天看见有新手在问&#xff1a;怎么把两列数据合并到一起&#xff1f;其实&#xff0c;这种情况在工作中会经常遇到&#xff0c;但很多人可能还在用复制粘贴的方法。只要掌握最简单的一个函数公式&#xff0c;就可以实现快速两列合并。第一步&#xff1a;掌握“&”运算符使…

Pycharm Anaconda 安装dlib

由于采用python3.7安装会出现各种问题&#xff0c;两种解决方法。 1&#xff09;安装Cmake boost等&#xff08;不推荐&#xff0c;麻烦且不容易成功&#xff09;。 2&#xff09;安装Anaconda&#xff0c;创建一个python3.6的环境。 这里使用第二种。 一、安装Anaconda 。 方法…

java 使用jasper_使用Jasper Reports以Java创建报告

java 使用jasper上周&#xff0c;我试图使用Jasper创建报告。 在这篇文章中&#xff0c;我将记录一些资源和链接&#xff0c;以便对任何寻求类似信息的人都有用。 我将介绍Jasper报告&#xff0c;示例和Dynamic Jasper的生命周期。 Jasper Reports是世界上最受欢迎的开源报告…

计算机科学基础知识(四): 动态库和位置无关代码

一、前言 本文主要描述了动态库以及和动态库有紧密联系的位置无关代码的相关资讯。首先介绍了动态库和位置无关代码的源由&#xff0c;了解这些背景知识有助于理解和学习动态库。随后&#xff0c;我们通过加-fPIC和不加这个编译选项分别编译出两个relocatable object file&…

安装后添加没有class library_《没有秘密的你》:戚薇曝光手机号,粉丝急忙添加后却甜哭了?...

现在大家对于戚薇都是非常熟悉的吧&#xff0c;现在她可以说是娱乐圈内非常受关注的一个明星了&#xff0c;因为自己的颜值和耿直的性格也是直接圈粉无数&#xff0c;当时自己没有很多名气的时候&#xff0c;更是因为自己的女儿增添了很多的人气。想必在今年夏天的时候&#xf…

ubuntu 硬盘使用情况

df &#xff08;硬盘使用情况&#xff09; df -h du &#xff08;当前文件夹多大&#xff09; du -h

执行器的Spring启动和安全性事件

Spring Boot Actuator提供了审核功能&#xff0c;用于在启用Spring Security的Spring Boot应用程序中发布和侦听与安全相关的事件。 默认事件是身份验证成功&#xff0c;身份验证失败和访问被拒绝&#xff0c;但是可以使用自定义事件进行扩展。 确保在项目中启用了Spring Boot…

docker 查看日志_8个优秀Docker容器监控工具,收藏了

Docker是目前使用最广泛的容器之一&#xff0c;但它并不总是像物理硬件一样可见。而使用docker容器监控工具有助于消除这种透明度的缺失。以下介绍8种优秀Docker容器监控工具。1.SolarWinds Server&Application MonitorSolarWinds Server&Application Monitor是一个应用…

ubuntu 打包压缩

打包 tar -cvf test.tar *.txt tar -cvf test.tar *.txt 解包 tar -xvf test.tar tar -xvf test.tar -C abc/ 解压到当前路径的abc目录下 打包压缩 tar -zcvf test.tar.gz *.txt 解压缩包 tar -zxvf test.tar -C abc/ 解压到当前路径的abc目录下 .tar.bz2格式…

计算机基础知识:什么是位、字节、字、KB、MB

位、字节、字、KB、MB 位&#xff1a;“位(bit)”是电子计算机中最小的数据单位。每一位的状态只能是0或1。 字节&#xff1a;8个二进制位构成1个“字节(Byte)”&#xff0c;它是存储空间的基本计量单位。1个字节可以储存1个英文字母或者半个汉字&#xff0c;换句话说&#xf…

Tr A(矩阵快速幂)

A为一个方阵&#xff0c;则Tr A表示A的迹&#xff08;就是主对角线上各项的和&#xff09;&#xff0c;现要求Tr(A^k)%9973。 Input 数据的第一行是一个T&#xff0c;表示有T组数据。 每组数据的第一行有n(2 < n < 10)和k(2 < k < 10^9)两个数据。接下来有n行&am…

matlab中的方波信号图片_基于Matlab的雷达信号处理仿真

这是一个较为基础的图文教程(含仿真代码)&#xff1a;利用MATLAB设计经典的雷达数字信号处理。该系统具备对雷达目标回波的处理能力&#xff0c;能够从噪声中将目标检测出来&#xff0c;并提取目标的距离、速度、角度信息。教程分五节完成&#xff0c;主要包括&#xff1a;第一…