面向过程;面向的是完成这件事儿的过程,强调的是完成这件事儿的动作;
用面向过程的思想去解决问题,当执行这件事的人不同的时候,我们必须为他量身定做不同的方式来解决问题;
面向对象;找个对象帮你做事; 面向对象就是屏蔽差异,写出通用的代码; 对象一般都是被动的那个;
我们在代码中描述一个对象,通过描述这个对象的属性和方法;
我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念;
类就是个模子,确定了对象应该具有的属性和方法;对象是根据类创建出来的;
类
[public] class 类名
{
字段;
属性;
方法;
}
如果方法前面加了static,那么调用的时候就要用类名.方法 ;如果这个方法和Main函数在同一个类中,那么可以省略类名,直接写方法名;
写好了一个类之后,我们需要创建这个类的对象,我们管创建这个类对象过程称之为类的实例化;使用关键字new; Person p = new Person(); 跟结构一样,通过对象.字段的方式调用;p.age = 24;
public void CHLSS()
{
Console.WriteLine("我叫{0},我今年{1}岁了",this._name,this._age);
}
this表示当前类的对象; 通过对象.方法名的方式调用;p.CHLSS();
类是不占内存的;而对象是占内存的;
Person p; 跟int a;其实都是一个道理,声明一个变量;
我们自己写的类,我们称之为自定义类;
Person p;如果不创建对象,它的值是null;null在内存中是不占内存的; 如果创建了对象,那对象的字段就有了初值,因此开辟了内存空间;与其说对象占内存,不如说类当中的字段占内存;
如果方法不是static的,叫做非静态方法;那么调用它的时候,应该先创建一个对象,在用对象.的方式去调用方法;
结构和类的区别,结构是面向过程的,类是面向对象的;结构不具备面向对象的任何特征;类是真正的面向对象的;
属性的作用就是保护字段;对字段的赋值和取值进行限定;
属性应该写在类当中
public string _name;
public string Name
{
get {return _name;}
set {_name = value;}
}
属性的本质是两个方法,一个是get(),控制取值,一个是set();控制赋值;
通过反编译器可以看到程序的源代码;先把写好的程序编译一下,编译成功后,在文件资源管理器中找到bin下的debug目录下的.exe可执行文件,把它拖到反编译器 里面;就可以看到源代码;如果找到了属性,但是还想继续看下面的代码,先在上面把C#转换为IL&Bytes,继续往里点到最后,再把IL中间语言转化为C#,就能看懂代码了;
fields字段;methods方法;Properties属性
给字段赋值的时候会执行set方法,外面传进来一个值,通过属性,把值传给字段; 赋值的时候不能给字段赋值,要通过属性赋值,虽然是给属性赋值,但是最终赋值到的还是字段;属性在中间只起到过渡中间的作用;
当你给属性赋值的时候,首先会执行set()方法; 当你输出属性的值的时候,会执行get()方法
蓝色的长方体是字段;扳手图标是属性;
通过属性有2种方式对字段的取值和赋值进行限定;一个是在set()方法里面,一个是在get()方法里面;
在整个过程中,属性是没有存储值的。
打属性的快捷键 Ctrl+R,E两下回车;
字段是女人,存储数据用的,我们要好好保护起来;不能轻易得被别人访问到;属性才是男人,所有跟外界打交道的事应该交给属性去做;因此字段的访问修饰符是 private
访问修饰符 public:公开的,公共的,在哪都能访问 private:私有的,只能在当前类的内部进行访问,出了这个类就访问不到了;
类中,如果字段不加访问修饰符,默认就是private;
get
{
if(_gender != '男' && _gender != '女')
{
return _gender = '男';
}
return _gender;
}
set
{
if(value < 0 || value > 100)
{
value = 0;
}
_age = value;
}
对同一个属性,在get()中控制值和在set()中控制值的效果是一样的; 等我们学了构造函数,在构造函数中也可以设定;
并不是所有的属性都有get()和set(); 如果一个属性既有get()又有set()我们称之为可读可写属性;只有get()我们称之为只读属性 只有set()我们称之为只写;
在set里面我们控制的是value的值,在get里面我们控制的是字段的值,先set()后get()因为先赋值后取值;
字段在类中必须是私有的,属性是公有的; 类中的成员,不加访问修饰符,默认是private;
给对象的每个属性赋值的过程叫做对相的初始化;
看一个成员是不是静态成员,就要看这个成员有没有被static修饰;
在非静态类中,即可以有实例成员,也可以有静态成员; 在调用实例成员的时候,需要使用对象名.实例成员(); 在调用静态成员的时候,需要使用类名.静态成员名; 静态成员必须使用类名去调用,而实例成员使用对象名调用;
在非静态类中可以有静态属性,静态字段,非静态属性,非静态字段,静态方法,非静态方法;
静态函数中,只能访问静态成员;不允许访问实例成员; 实例函数中,既可以使用静态成员,也可以使用实例成员; 静态类当中只允许有静态成员;不允许出现实例成员;
静态类不能创建实例对象,因为在调用静态成员的时候是用类名.的方法去调用,因此即使能够创建静态类的对象,也是没有意义的;
什么时候使用静态类:如果你想要你的类当做一个"工具类"去使用,这个时候可以考虑将类写成静态类; 我们把经常会使用的函数封装到一个类当中,我们称这个类是工具类;
静态类的特点:1.调用方便; 2.静态类在整个项目中,资源共享。
类是不占内存的,但是对象是占内存的,不过静态类例外;静态类没有对象,静态类的成员由于没有对象,因此只能用静态类本身来存;所以静态类本身是占内存的;
堆 栈 静态存储区域(存的是静态类的资源) 在整个项目中,谁都可以访问静态存储区域,因此也就造成了静态类在整个项目中资源共享;
QQ登陆之后,把账号,密码保存到一个静态类当中;因此访问不同的模块的时候不需要重新输入用户名和密码;
.net释放资源是用GC来完成的,垃圾回收器,但是有些东西是它释放不了的,比如我们所说的文件流; 静态类资源越少越好,1多的话占内存;2.只有在程序全部结束之后,静态类才会释放资源;所以静态类不要太多,它会始终消耗你的资源;
构造函数用来创建对象,并且可以在构造函数中对对象进行初始化(给对象的每个属性依次的赋值);
构造函数是用来创建对象的特殊方法; 1.构造函数没有返回值,连void都不能写 2.构造函数的名称必须跟类名一样;
构造函数可以有参数,new对象的时候传递函数参数即可
如果不指定构造函数,则类有一个默认的无参构造函数。如果指定了构造函数,则不再有默认的无参构造函数,如果需要无参构造函数,则需要自己来写
类里面可以有字段,属性,方法,构造函数;
构造函数的访问修饰符必须是public;
public Student()
{
}
在我们创建对象的时候,首先会执行构造函数; 如果想初始化对象的话,就在构造函数中对对象的每个属性赋值;
public Student
(string name,int age,char gender,int chinese,int math,ing english)
{
this.Name = name;
this.Age = age;
this.Chinese = chinese;
this.Gender = gender;
this.Math = math;
this.English = english;
}
创建对象的时候会调用构造函数,要求你传入6个参数,构造函数把你传入的值依次得赋值给这个对象对应的属性;
Student zsStudent = new Student("张三",18,'男',100,100,100);
//zsStudent.Name = "张三";
//zsStudent.Age = 18;
//zsStudent.Gender = '男';
//zsStudent.Chinese = 100;
//zsStudent.Math = 100;
//zsStudent.English = 100; 用了有参数的构造函数这些给属性赋值的代码就不必用了;因此构造函数可以大大减少代码量;
zsStudent.SayHello();
zsStudent.ShowScore();
new关键字; Student s = new Student();
new帮助我们做了三件事; 1.在内存中开辟一块空间; 2.在开辟的空间中创建对象; 3.调用对象的构造函数进行初始化对象;
这三步有一步完不成这个对象就创建不出来;因此构造函数的访问修饰符必须是public;如果是private的话其他类里面创建对象的时候就访问不到这个构造函数了;
public Student(string name,int age,char gender)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
}
构造函数可以重载,也就是有多个参数不同的构造函数。
我们写好一个类之后,就有一个自带的默认无参的构造函数; 类当中会有一个默认的无参的构造函数,当你写一个新的构造函数之后,不管是有参数的还是无参数的,那个默认的无参数的构造函数都被干掉了;
public Student(string name,int chinese,int math, int english):this(name,"0",'男',chinese,math,english)
{
}
public Student(string name,int chinese,int math, int english):this(name,"0",'男',chinese,math,english)
调用的时候 Student zhangSan = new Student("张三",100,100,100);
执行的过程是先调用这个构造函数,调用这个构造函数的时候又调用全参的构造函数; 把(string name,int chinese,int math, int english)这些参数传给全参的构造函数;再由全参的构造函数赋值给每个属性;归根结底调用的是全参的构造函数; 这就是通过类中的构造函数去显示的调用另外的构造函数;目的就是减少冗余代码;
this的作用 1.代表当前类的对象; 2.在类当中显示的调用本类的构造函数:this
类里面可以有字段,属性,方法,构造函数,析构函数;
析构函数
~Student() //这就是析构函数;
{
}
当程序结束的时候,析构函数才被执行;
析构函数对我们的作用就是释放资源;.net有GC GarbageCollection垃圾回收器,能够自动的帮助我们释放资源; 但一般我们不去手动的调用GC帮我们回收,而是我们的程序自动使用GC帮我们回收程序;这时候有个问题,有可能我们的程序结束后,GC没有马上帮助我们 释放资源;如果你想要资源马上去释放的话,那我们就要去使用析构函数;如果不使用析构函数的话,那么就由我们的垃圾回收器GC自动帮我们释放资源;
public class Ticket
{
private double _distance;
public double Distance
{
get{return _distance;
}
}
public Ticket(double distance)
{
if(distance < 0 )
{
distance = 0;
}
this._distance = distance; //在构造函数中也能控制字段的值的非法性,另外还有在属性的get和set方法中也能控制字段的非法性;
}
privete double _price;
public double Price
{
get
{
if(_distance > 0 && _distance <= 100)
{ return distance * 1.0; }
else if(_distance >= 101 && _distance < 200)
{ return distance * 0.95; }
else if(_distance >= 201 && _distance < 300)
{ return distance * 0.9;}
else
{ return distance * 0.8;}
} //get是一个天然的方法;在取值的时候就会调用这个方法;
}
public void ShowTicket()
{
Console.WriteLine("{0}公里的价格是{1}",Distance,Price);
}
}