Stack栈
知识点一 Stack的本质
Stack(栈)是一个C#为我们封装好的类
它的本质也是object[]数组,只是封装了特殊的存储规则Stack是栈存储容器,栈是一种先进后出的数据结构
先存入的数据后获取,后存入的数据先获取
栈是先进后出
知识点二 申明
需要引用命名空间 System.Collections
Stack stack = new Stack();
知识点三 增取查改
增
压栈
stack.Push(1); stack.Push("123"); stack.Push(true); stack.Push(1.2f); stack.Push(new Test());
取
栈中不存在删除的概念
只有取的概念
弹栈
object v = stack.Pop(); Console.WriteLine(v); v = stack.Pop(); Console.WriteLine(v);
查
1.栈无法查看指定位置的 元素
只能查看栈顶的内容
v = stack.Peek(); Console.WriteLine(v); v = stack.Peek(); Console.WriteLine(v);
2.查看元素是否存在于栈中
if( stack.Contains("123") ) { Console.WriteLine("存在123"); }
改
栈无法改变其中的元素 只能压(存)和弹(取)
实在要改 只有清空
stack.Clear(); Console.WriteLine(stack.Count); stack.Push("1"); stack.Push(2); stack.Push("哈哈哈");
知识点四 遍历
1.长度
Console.WriteLine(stack.Count);
2.用foreach遍历
而且遍历出来的顺序 也是从栈顶到栈底
foreach(object item in stack) { Console.WriteLine(item); }
3.还有一种遍历方式
将栈转换为object数组
遍历出来的顺序 也是从栈顶到栈底
object[] array = stack.ToArray(); for (int i = 0; i < array.Length; i++) { Console.WriteLine(array[i]); } Console.WriteLine(stack.Count);
4.循环弹栈
while( stack.Count > 0 ) { object o = stack.Pop(); Console.WriteLine(o); } Console.WriteLine(stack.Count);
知识点五 装箱拆箱
由于用万物之父来存储数据,自然存在装箱拆箱。
当往其中进行值类型存储时就是在装箱
当将值类型对象取出来转换使用时,就存在拆箱。
Queue
知识点一 Queue本质
Queue是一个C#为我们封装好的类
它的本质也是object[]数组,只是封装了特殊的存储规则Queue是队列存储容器
队列是一种先进先出的数据结构
先存入的数据先获取,后存入的数据后获取
先进先出
知识点二 申明
需要引用命名空间 System.Collections
Queue queue = new Queue();
知识点三 增取查改
增
queue.Enqueue(1); queue.Enqueue("123"); queue.Enqueue(1.4f); queue.Enqueue(new Test());
取
队列中不存在删除的概念
只有取的概念 取出先加入的对象
object v = queue.Dequeue(); Console.WriteLine(v); v = queue.Dequeue(); Console.WriteLine(v);
查
1.查看队列头部元素但不会移除
v = queue.Peek(); Console.WriteLine(v); v = queue.Peek(); Console.WriteLine(v);
2.查看元素是否存在于队列中
if( queue.Contains(1.4f) ) { Console.WriteLine("队列中存在1.4f"); }
改
队列无法改变其中的元素 只能进出队列
实在要改 只有清
Console.WriteLine(queue.Count);
queue.Clear();
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);知识点四 遍历
1.长度
Console.WriteLine(queue.Count);
2.用foreach遍历
foreach (object item in queue)
{
Console.WriteLine(item);
}
3.还有一种遍历方式
/ 将队列转换为object数组
object[] array = queue.ToArray();
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
4.循环出列
while(queue.Count>0)
{
object o = queue.Dequeue();
Console.WriteLine(o);
}
Console.WriteLine(queue.Count);
知识点五 装箱拆箱
由于用万物之父来存储数据,自然存在装箱拆箱。
当往其中进行值类型存储时就是在装箱
当将值类型对象取出来转换使用时,就存在拆箱。
Hashtable
知识点一 Hashtalbe的本质
Hashtable(又称散列表) 是基于键的哈希代码组织起来的 键/值对
它的主要作用是提高数据查询的效率
使用键来访问集合中的元素
知识点二 申明
需要引用命名空间 System.Collections
Hashtable hashtable = new Hashtable();
知识点三 增删查改
增
hashtable.Add(1, "123"); hashtable.Add("123", 2); hashtable.Add(true, false); hashtable.Add(false, false);
注意:不能出现相同键
删
1.只能通过键去删除
hashtable.Remove(1);
2.删除不存在的键 没反应
hashtable.Remove(2);
3.或者直接清空
hashtable.Clear(); hashtable.Add(1, "123"); hashtable.Add(2, "1234"); hashtable.Add(3, "123"); hashtable.Add("123123", 12);
查
1.通过键查看值
找不到会返回空
Console.WriteLine(hashtable[1]); Console.WriteLine(hashtable[4]);//null Console.WriteLine(hashtable["123123"]);
2.查看是否存在
根据键检测
if( hashtable.Contains(2) ) { Console.WriteLine("存在键为2的键值对"); } if( hashtable.ContainsKey(2) ) { Console.WriteLine("存在键为2的键值对"); }
根据值检测
if( hashtable.ContainsValue(12) ) { Console.WriteLine("存在值为12的键值对"); }
改
只能改 键对应的值内容 无法修改键
Console.WriteLine(hashtable[1]); hashtable[1] = 100.5f; Console.WriteLine(hashtable[1]);
知识点四 遍历
得到键值对 对数
Console.WriteLine(hashtable.Count);
1.遍历所有键
foreach (object item in hashtable.Keys) { Console.WriteLine("键:"+item); Console.WriteLine("值:"+hashtable[item]); }
2.遍历所有值
foreach (object item in hashtable.Values) { Console.WriteLine("值:" + item); }
3.键值对一起遍历
foreach (DictionaryEntry item in hashtable) { Console.WriteLine("键:" + item.Key + "值:" + item.Value); }
4.迭代器遍历法
IDictionaryEnumerator myEnumerator = hashtable.GetEnumerator(); bool flag = myEnumerator.MoveNext(); while (flag) { Console.WriteLine("键:" + myEnumerator.Key + "值:" + myEnumerator.Value); flag = myEnumerator.MoveNext(); }
知识点五 装箱拆箱
由于用万物之父来存储数据,自然存在装箱拆箱
当往其中进行值类型存储时就是在装箱
当将值类型对象取出来转换使用时,就存在拆箱
泛型
知识点一 泛型是什么
泛型实现了类型参数化,达到代码重用目的
通过类型参数化来实现同一份代码上操作多种类型泛型相当于类型占位符
定义类或方法时使用替代符代表变量类型
当真正使用类或者方法时再具体指定类型
知识点二 泛型分类
泛型类和泛型接口
基本语法:
class 类名<泛型占位字母> interface 接口名<泛型占位字母>
泛型函数
基本语法:函数名<泛型占位字母>(参数列表)
注意:泛型占位字母可以有多个,用逗号分开
知识点三 泛型类和接口
class TestClass<T> { public T value; } class TestClass2<T1,T2,K,M,LL,Key,Value> { public T1 value1; public T2 value2; public K value3; public M value4; public LL value5; public Key value6; public Value value7; } interface TestInterface<T> { T Value { get; set; } } class Test : TestInterface<int> { public int Value { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } }
知识点四 泛型方法
1.普通类中的泛型方法
class Test2 { public void TestFun<T>( T value) { Console.WriteLine(value); } public void TestFun<T>() { //用泛型类型 在里面做一些逻辑处理 T t = default(T); } public T TestFun<T>(string v) { return default(T); } public void TestFun<T,K,M>(T t, K k, M m) { } }
2.泛型类中的泛型方法class Test2<T> { public T value; public void TestFun<K>(K k) { Console.WriteLine(k); } //这个不叫泛型方法 因为 T是泛型类申明的时候 就指定 在使用这个函数的时候 //我们不能再去动态的变化了 public void TestFun(T t) { } }
知识点五 泛型的作用
1.不同类型对象的相同逻辑处理就可以选择泛型
2.使用泛型可以一定程度避免装箱拆箱
举例:优化ArrayListclass ArrayList<T> { private T[] array; public void Add(T value) { } public void Remove( T value) { } }
总结
1.申明泛型时 它只是一个类型的占位符
2.泛型真正起作用的时候 是在使用它的时候
3.泛型占位字母可以有n个用逗号分开
4.泛型占位字母一般是大写字母
5.不确定泛型类型时 获取默认值 可以使用default(占位字符)
6.看到<>包裹的字母 那肯定是泛型
class Program { static void Main(string[] args) { Console.WriteLine("泛型"); TestClass<int> t = new TestClass<int>(); t.value = 10; Console.WriteLine(t.value); TestClass<string> t2 = new TestClass<string>(); t2.value = "123123"; Console.WriteLine(t2.value); TestClass2<int, string, float, double, TestClass<int>, uint, short> t3 = new TestClass2<int, string, float, double, TestClass<int>, uint, short>(); Test2 tt = new Test2(); tt.TestFun<string>("123123"); Test2<int> tt2 = new Test2<int>(); tt2.TestFun(10); tt2.TestFun<string>("123"); tt2.TestFun<float>(1.2f); tt2.TestFun(20); } }
泛型约束
知识回顾
泛型类 class TestClass<T, U> { public T t; public U u; public U TestFun(T t) { return default(U); } 泛型函数 public V TestFun<K, V>(K k) { return default(V); } }
知识点一 什么是泛型约束
让泛型的类型有一定的限制
关键字:where
泛型约束一共有6种
1.值类型 where 泛型字母:struct
2.引用类型 where 泛型字母:class
3.存在无参公共构造函数 where 泛型字母:new()
4.某个类本身或者其派生类 where 泛型字母:类名
5.某个接口的派生类型 where 泛型字母:接口名
6.另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母where 泛型字母:(约束的类型)
知识点二 各泛型约束讲解
值类型约束 class Test1<T> where T:struct { public T value; public void TestFun<K>(K v) where K:struct { } } 引用类型约束 class Test2<T> where T:class { public T value; public void TestFun<K>(K k) where K:class { } } 公共无参构造约束 class Test3<T> where T:new() { public T value; public void TestFun<K>(K k) where K : new() { } } class Test1 { public Test1() { } } class Test2 { public Test2(int a) { } } 类约束 class Test4<T> where T : Test1 { public T value; public void TestFun<K>(K k) where K : Test1 { } } class Test3:Test1 { } 接口约束 interface IFly { } interface IMove:IFly { } class Test4:IFly { } class Test5<T> where T : IFly { public T value; public void TestFun<K>(K k) where K : IFly { } } 另一个泛型约束 class Test6<T,U> where T : U { public T value; public void TestFun<K,V>(K k) where K : V { } }
知识点三 约束的组合使用
class Test7<T> where T: class,new() { }
知识点四 多个泛型有约束
class Test8<T,K> where T:class,new() where K:struct { }
总结
泛型约束:让类型有一定限制
class
struct
new()
类名
接口名
另一个泛型字母注意:
1.可以组合使用
2.多个泛型约束 用where连接即可
class Program { static void Main(string[] args) { Console.WriteLine("泛型约束"); TestClass<string, int> t = new TestClass<string, int>(); t.t = "1`23123"; t.u = 10; t.TestFun("123"); t.TestFun<float, double>(1.4f); Test1<int> t1 = new Test1<int>(); t1.TestFun<float>(1.3f); Test2<Random> t2 = new Test2<Random>(); t2.value = new Random(); t2.TestFun<object>(new object()); Test3<Test1> t3 = new Test3<Test1>(); Test4<Test3> t4 = new Test4<Test3>(); Test5<IMove> t5 = new Test5<IMove>(); //t5.value = new Test4(); Test6<Test4, IFly> t6 = new Test6<Test4, IFly>(); } }