面向对象三大特性:封装,继承,多态。
面向对象:是一种看带问题,解决问题的思维方式。 着眼点:在于找到一个能够帮助我们解决问题的实体,然后委托这个实体帮我们解决。
面向过程:是另一种看待问题,解决问题的思维方式。 着眼点:在于问题是怎么样一步步的解决的,然后亲力亲为的去解决这个问题。
eg: 小明作为一个电脑小白,需要自己组装一台电脑。
面向过程:
a:补充相关知识(小明) b:去买零配件(小明) c:运回家里(小明) d:组装(小明)
面向对象:
a:找一个懂电脑的朋友,老王(小明) b:买里面配件(老王) c:运回家里(快递) d:组装(老王)
对象:具有一定的功能,能够帮助解决特定问题的实体,就是一个对象。 类:一系列具有相同功能和特征的对象的集合。
在程序中,先设计一个类,才能通过类拿到设计的对象。所以引入了类的设计这个概念。
语法
class 类名 //类名是一个标志符,遵循大驼峰命名法。 { //类体 }类内的成员 字段:用来描述这个类所有的对象公有的特征。 方法:用来描述这个类所有的对象公有的行为或功能
class Person { //特征(通过字段来表现) //加Public是为了让其他类也能引用到该类中的字段 public string name;//引用数据类型的初始值为NULL public int age; public char gender;//gender是这个类的一个字段 //行为(通过方法来表现) public void Eat() { Console.WriteLine(name + "在吃饭"); } public void Sleep() { Console.WriteLine(name + "在睡觉"); } public void Beat() { Console.WriteLine(name + "在打豆豆"); } }*例子:
List item //eg1:(两个内容相同的对象,是否是同一个对象) Person lili = new Person(); lili.name = "lili"; lili.age = 9; lili.gender = 'M'; Person lucy = new Person(); lucy.name = "lili"; lucy.age = 9; lucy.gender = 'M'; //只是结果恰好相同但是,不是同一个对象,指向的不同地址上的结果,因此是false Console.WriteLine(lili == lucy);//结果为false //eg2;坑(地址的引用) Person polly = new Person();//在堆上开辟新空间,将地址给了plloy polly.name = "polly";//将名字命名为plloy Person kity = polly;//没有在堆上开辟了新空间,而是将plloy中的地址给了kity,所以kity指向的还是plloy在堆上的空间 kity.name = "kity";//将名字重新命名为kity Console.WriteLine(polly.name);//打印plloy地址指向的堆上的name空间 Console.WriteLine(kity.name);//打印kity地址也就是plloy地址指向的name空间 //因此结果都为:kitystatic表示静态的,可以用来修饰类的成员(字段,方法等),也可以用来修饰类static静态的,不变的,在某个类中只有一个,不会因实例化对象的不同而不同。static可以修饰类、字段、属性、方法等。如一个方法前加上static修饰后要对其进行调用可以直接通过类名点出来(即静态的成员是属于类的),不用再对类进行实例化。
静态(static)的成员是属于类的,访问的时候是需要用类来访问
非静态成员是属于对象的,访问的时候需要用对象来访问
class Dog { //static关键字 public int age; public char gender; public string name; public static string kind; public void Eat() { Console.WriteLine(name + "吃饭"); } public void Sleep() { Console.WriteLine(name + "睡觉"); } public void Bark() { Console.WriteLine(name + "在叫"); } public static void StaticTest() { } } //实例化一个对象 Dog hashiqi = new Dog(); //访问类中的成员 hashiqi.name = ""; hashiqi.age = 1; hashiqi.gender = 'M';//非静态用字段来访问 //hashiqi.kind = "";//会出错 Dog.kind = "哈士奇(拆迁队)";//静态用类来访问 Dog.kind = "萨摩(拆迁队长)"; Dog taidi = new Dog(); taidi.name = "泰迪"; taidi.age = 1; taidi.gender = 'F';如果在设计类时,希望字段的值可以是不一样的可以修改的,那么字段设计成非静态的。一般设计类中,绝大部分都是非静态的。
1.只能包含静态成员(静态方法或静态变量),非静态成员是不能使用的,而非静态类可以包含静态的方法、字段、属性或事件,且无论对这个非静态类创建多少个实例,它的静态成员都只有一个。 2.不能对其实例化。 3.不能被继承,因为静态类本质是一个抽象的密封类。 4.不能包含实例构造函数。
1.static只能修饰成员变量,不能修饰局部变量。 2.表示每次重新使用该变量所在方法、类或自定义类时,变量的值为程序这次运行最后一次为变量赋值时的值。 3.静态变量一直记录变量的值,一直到下次赋值时。 4.不同线程下访问的静态属性总是同一属性,如果某一线程更改了属性值,将造成其他线程访问属性值的错误。因此方法中访问同一静态属性就需要使用lock关键字,或创建互斥对象来保持静态属性在同一时间只能被某一对象的属性或方法访问。 5.静态成员只被创建一次,所以静态成员只有一份,而实例成员有多少个对象,就有多少个成员。
1、在方法(函数)前用static修饰,表示此方法为所在类或所在自定义类所有,而不是这个类的实例所有。 2、在静态方法中只能直接调用同类中其他的静态成员(包括变量和方法), 而不能直接访问类中的非静态成员。 3、每一个线程在同一时间访问的静态方法都是不同的,因此静态方法在多线程调用中不会产生冲突。 4、在静态方法中不能直接调用实例成员,因为静态方法被调用时,对象还有可能不存在。 5、this/base关键字在静态方法不能使用,因为有可能对象还不存在。 6、静态方法只能被重载,不能被重写,因为静态方法不属于类的实例成员。
1.静态类可以有静态构造函数,静态构造函数不可继承。 2.可以用于静态类,也可用于非静态类。 3.无访问修饰符、无参数,只有一个static标志。 4.不可被直接调用,当创建类实例或引用任何静态成员之前,静态构造函数被自动执行,并且只执行一次。
1.当变量需要被共享时可以将变量定义为静态变量。 2.当方法需要被反复调用时可以将方法定义为静态方法。 3.当一个类中包含的成员都是静态时可以将类定义为静态类。
类中的每一个字段方法和属性,在访问的时候都需要有一个主体(主语)来访问,在某些情况下,访问的主体是可以被省略的。
C#所有的对象都将创建在托管堆上。实例化后的类型我们称之为对象,其核心特征便是拥有了一份自己特有的数据成员拷贝。这些为特有的对象所持有的数据成员我们称之为实例成员。相反那些不为特有的对象所持有的数据成员我们称之为静态成员,在类中用static修饰符声明。仅对静态数据成员实施操作的称为静态函数成员。
C#中静态数据成员和函数成员只能通过类名引用获取,看下面的代码:
注意静态方法不能使用this关键字 上面的代码中,因为主函数是静态函数,我们只能通过实例化对象才能访问。 而在实例方法fun2中我们可以直接用this调用fun1,并且可以省略this。
实例方法比静态方法多传递一个隐含的指针参数(即使是无参函数),只要是成员方法,编译器就会给你加上this这个参数,例如 void method1(){}实际上是这样的--------> void method1(A this) void method2(int x){}实际上是这样的--------> void method2(A this, int x)
this代表的是调用这个函数的对象的引用,而静态方法是属于类的,不属于对象,静态方法成功加载后,对象还不一定存在. 静态方法不可使用this因为静态方法不针对任何实例对象。实例对象调用静态方法会因参数中多出一个指向自己的指针(this)而发生错误。 而静态方法与对象无关,根本不能把对象的引用传到方法中,所以不能用this
在构造函数中this用于限定被相同的名称隐藏的成员
public class Student { public int age = 10; public Student(string name, string age) { this.name = name; Console.WriteLine(this.age);//结果为:10 Console.WriteLine(age);//结果为:20 } } class Progran{ public static void Main(string[] ages){ Student xiaoming = new Student(20); } }1、构造方法没有返回值(int、float、string、void等),甚至void也不可以写。
2、构造方法的方法名必须是类名。
3、构造方法不能显示调用,是在实例化对象的时候被自动调用的。
4、作用:用来实例化一个对象。
5、非静态的构造放方法只有在实例化对象的时候才会执行,当Person 老王 = null;此时构造方法没有被执行。
6、注意:在实例化一个对象时,必须要构造方法。如果一个类中,没有写构造方法,那么系统会提供一个默认的无参的public权限的构造方法;如果一个类中已经写了构造方法,那么这个系统的构造方法将不再被提供。(只是在非静态构造方法中符合)
eg:无参构造基本用法
class Person{ public int age; //无惨构造方法 //如果变成private时,则无法访问, //private是私有权限,表示私有权限修饰的字段、属性、方法只能在当前类内使用 public Person() { Console.WriteLine("无参的构造方法被调用了"); //谁调用方法this就是谁 //刚刚Person xiaoming = new Person()调用了当前这个方法, //因此这个this就是xiaoming,所以age的结果为:10 this.age = 10; } } class Program { public static void Main(string[] args) { Person xiaoming = new Person();//new Person()就相当于调用了无参的构造方法 Console.WriteLine(xiaoming.age);//结果为:10 } }在这个例子中,主程序调用Show(10);方法Show中的形参a将值传给了Add(a);方法Add中的形参a又将值传给了Dog(a);最后方法Dog将结果打印出来。而下述例子中值的传递与“:this(name)”方法中值的传递是一样的.
//形参中的string name指向的是this(name),也就是说将形参中的name值传给了this中的name.例如: static void Show(int a) { Add(a); } static void Add(int a) { Dog(a); } static void Dog(int a) { Console.WriteLine(a); } public static void Main(string[] args){ Show(10); }1、用static修饰的构造方法 2、静态构造方法不允许使用访问修饰符 3、静态构造方法必须是无参数的 4、静态的构造方法只执行一次,在第一次使用这个类的时候执行(当这个类第一次被加载在内存中的时候执行)
使用类的两种情况:
第一种:当实例化一个对象的时候
第二种:当调用一个静态方法的时候
class Person { //静态构造方法 static Person() { Console.WriteLine("静态构造方法被执行了"); } public Person() { Console.WriteLine("非静态的构造方法被执行了"); } //2、调用静态方法 public static void Show() { Console.WriteLine("静态的构造方法被执行了"); } } class Program { public static void Main(string[] args) { //1、实例化一个Person对象 Person xiaoming = new Person();//结果为:静态构造方法被执行了 // 非静态的构造方法被执行了 //产生这个结果的原因:在非静态构造方法中当实例化一个对象时,如果没有写构造方法,那么系统会自动提供一个非静态的构造方法,而这里有静态构造方法和非静态构造方法,但是参数一样,因此会两个都打印,且静态构造方法调用在前。 Person laowang = null;//不算实例化对象,因此不执行 //2、调用静态方法 Person.Show();//结果为:静态构造方法被执行了 // 静态的构造方法被执行了 Person,Show();//结果为:静态构造方法被执行了 // 静态的构造方法被执行了 Person.Show();//结果为:静态的构造方法被执行了(public static void Show()) //Static Person()结果只会打印一次,因为只有第一次使用类的时候,静态构造方法才会执行,因此第二次不会打印“静态构造方法被执行了” } }当某一个对象被销毁时调用。
当需要销毁一个对象的时候被自动调用
1.析构函数的定义与注意的问题:
a.析构函数用于释放被占用的系统资源。
b.析构函数的名字由符号“~”加类名组成。
2.使用析构函数时,应该注意下面的问题:
a.只能在类中使用析构函数,不能在结构体中使用析构函数。
b.一个类只能有一个析构函数。
c.不能继承或重载析构函数。
d.析构函数只能被自动调用。
e.析构函数没有任何修饰符、没有任何参数、也不返回任何值。
3.调用析构函数
a.垃圾回收器决定了析构函数的调用,我们无法控制何时调用析构函数。
b.垃圾回收器检查是否存在应用程序不再使用的对象。如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。
c.程序退出时会调用析构函数。
d.我们可以通过调用Collect强制进行垃圾回收,但是请不要这样做,因为这样做可能导致性能问题。
1.构造函数和析构函数是在类中说明的两种特殊的成员函数。
2.构造函数是在创建对象时,使用给定的值将对象初始化。
3.析构函数用于释放一个对象。在对象删除前,使用析构函数做一些清理工作,它与构造函数的功能正好相反。
eg:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test { class Program { class First // 基类First { ~First() // 析构函数 { Console.WriteLine("~First()析构函数"); } } class Second : First // Second类从First类派生 { ~Second() // 析构函数 { Console.WriteLine("~Second()析构函数"); } } class Third : Second // Third类从Second类派生 { ~Third() // 析构函数 { Console.WriteLine("~Third()析构函数"); } } static void Main(string[] args) { // C#析构函数-www.baike369.com Third Third1 = new Third(); // 创建类的实例 } } }程序运行时,这三个类的析构函数将自动被调用,调用顺序是按照从派生程度最大的(Third())到派生程度最小的(First())次序调用的,和构造函数的调用顺序正好相反。
运行结果:
~Third()析构函数
~Second()析构函数
~First()析构函数