C#字符串
StringBuilder和String的区别
String在进行运算时(如赋值、拼接等)会产生一个新的实例,而StringBuilder则不会。
字符串的不可变性
- 当你给一个字符串重新赋值之后,老的值并没有销毁,而是重新开辟一块空间存储新值。
- 当程序结束后,GC扫描整个内存,如果发现有空间没有被指向,则立即把它销毁。
字符串是一个char类型的一个只读数组
- ToCharArray();将字符串转换为char数组。
- new string(char[] chs);能够将char数组转换为字符串。
字符串提供的各种方法
- Length,获得当前字符串中字符的个数。
- ToUpper(),将字符串转换成大写形式。
- ToLower(),将字符串转换成小写形式。
- Equal(str,Stringcomparison.OrdinalIgnoreCase),比较两个字符串的值是否相等,参数可忽略大小写。
- Split(),分割字符串,返回字符串类型的数组。
- Substring(),截取字符串,在截取的时候包含要截取的字符的位置。
- IndexOf(),判断某个字符串在字符串中第一次出现的位置,如果没有返回-1。
- LastIndexOf(),判断某个字符串在字符串中最后一次出现的位置,如果没有返回-1。
- StartsWith(),判断以…开始。
- EndsWith(),判断以…结束。
- Replace(),将字符串中某个字符串替换成一个新的字符串。
- Contains(),判断某个字符串是否包含指定的字符串。
- Trim(),去掉字符串中前后的空格。
- TrimEnd(),去掉字符串中结尾的空格。
- TrimStart(),去掉字符串中前面的空格。
- string.IsNullOrEmpty(),判断一个字符串是否为空或者为null。
- string.Join(),将数组按照指定的字符串连接,返回一个字符串。
继承
我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员,单独封装到一个类中,作为这些类的父类。如Student、Teacher、Driver称为子类或派生类,Person称为父类或基类。
继承的特性
- 继承的单根性:一个子类只能有一个父类,即单继承。
- 继承的传递性:如Student继承自Person,Programmer继承自Student,Driver继承自Programmer,则最后的类Driver既可以访问Programmer类中的属性和方法,也可以访问Person类中的属性和方法。
查看类图
VS2017中,需要安装VS扩展开发,并勾上类设计器后,在项目-右键-查看类图。
问题:子类有没有继承父类的构造函数?
答:子类并没有继承父类的构造函数。但是,子类会默认调用父类无参数的构造函数。在子类的内部创建父类的对象,让子类可以使用父类中的成员。
如果在父类中重写了一个有参数的构造函数之后,那个默认的无参数构造函数就被覆盖掉了,子类调用不到,因此会报错。
解决办法:
- 在父类中重新写一个无参数的构造函数。
- 在子类中显式调用父类的有参数的构造函数,使用关键字:base()
如:
public Student(string name, string age, string gender, string id) : base(name, age, gender)
{
this.id = id;
}
new关键字
创建对象。
隐藏从父类那里继承过来的同名成员。
隐藏的后果就是子类调用不到父类的成员。
里氏转换法
里氏转换
子类可以赋值给父类:如果有一个地方需要一个父类作为参数,我们可以给一个子类代替。
如:
Student s = new Student();
Person p = s;或者
string str = string.Join("|", new string[] { "1", "2", "3", "4"});
Join方法第二个参数为object,可以用一个子类代替,string为object的一个子类。
如果父类中装的是子类对象,那么可以将这个父类强转为子类对象。
如:
Person p = new Student();
Student ss = (Student)p;
注意:子类对象可以调用父类中的成员,但是父类对象永远都只能调用自己的成员。
as和is关键字
is表示类型转换,如果能够转换成功,则返回一个true,否则返回一个false。
as表示类型转换,如果能够转换则返回对应对象,否则返回一个null。
is的用法:
if (p is Student) |
as的用法:
Student t = p as Studnet; |
Protected
受保护的:可以在当前类的内部以及该类的子类中访问。
多态
概念
让一个对象能够表现出多种的状态(类型)。
多态的好处
- 减少冗余的代码
- 增加程序的可扩展性
- 取消各个对象的差异性
实现多态的三种方法
虚方法
将父类的方法标记为虚方法,使用关键字virtual,这个方法可以被子类用关键字override重新写一遍。
解释:emps[i].DaKa()调用的依然是父类的方法,只是该方法被子类重写了,调用的时候不再执行父类的方法,而是执行子类重写的方法,调用哪个子类的重写方法取决于对象里面装的是哪个子类。
//员工类 |
Main方法
//经理11点打卡,员工9点打卡,程序猿不打卡 |
抽象类
当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法。
抽象类的特点:
- 抽象类和接口不允许创建对象。
- 抽象成员必须标记为abstract,并且不能有任何实现。
- 抽象类中可以有非抽象成员,并且非抽象成员在子类中不需要被重写。
- 抽象类成员必须在抽象类中。
- 子类继承抽象类后,必须把父类中的所有抽象成员都重写。(除非子类也是一个抽象类,则可以不重写)
- 抽象类是有构造函数的,虽然不能被实例化。
- 如果父类的抽象方法中有参数,那么继承这个抽象父类的子类在重写父类的方法的时候,必须传入对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候,也必须要有相同的返回值。
注意:方法的签名就是方法的返回值还有参数。
//抽象类 |
Main方法
Animal a = new Dog(); |
虚方法抽象类总结
- 如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑把父类定义成一个普通类,用虚方法来实现多态。
- 如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类。
- 在抽象类中写一个虚方法,是有意义的。(如果类中需要抽象成员,就写抽象类。如果不需要抽象成员,则不写抽象类)