面向对象三大特征:
封装 继承 多态
封装:方便多次调用;简化用户操作
为什么要使用继承:
1.相同代码出现两次:冗余代码!!!
2.设计类的时候会发现,很多类中具有相同的成员,为了减少代码的冗余,我们将这些相同的成员提取出来,单独的封装成了一个类,作为其他类的父类,或者叫基类.其他类这叫做这个类的子类,或者派生类.
继承的缺点: 打破类的封装性!
C#中所有的类都直接(无冒号:)或者间接(有冒号:)的继承于 Object类.
一个子类继承了一个父类,那么子类继承了父类的如下成员(能.出来的):
1.属性
2.函数(不含构造函数)
字段(private)虽然"继承"了,但是.不出来,因为它是父类这个类的,而不是父类某个对象的.
难点: 子类是否继承了父类的构造函数!!!!!
1.子类并没有继承父类的构造函数,因为在创建子类对象的时候,调用不到父类的构造函数.
2.但是,在创建子类对象的时候,会先执行父类的构造函数,也就是说,子类并没有继承父类的构造函数,但是会先调用父那个无参数的构造函数.因为父类有可能在自己默认的无参数的构造函数中对成员进行初始化,如果子类想要得到父类初始化后的成员,子类就要去调用父类默认的无参数的构造函数.
3.子类用有参数的构造函数创建对象的时候,也会先去调用父类默认的无参数的构造函数.
当我们在父类中重新写了一个有参数的构造函数后,默认的无参数的构造函数就不存在了.
解决方法:1.在父类中重新写一个无参数的构造函数;---这个方法基本不用.
2.在子类中显示的调用父类有参数的构造函数,使用关键字 :base
父类:public Person(string name,int age,char gender){...;}
子类:public Student(string name int age,char gender,int id):base(name,age,gender)
{ ... ;this Id = id;}
如果不写 :base(name,age,gender),子类用有参数的构造函数创建对象的时候,依然会先调用父类无参数的构造函数,如果父类没有显示的写出无参数的构造函数,会报错!
如果父类没有无参数的构造函数,子类也不能有,会报错!
this:代表当前类的对象,可以显示的调用本类的构造函数;
base:一个指向父类的引用,通过base可以调用父类的成员,不代表父类的对象.
new:1.隐藏父类的成员
2.创建对象
静态成员的好处:资源共享;
坏处:占内存,能不写尽量不写.
方法表 :类的方法的存放空间,里面有一块区域叫 静态存储区域,专门存放 类的 所有静态成员
继承的特性:
1.单根性:只有一个爹,干爹都不算(类是亲爹,object 接头都是干爹)
2.传递性:继承的成员可以一层一层往下传递.
访问修饰符(访问的权限):
1.private 私有的,只能在当前类的内部访问
2.public 公开的,在哪都可以访问
3.internal 只能在当前项目的内部访问,出了这个项目就访问不到了(项目可以理解为命名空间),类默认就是internal
4.protected 只能在当前类的内部,以及该类的子类中访问
5.protected internal
父类的访问权限不能比子类的访问权限低:
因为如果父类低于子类的话,父类的成员会暴露,别的项目可以通过子类访问父类的成员.
类 : internal < public 默认 internal
成员: 当前项目中 internal 的权限比protected大
但是跨项目,protected 比 internal 大,因为跨项目后,可以通过继承该类,然后访问 protected 修饰的成员.(不理解!!!)
跨项目访问:
1.添加要访问的项目的引用:
2.导入要使用的类所在的命名空间; using ***;
里氏替换原则:
1.子类可以复制给父类
2.如果父类中装的是子类对象,那么可以将这个父类转换为"对应"的子类对象,这样就可以调用子类的成员了.
Person p = new Person();
p. 这里是无法调用子类的成员;
Person p = new Student();
p. 这里也无法调用子类的成员;
Person p = new Student();
((Student)p). 这里就可以调用子类的成员;
我们使用两个关键字帮助我们实现类型转换:is as
is:判断是否能转换,返回值是 bool 类型,但是实际并没有转换
Person p = new Student();
if (p is Student){...}
as:进行类型转换,如果成功,返回对应的对象,如果失败则返回null
Person p = new Student();
Student s = p as Student;//
额外: string ss = string.Join("||", "213", true, 342,‘男‘); //结果为: 213||true||342||男
for+TAB(快捷方式)
开放封闭原则: 对程序的扩展开放,对代码的修改保持封闭
集合:
1.非泛型集合 : 长度不固定,类型不固定(对应数组:长度固定,类型固定)
ArrayList list = new ArrayList();
//list.Add(Object value)
list.Add("123");
list.Add(3123);
list.Add(true);
list.Add(new Person());
//list.Add(new int[] { 1,23,4,3,5,6,6,5}); 这样写,显示不出来具体的数字,需要用 is或者 as 强制转换
list.AddRange(new int[] { 1,2,3,4,5,6});
//list.Add(list);这样写,显示不出来具体的数字;
list.AddRange(list);
===>给集合添加单个元素用Add,添加数组和集合用AddRange
list.Clear():清空所有的数据
list.Remove(Object obj):写谁删谁(如果有重复的,删第一个)(和 for一起用的时候,容易出错喔!!删了下标就变了喔!)
list.RemoveAt(int index):下标是谁就删谁,没有这个下标就抛异常
list.RemoveRange(0, 2);从下标0的元素开始删,删2个.
list.Contains(Object obj);返回bool类型
list.Insert(1,"aaaa"); 在 下标1的位置插入aaaa;
list.InsertRange(1,new string[]{"aaa","bbb"}); 在 下标1的位置插入数组或者集合;
list.Reverse() 顺序反转
list.Reverse(int index,int count) 制定范围的元素顺序反转
list.Sort(); 升序排序,类型不一样报异常
list.Count 是指集合中实际包含的元素的个数.(注意和数组区分) int 类型
list.Capcity:集合中可以包含的元素的个数 int 类型
count变少,多的空间也销毁掉,但始终比count多
2.泛型集合