1、属性
属性的作用就是保护字段,对字段的赋值和取值进行限定
属性的本质就是两个方法,get()和set()方法
2、值类型和引用类型
区别:
1)值类型和引用类型在内存上储存的地方不一样
值类型的值就是存储在栈中啊
引用类型是将存放本身的值存放在堆中,将存放本身的值的地址存放在栈中,根据这个地址可以去找到自己
2)传递的方式不同(值传递<所以ref表示将值传递转换成引用传递>,引用传递)
值类型:int,double,bool,char,decimal,struct,enum
引用类型:string,自定义类,数组
3、字符串的特点
1)字符串的不可变性
当为一个字符串重新赋值后,老值并没有销毁(等待gc处理),而是重新开辟了一块内存空间
string a = "abc";
string b = "abc"; // 变量a和b指向同一块堆内存
2)可以将字符串看做是char型**只读**数组
static void Main(string[] args)
{
string ss = "你好";
Console.WriteLine(ss[0]); // 你
// ss[0] = '我'; // 报错,因为是char型只读数组
// 修改的方法
char[] charArray = ss.ToCharArray(); // 字符串 => char数组
charArray[0] = '我';
ss = new string(charArray); // char数组 => 字符串
Console.WriteLine(ss); // 我好
Console.ReadLine();
}
4、StringBuilder
时间测试——String
static void Main(string[] args)
{
// 使用String的时间:00:00:00.1375408
String s = null;
Stopwatch sw = new Stopwatch(); // 创建计时器
sw.Start(); // 开始计时
for (int i = 0; i < 10000; i++)
{
s += i;
}
sw.Stop(); // 结束计时
Console.WriteLine(s);
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
时间测试——StringBuilder
static void Main(string[] args)
{
// 使用StringBuilder的时间:00:00:00.0032886
StringBuilder sb = new StringBuilder();
Stopwatch sw = new Stopwatch(); // 创建计时器
sw.Start(); // 开始计时
for (int i = 0; i < 10000; i++)
{
sb.Append(i);
}
sw.Stop(); // 结束计时
Console.WriteLine(sb.toString()); // 调用toString()方法转成字符串
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
结论:StringBuilder比String快
原因:String修改字符串是在不断新建一块内存空间
5、字符串的方法们
"xxx".Length // 获取字符串的长度
"xxx".ToUpper() // 将字符串变大写
"XXX".ToLower() // 将字符串变小写
"xxx".Equals("XXX", StringComparison.OrdinalIgnoreCase) // 比较两个字符串是否相同,StringComparison.OrdinalIgnoreCase为忽略大小写
// 切割字符串
static void Main(string[] args)
{
string s = "a bsjcjislc sfcnvkj _+= dvsnlk,";
char[] ch = {' ', '_', '+', '=', ','};
string[] strings = s.Split(ch, StringSplitOptions.RemoveEmptyEntries); // 里面的表示去除空格
foreach (string s2 in strings)
{
Console.WriteLine(s2);
}
Console.ReadLine();
}
"xxx".Contains("xx"); // 判断字符串中是否包含xx
"xxx".Replace("xx", "yy"); // 将xx替换为yy
"xxx".StartsWith("xx");
"xxx".EndsWith("xx");
"abc".Substring(1, 2) // 输出bc
"abcbf".IndexOf("b") // 寻找字符串第一次出现的位置,找不到输出-1
"abcbf".IndexOf("b",2) // 寻找字符串第一次出现的位置,从索引为2的位置开始找
"abcbf".LastIndexOf("b") // 寻找字符串最后一次出现的位置,找不到输出-1
"abcbf ".Trim() // 清除前后的空字符
"abcbf ".TrimStart() // 清除前面的空字符
"abcbf ".TrimEnd() // 清除前后的空字符
string.IsNullOrEmpty("xxx"); // 判断字符串是否为空(""/null)
// 字符串拼接
string[] names = {"a", "b", "c"};
string s = string.Join("|",names);
Console.WriteLine(s); // a|b|c
6、C#中的继承使用:代替extend
1)虽然被private修饰的不能被继承,但可以继承他的属性(get,set方法),子类一样可以操作私有的字段
2)如果子类中没有构造方法,默认调用的是父类的空参构造。如果没有空参构造,需要使用以下方式调用父类的有参构造:
public class Student:Person
{
public Student(string name, int age, char gender) : base(name, age, gender)
{
}
}
3)如果子类要重写父类的方法,要在子类中添加new关键字 public new void sayHello(){}
7、里式转换
1)子类可以赋值给父类
Person p = new Student(); // 要父类给子类
2)如果父类中装的是子类对象,可以强转为子类
Student s = (Student) p;
if (s is Student){ // 判断s是否是Student的对象
Student s = (Student) p;
}
Student s = p as Student // 如果s是Student的对象则返回student对象,否则返回Null
8、在C#中toString()方法默认打印的是对象所在的类的命名空间
9、ArrayList
添加元素的方法
// add系
ArrayList arrayList = new ArrayList();
arrayList.Add("abc123");
arrayList.AddRange(new string[]{"a","b","c"}); // 可以是数组
arrayList.AddRange(arrayList); // 也可以是集合
// insert系
arrayList.Insert(2,"123"); // 在指定的位置插入一个元素
arrayList.InsertRange(3,new String[]{"1","2"}); // 在指定的位置插入一个集合/数组
删除元素
arrayList.Remove("abc123"); // 删除单个元素,写谁就删谁
arrayList.RemoveAt(0); // 根据索引删除单个元素
arrayList.RemoveRange(1,5); // 根据索引删除一定范围的元素
arrayList.Clear(); // 清空集合
其它
arrayList.Sort(); // 排序
arrayList.Reverse(); //反转
bool contains = arrayList.Contains("123abc"); // 判断是否包含指定元素
Console.WriteLine(arrayList.Count); // 实际包含的元素个数
Console.WriteLine(arrayList.Capacity); // 可以包含的元素个数
注:每次集合中实际包含的元素(count)超过了可以包含的元素个数(Capacity)的时候,集合就会向内存中多申请开辟一倍的空间,来保证集合一直够用。
10、hashtable
两种添加元素的方法
ht.Add(true,"xxx");
ht["xjkcnakm"] = 123;
遍历方法
foreach (var k in ht.Keys)
{
Console.WriteLine("键:"+k+"值:"+ht[k]);
}
判断是否包含这个key
bool containsKey = ht.ContainsKey("abc123");
11、Path类
String path = @"E:\Documents\Desktop\TIM截图20180509165713.png";
Console.WriteLine(Path.GetFileName(path)); // 获取文件名
Console.WriteLine(Path.GetFileNameWithoutExtension(path)); // 获取文件名,不包括扩展名
Console.WriteLine(Path.GetExtension(path)); // 获取文件扩展名
Console.WriteLine(Path.GetDirectoryName(path)); // 获取文件所在文件夹的路径
Console.WriteLine(Path.GetFullPath(path)); // 获取文件的全路径
Console.WriteLine(Path.Combine(@"c:\a\","b.txt")); // 将两个字符串拼接成路径
12、File类(只能读取小文件,因为它读取文件的方法是一下全读进来)
File.Delete(path); // 删除一个文件
File.Create(path); // 创建一个文件
// 复制一个文件
File.Copy(@"E:\Documents\Desktop\1.txt", @"E:\Documents\Desktop\2.txt");
读取文件内容(字节形式)
String path = @"E:\Documents\Desktop\1.txt";
// 获取文件的字节数组
byte[] bytes = File.ReadAllBytes(path);
// 根据指定编码格式转换成字符串
string s = Encoding.GetEncoding("UTF-8").GetString(bytes);
// 打印文件内容
Console.WriteLine(s);
写入文件(字节形式)
// 1.将字符串转成字节数组
byte[] bytes = Encoding.GetEncoding("UTF-8").GetBytes("你好,世界!");
//byte[] bytes = Encoding.Default.GetBytes("你好,世界!"); // windows默认编码格式为GBK
// 2.写入文件
File.WriteAllBytes(path,bytes);
以行的形式读取文件
String path = @"E:\Documents\Desktop\1.txt";
// 1.读取文件中的每行数据,返回一个string数组
string[] strings = File.ReadAllLines(path);
// 2.遍历数组,输出
foreach (string item in strings)
{
Console.WriteLine(item);
}
以行的形式写入文件
File.WriteAllLines(path,new string[]{"abc","abc","abc","abc","abc","abc","abc","abc","abc","abc","abc","abc"});
13、操作文件(可以操作大文件,因为他是一点一点读的)
FileStream 操作字节的
1)读取文件
String path = @"E:\BaiduNetdiskDownload\C#\第12天-面向对象多态\9、StreamReader和StreamWriter.avi";
// 1.创建文件输入流
FileStream stream = new FileStream(path,FileMode.Open,FileAccess.Read);
// 2.建立一个字节数组,用来一点一点取数据
byte[] bytes = new byte[1024*1024*5];
// 3.读取5M的数据,返回值为本次读取文件的字节大小
int r = stream.Read(bytes,0,bytes.Length);
// 4.字节转为字符串
string s = Encoding.GetEncoding("utf-8").GetString(bytes,0,r);
Console.WriteLine(s); // 输出
// 5.关闭流
stream.Close();
// 6.释放资源
stream.Dispose();
由于每次都要关闭流,释放资源很麻烦,于是有了using代码块
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
// 2.建立一个字节数组,用来一点一点取数据
byte[] bytes = new byte[1024 * 1024 * 5];
// 3.读取5M的数据,返回值为本次读取文件的字节大小
int r = stream.Read(bytes, 0, bytes.Length);
// 4.字节转为字符串
string s = Encoding.UTF8.GetString(bytes, 0, r);
Console.WriteLine(s); // 输出
}
2)写入文件
using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
{
string str = "你好!";
byte[] bytes = Encoding.UTF8.GetBytes(str);
stream.Write(bytes,0, bytes.Length);
}
StreamReader和StreamWriter 操作字符的
1)StreamReader
string path = @"E:\Documents\Desktop\1.txt";
using (StreamReader sr = new StreamReader(path,Encoding.UTF8))
{
while (!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
}
2)StreamWriter
using (StreamWriter sw = new StreamWriter(path,true)) // true表示追加形式写入
{
sw.Write("xxx");
}
14、泛型集合 List<>
string[] strings = {"a", "b", "c", "d"};
// 数组 => 集合(List<>)
List<string> list = strings.ToList();
// 集合 => 数组
string[] array = list.ToArray();
15、装箱和拆箱
装箱:将值类型转换成引用类型
拆箱:将引用类型转换成值类型
注:看是否发生了装箱和拆箱,要看两者之间是否存在继承关系
16、字典
Dictionary<int, string> dic = new Dictionary<int, string>();
17、C#中5个访问修饰符
public:公开的
protected:受保护的,只能在当前类内部以及该类的子类中访问
private:私有的,只能在当前类内部访问
internal:只能在当前项目中访问
protected internal:protected+internal
17、类访问修饰符特点
1)可以修饰类的修饰符只有两个:public,internal
internal(不写类的修饰符时默认是它):修饰类,表示该类只能在当前项目中访问
2)子类的可访问权限不能高于父类的可访问权限
internal class Person{}
public class Student:Person{} // 这是错误的 应该把public==>internal
18、序列化与反序列化
序列化:将对象转换成二进制
// 1.标志这个类是可以被序列化的
[Serializable]
public class Program
{
static void Main(string[] args)
{
// 2.使用FileStream将对象的二进制写入文件
using (FileStream fs = new FileStream(@"E:\Documents\Desktop\1.txt", FileMode.OpenOrCreate, FileAccess.Write))
{
// 3.实例化序列化对象
BinaryFormatter bf = new BinaryFormatter();
// 4.实例化要写入文件的对象
List<string> list = new List<String>();
// 5.调用序列化方法
bf.Serialize(fs,list);
}
}
}
反序列化:将二进制转换成对象
// 1.标志这个类是可以被序列化的
[Serializable]
public class Program
{
static void Main(string[] args)
{
// 2.使用FileStream将对象的二进制写入文件
using (FileStream fs = new FileStream(@"E:\Documents\Desktop\1.txt", FileMode.Open, FileAccess.Read))
{
// 3.实例化序列化对象
BinaryFormatter bf = new BinaryFormatter();
// 4.反序列化
List<string> deserialize = (List<string>) bf.Deserialize(fs);
}
}
}
19、部分类
就是在同一个命名空间中可以有多个同名的类(实际上就是一个类,不知道设计出来有吊用)
public **partial** class Person{
...
}
public partial class Person{
...
}
public partial class Person{
...
}
20、密封类
特征:不能被继承,可以继承别人
public sealed class Person:xxx类{
...
}
21、接口
interface声明接口,和继承一样使用:实现接口,使用:实现接口的(多)继承
接口中可以有方法,属性(没有方法体),索引器
1)显示实现接口
void 接口名.要实现的方法(){...} // 不能用public修饰。
默认表示不写修饰符时:
注:C#中类的修饰符默认是internal,类中方法默认修饰符为private,接口中方法默认修饰符为public abstract
java中 类中方法默认修饰符为default(比private限制更少,但比protected限制更多),接口中方法默认修饰符为public abstract
2)隐式实现
public void 要实现的方法(){...}
没有任何区别
22、自动属性与普通属性
1)普通属性
private string _name;
public string Name{
get {return _name};
set {_name = value};
}
2)自动属性
public string Name{
get;
set;
}
没有任何区别,自动属性省代码
23、Directory类
// 在c盘下创建a文件夹
Directory.CreateDirectory(@"C:\a");
// 删除文件夹
Directory.Delete(@"C:\a");
Directory.Delete(@"C:\a",true); // 如果文件夹不为空,则不能删除,此时要加上true字段
// 移动文件夹
Directory.Move(@"C:\a", @"C:\KuGou\a");
// 获取文件夹下的所有图片的全路径(不包括文件夹)。指定文件后缀
string[] strings = Directory.GetFiles(@"F:\快盘\宝岩\没有这幅画、\Lovers","*.jpg");
foreach (var img in strings)
{
Console.WriteLine(img);
}
// 获取目录下的文件夹
string[] directories = Directory.GetDirectories(@"F:\快盘\宝岩\没有这幅画、\Lovers");
foreach (var directory in directories)
{
Console.WriteLine(directory);
}
// 判断路径是否存在
bool exists = Directory.Exists(@"F:\快盘\宝岩\没有这幅画、\Lovers");
Console.ReadKey();
88、索引器
89、静态类
静态类中资源共享