1.复习
里氏转换:
1)、子类可以赋值给父类(如果有一个方法需要一个父类作为参数,我们可以传第一个子类对象)
2)、如果父类中装的是子类对象,则可以将这个父类强转为子类对象

is和as判断转换成功失败

C#基础笔记(第十二天) 数据库 第1张
 1 Person p = new Student();
 2 //if(p is Student)
 3 //{
 4 // ((Student)p).StudentSayHello();
 5 //}
 6 //else
 7 //{
 8 // Console.WriteLine("转换失败");
 9 //}
10 Student ss = p as Student;
11 ss.StudentSayHello();
12 Console.ReadKey();
View Code

在键值对中,键必须是唯一的
查看键值对集合中的数据用foreach循环查看,根据键来推断值

Path可以获得文件名,目录,路径等
Path和File都是静态类

ReadAllBytes() 读数据 Encoding.Default.GetString(字节数组)
byte[] buffer = File.ReadAllBytes(@"C:\Users\SJD\Desktop\123.txt");
//将字节数组中的每一个元素都要按照我们指定的编码格式解码成字符串
//UTF-8 GB2312 GBK ASKII Unicode
//UTF8,UTF7,UTF32共同组成的编码格式叫Unicode
//GB2312简体中文,GBK既有简体也有繁体
//Encoding.Default Default解析存的是什么格式就用什么格式
string s = Encoding.GetEncoding("GB2312").GetString(buffer);
Console.WriteLine(s);
Console.ReadKey();

WriteAllBytes() 写数据 Encoding.Default.GetBytes(字符串)
string str = "好好学习天天向上";
byte[]buffer= Encoding.Default.GetBytes(str);
File.WriteAllBytes(@"C:\Users\SJD\Desktop\new.txt", buffer);
Console.WriteLine("写入成功");
Console.ReadKey();

ReadAllLines()读数据 以行的形式读取,返回一个string类型的数组
string []contents=File.ReadAllLines(@"C:\Users\SJD\Desktop\123.txt",Encoding.Default);
foreach (string item in contents)
{
Console.WriteLine(item);
}
Console.ReadKey();

ReadAllText()读数据 以TEXT的形式读取,返回一个string 类型的字符串
string str=File.ReadAllText(@"C:\Users\SJD\Desktop\123.txt",Encoding.Default);
Console.WriteLine(str);
Console.ReadKey();

WriteAllLines()写数据 以string类型的数组覆盖写入
File.WriteAllLines(@"C:\Users\SJD\Desktop\new.txt", new string[] { "张三", "李四", "王二麻子" });
Console.WriteLine("写入成功");
Console.ReadKey();

WriteAllText()写数据 以string类型的字符串覆盖写入
File.WriteAllText(@"C:\Users\SJD\Desktop\new.txt", "张三李四王二麻子");
Console.WriteLine("写入成功");
Console.ReadKey();

AppendAllLines(),AppendAllText(),AppendText() 都是追加写入,不覆盖。

File类最大的缺陷是只能用来读小文件。
因为它读取的方式是一下子全部读进来,很浪费内存。
读取大文件需要用文件流
读文本的时候用ReadAllText()和ReadAllLines(),读多媒体等文件时用ReadAllBytes()
返回数组可以精确的操作每一行的数据。返回字符串只能返回 一个整体回来。

2.绝对路径和相对路径
绝对路径:通过给定的这个路径直接能在我的电脑中找到这个文件。
相对路径:文件相对于应用程序的路径。 放在执行文件的同一目录下里,运行时不用指定路径

写代码的时候最好都使用相对路径,因为绝对路径只能在我自己的电脑可以用。相对路径在任何电脑都可以用。
开发中应该尽量使用相对路径。

3.List泛型集合
ArrayList的好处:1)、集合的长度可以任意改变
2)、添加数据的数据类型没有要求,任意的
数据 声明什么类型,里面就要放什么类型
//创建泛型集合
List<int> list=new list<int>(); 不需要再手动引用命名空间
List泛型集合有ArrayList的好处,集合长度可以任意改变。读取时不需要再强转。
//List泛型集合可以转换为数组
List集合转换为数组
int []nums= List.ToArray();
//创建一个string类型的泛型集合
List<string> listStr = new List<string>();
//把string类型的泛型集合转换为string类型的数组
string []list= listStr.ToArray();
//把string类型的数组转换为string类型的泛型集合
List<string>listStrTwo= list.ToList<string>();

ArrayList集合和HashTable已经很少有人在用了。取的时候不方便。

4、装箱、拆箱
装箱:就是将值类型转换为引用类型。
拆箱:将引用类型转换为值类型。
int n=10;
object o=n;//装箱
int nn=(int)o;//拆箱
装箱会比普通的要慢(差了10倍),代码中要尽量避免装箱和拆箱
//这个地方没有发生任意类型的装箱或者拆箱
string str="123";
int n=convert.toint32(str);

看两种类型是否发生了装箱或者拆箱,要看这两种类型是否存在继承关系。
如果有继承关系,才有可能发生装箱或拆箱,如果没有继承关系,它们一定不会发生装箱或拆箱。
例:
int n=10;
IComparable i=n;//装箱 IComparable 也是引用类型,并有继承关系

5、Dictionary
基本上和BashTable是相同的
可以使用键值对来读取
例:
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "张三");
dic.Add(2, "李四");
dic.Add(3, "王二麻子");
dic[1] = "新来的";
foreach (KeyValuePair<int,string> kv in dic)
{
Console.WriteLine("{0}------{1}",kv.Key,kv.Value);
}

6、FileStream 文件流
和File的区别,读取文件的差距
两个缸子,A空缸,B装满水。要把B的水装到A里去
File的用法就是把B抬起来直接把水倒到A里面去。但是会对使用的人产生很大的压力,瘦小的人抗不起这水
FileStream的用法就是用水舀子把B的水一勺一勺舀到A去。每次都舀一勺

File读文件是一下子全部读过来
FileStream是一点一点的读(对内存基本上没什么压力)

//FileStream 操作字节的,可以操作任何类型的文件.
//StreamReader和StreamWriter 操作字符的,只能操作文本文件。
这两种相对于File来说的好处就是他们可以操作大文件,压力小。
小文件的话用File类就OK了。几百K的

*****学习.net就是学习它这些类怎么使用的。会的越多,越是大牛。
FileStream fsRead = new FileStream(@"C:\Users\SJD\Desktop\123.txt",FileMode.OpenOrCreate,FileAccess.Read);
//FileStream fsRead=new FileStream(1.你要操作的文件的路径,2.你要对文件进行一个什么操作,3.你要针对这个文件里面的数据做一个什么操作。);
枚举 枚举
打开后读取
byte[] buffer = new byte[1024 * 1024 * 5];//限定字节数组只能放5M
//fsRead.Read(1.限定字节,2.表示从哪个地方开始写入数据,3.最多读取的字节数);
int r=fsRead.Read(buffer, 0, buffer.Length);
//返回的Int类型
//只有3.8M,但我每次读取5M 返回的r就是本次次读取实际有效的字节数
//数据都在字节数组里面,看不懂这个东西,所以要把字节数组中每一个元素按我指定的编码格式解码成字符串
//将字节数组中每一个元素按照指定的编码格式解码成字符串
string s= Encoding.Default.GetString(buffer);
//用完了还要关闭流
fsRead.Close();
//释放流所占用的资源
fsRead.Dispose();
GC没办法回收文件流
Console.WriteLine(s);
Console.ReadKey();
//有效字节少,大部分打印出来都是空
//超过字节数的就不解码了。
string s= Encoding.Default.GetString(buffer,0,r);//从0开始解码,解码r个。
//这样解码出来的是r有效字节数,但实际上读的还是5M

//如果大数据,超过了5M,就要循环去读。

//使用FileStream来写入数据

7.将创建文件流对象的过程写在using当中,会自动的帮助我们释放流所占用的资源。
微软提供的语法,可以不用写fsRead.Close();和fsRead.Dispose();
using()
{

}
创建对象的过程写在()里,读取和写入写在{ }里面
using (FileStream fsWrite=new FileStream(@"C:\Users\SJD\Desktop\new.txt",FileMode.OpenOrCreate,FileAccess.Write))
{
string str = "看我有没有把你覆盖掉";
byte[] buffer = Encoding.Default.GetBytes(str);
fsWrite.Write(buffer, 0, buffer.Length);
}
Console.WriteLine("写入OK");
Console.ReadKey();

写和读用UTF8就不会出现乱码
Encoding.UTF8.GetBytes(str);

8.FileStream的多媒体拷贝
static void Main(string[] args)
{
//思路:就是先将要复制的多媒体文件读取出来,然后再写入到你指定的位置。
string source = @"C:\Users\SJD\Desktop\see.mp4";
string target = @"C:\Users\SJD\Desktop\new.mp4";
CopyFile(source, target);
Console.WriteLine("复制OK");
Console.ReadKey();
}

public static void CopyFile(string source, string target)
{
//1、我们创建一个负责读取的流
using (FileStream fsRead = new FileStream(source, FileMode.Open, FileAccess.Read))
{
//创建一个负责写入的流
using (FileStream fsWrite = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] buffer = new byte[1024 * 1024 * 5];
//因为文件可能会比较大,所以我们在读取的时候应该通过一个循环去读取
while (true)
{
//返回本次读取实际读取到的字节数
int r = fsRead.Read(buffer, 0, buffer.Length);
//如果返回一个0,也就意味什么都没有读取到,读取完了
if(r==0)
{
break;
}
fsWrite.Write(buffer, 0, r);
}
}
}
}

9.StreamReader和StreamWriter
FileStream是操作字节的(必须掌握)
StreamReader和StreamWriter是操作字符
//使用StreamWriter来写入一个文本文件 true是追加写入,不覆盖写入
using (StreamWriter sw = new StreamWriter(@"C:\Users\SJD\Desktop\new.txt",true))
{
sw.Write("看我有没有把你覆盖掉");
}
Console.WriteLine("写入OK");
Console.ReadKey();

10.多态
//概念:让一个对象能够表现出多种的状态(类型)
例:
Chinese cn1 = new Chinese("韩梅梅");
Chinese cn2 = new Chinese("李雷");
Japanese j1 = new Japanese("树下君");
Japanese j2 = new Japanese("井边子");
Korea k1 = new Korea("金秀贤");
Korea k2 = new Korea("金贤秀");
American a1 = new American("科比布莱恩特");
American a2 = new American("奥尼尔");
Person[] pers = { cn1, cn2, j1, j2, k1, k2, a1, a2 };
for (int i = 0; i < pers.Length; i++)
{
if(pers[i] is Chinese)
{
((Chinese)pers[i]).SayHello();
}
else if(pers[i]is Japanese)
{
((Japanese)pers[i]).SayHello();
}
else if(pers[i] is Korea)
{
((Korea)pers[i]).SayHello();
}
else
{
((American)pers[i]).SayHello();
}
}
Console.ReadKey();

pers[i].SayHello() 只是为了读取各个子类下对应的方法

//实现多态的3种手段:1、虚方法 2、抽象类 3、接口

11.实现多态的手段
1)、虚方法
步骤:
1、将父类的方法标记为虚方法,使用关键字 virtual,这个函数可以被子类重新写一遍
在父类方法返回之前加一个virtual
这样就将父类函数标记为虚方法
在子类同名的方法前面加一个override 重写

调用的依然是父类的对象,只是这个方法被重新了,所以调用的是子类的方法。
装的是谁的对象,就调用谁的方法
让一个对象可以表现多种类型出来,写出通用的代码。最大效益的取消他们的一个差异性
多态的好处就是减少了很多代码,增强了可发展性。

使用虚方法 首先要给一个父类 用关键字virtual
给子类 用关键字override

2)、抽象类
当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法
用abstract来标记父类 和方法
例:
public abstract class animal
{
public abstract void call();

}
意义:让子类重写
抽象方法必须没有方法体,用abstract标记
因为根本不知道怎么实现这个方法,干脆就不实现。抽象类是没有方法体的
public void Test()
{
//空实现 有方法体
}

抽象类无法创建对象,接口也是不允许创建对象的

1.抽象成员必须标记为abstract,并且不能有任何实现。
2.抽象成员必须在抽象类中。
3.抽象类不能被实例化
4.子类继承抽象类后,必须把父类中的所有抽象成员都重写。
(除非子类也是一个抽象类,则可以不重写)
5.抽象成员的访问修饰符不能是private
6.在抽象类中可以包含实例成员
而且抽象类的实例成员可以不被子类实现
7.抽象类是有构造函数的,虽然不能被实例化。
8.如果父类的抽象方法中有参数,那么。继承这个抽象父类的子类在重写父类的方法的时候必须传入对应的参数
如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候 也必须要传入返回值

=============
如果父类中的方法由默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法实现多态。
如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类。

在父类中
public abstract void Bark(); 抽象类

public abstract string Name 抽象属性
{
get;
set;
}

测试会发现报错,没有继承。
要继承要去找到子类,光标放在继承后面 shift+alt+f10(实现抽象类) 子类的方法的属性就会重写了。

一个子类如果继承了一个抽象的父类,这个子类必须实现这个抽象父类中所有的抽象成员
抽象类可以写非抽象成员
父类自己不能创建对象,但是子类继承里面可以用。
所以父类可以有抽象成员也可以有非抽象成员
不能在一个非抽象类中写一个抽象成员

返回值和参数就是方法里的签名

//使用多态求矩形的面积和周长以及圆形的面积和周长
//Shap shape = new Circle(5);
Shap shape = new Square(5, 6);
double area = shape.GetArea();
double perimeter = shape.GetPerimeter();
Console.WriteLine("这个形状的面积是{0},周长是{1}",area,perimeter);
Console.ReadKey();

12.小结
list<T>
Dictionary<Tkey,Tvalue>
比ArrayList的好处就是不会发生拆装箱

FileStream 操作字节
SteamReader和StreamWriter 操作字符的
可以操作大文件

Flie 只能操作小文件

拆装箱
装箱是值类型到引用类型
拆箱是引用类型到值类型
装箱拆箱都会影响到系统的性能,运行需要时间。尽量避免拆装箱

多态
虚方法 父类有实现,父类需要创建对象用虚方法
抽象类 父类没有实现,父类不需要创建对象用抽象类
抽象类需要掌握一坨特点
接口