类的定义
一切皆对象,客观世界中的所有事物,我们都可以用面向对象的方式将其描述出来。所以,从某种角度来看,面向对象的程序就是用类来堆积起来的。
语法:
[访问修改符] [static] class 类名 { 类成员:[属性] [字段] [方法][….] }
其中:
访问修饰符:代表了这个类可以被访问的范围。
static:代表它是一个静态类
属性与字段:就是类中以变量的形式来存储的类的特征信息。
方法: 类的动作特征。
注:class是小写。类名可以用英文与可以用中文。
示例:
class Program { static void Main(string[] args) { person tom = new person(); tom.age = 3; tom.birthday(); tom.birthday(); } } class person //类名 { public int age; //字段、成员变量 public void birthday() //方法、成员函数 { age += 1; Console.WriteLine("Happy birthday to me , I'm {0} years old !",age); } }
类在本质上就是一种数据类型
我们自己定义的类,可以成为,本类或另一个类中的成员变量、属性、方法返回值(等情况)的数据类型,该数据类型的值,就是该类的实例化对象。
基本上可以用int、string、bool等数据类型的情况,都可以用你自己定义类型来代替。
示例:
class Program { static void Main(string[] args) { Driver 老张 = new Driver(); 老张.姓名 = "老张"; car ccc = new car("阿斯顿马丁", 250); car ccc1 = new car("奔驰S600", 250); car ccc2 = new car("兰博基尼", 300); car todayCar = 老张.driving(ccc2); Console.WriteLine("老张今天开的是" + todayCar.车型); } } class car { public string 车型; public int 速度; public car(string model , int speed) 车型 = model; 速度 = speed; } public void checkspeed() { if (速度 > 100) Console.WriteLine("您已超速,请安全驾驶"); } } class Driver { public string 姓名; public car mycar; public car driving(car car1) { mycar = car1; Console.WriteLine("{0}正在驾驶{1},他的速度是每小时{2}公里。",姓名,mycar.车型,mycar.速度); return mycar; } }
字段:
就是类里面定义的变量,用于存储类的特征信息。
比如:上例中的age
定义字段(成员变量)的语法
class 类名 { [访问修饰符] [static] 数据类型 变量名; }
方法:
类里面的成员函数
语法:
class 类名{ [访问修饰符] [static] <返回类型> 方法名(参数列表) { [return [返回值]] } }
静态方法与非静态方法的区别
没有static的非静态方法,必须通过类的实例对象来调用,不用直接通过类名来调用。(只有静态方法可以通过类名来调用)。
示例:
class Program { static void Main(string[] args) { person tom = new person(); tom.age = 3; tom.birthday(); //非静态方法必须通过对象来调用 person.showAge(); //静态方法必须通过类名来调用 } } class person //类名 { public int age; //字段、成员变量 public void birthday() //方法、成员函数 { Console.WriteLine("Happy birthday to me , I'm {0} years old !",age); } public static void showAge() //静态方法 { Console.WriteLine("你好,见到你很高兴"); } }
复习静态方法以了解非静态方法的用法:
示例:
class Program { static void Main(string[] args) { 计算器 j1 = new 计算器(); float result = j1.加法(3.14f,10); //调用方法并传入参数,并将方法返回的结果存入另一个变量中。 Console.WriteLine(result); } } class 计算器 { public float 加法(float 加数, float 被加数) { return 加数 + 被加数; //返回值 } }
对象的实例化
语法:
类 对象名 = new 构造函数();
其意义就是创建一个类中的具体的成员。
构造函数
其主要作用,就是当需要从一个类中实例化一个对象的时候,用于对这个对象的字段或属性进行初始化的赋值等操作。
构造函数什么时候执行?
构造函数就是在用类实例化对象的同时执行的,就是new关键字后面的构造函数名所调用。
语法:
[访问修饰符] 类名([参数列表])
{
初始化类成员
}
示例:
class Program { static void Main(string[] args) { 学生 tom = new 学生(20, "tom", 53.3f); //通过构造函数来对类中的每一个成员赋值 Console.WriteLine("我叫{0}今年{1}岁体重{2}公斤",tom.name , tom.age , tom.heavy); } } class 学生 { public int age; public string name; public float heavy; public 学生(int Age,string Name, float Heavy) { age = Age; name = Name; heavy = Heavy; } }
注意事项
构造函数的函数名与类名是相同的。
构造函数是没有返回值的。
构造函数与方法一样可以接收传入参数。
构造函数的默认访问修饰符是private,因此通常我们都需要在构造函数的前面加上public ,以便在实例化对象的时候使用。
当一类中没有构造函数的时候,系统会自动添加一个public的空的构造函数。
小练习:
1、设计一个book类,这个类有书名、作者、价格三个成员变量。实例化四本书,并为其成员变量赋值。添加一个“打折”方法(输入参数为折扣,比如0.8就是八折,然后显示打折后的价格。),调用这个打折方法显示类似“由{0}所著的《{1}》正在打折,原价{2}元,会员折后价{3}元。”
2、定义一个类,名叫“圆形”,只有一个字段“半径”,我们通过构造函数来对半径赋值。它有两个方法,一个是显示圆面积,一个是显示圆周长。然后,实例化两个圆形,并分别调用这两个方法。
3、定义一个类,名叫“长方体”。它拥有长、宽、高三个字段,我们通过构造函数来对长宽高三个字段赋值。它有两个方法,一个是显示体积,一个是返回表面积,然后,实例化两个长方体并分别执行这两个方法。
4、定义一个类,名叫“car”,有两个字段:车型、速度。通过构造函数来对两个字段赋值,定义一个方法checkSpeed,判断车速大于100的话就显示“您已超速,请安全驾驶”。实例化汽车对象,并执行checkSpeed()方法
5、定义一个司机类Driver:
a)其成员变量:姓名、汽车(使用上题中的类作为汽车数据类型)
提示:public car myCar
b)定义一个方法driving , 在该方法中实例化汽车对象(并将其赋值给该类的”汽车”字段,显示:“谁正驾驶什么型号车,最大时速是多少”)。
6、定义一个计算器类,不包含任何字段,但是它有四个方法:加减乘除,这四个方法都接收两个float类型的传入参数并返回return一个运算结果。
7、定义一个“员工类”,拥有字段 姓名、本月应工作日,本月迟到次数(迟一次扣30元)、本月旷工次数(旷一天扣三天工资)、本月请假次数(请一天扣一天工资)、基本工资数,再添加一个方法“实现工资”,运算并返回最终工资(计算过程不允许使用+-*/号,必须使用上题中的计算器方法进行加减乘除)。
8、定义一个类 游戏角色,此类拥有字段:名称、攻击力、血量、防御力,及一个方法:
Public float 攻击(游戏角色 对手) //代表被打的一方 { 本次伤害值 =我方攻击力 – 对方防御力 对方血量 =对方血量 –本次伤害值 return本次伤害值 }
再定义一个 ”战场” 类,该类有两个字段分别是 “游戏角色” 类型 的角色1和角色2,还有一个”对决开始()” 方法,在这个方法中让 角色1和 角色2轮流执行攻击对方(并显示每次攻击的结果),直到一方的血量<=0为止,效果如下:
游戏开始:
小怪兽攻击奥特曼并造成21点伤害,奥特曼当前生命值19点。
奥特曼攻击小怪兽并造成11点伤害,小怪兽当前生命值11点。
小怪兽攻击奥特曼并造成21点伤害,奥特曼当前生命值-2点。
小怪兽获胜。
附加:每次攻击的伤害值,都会产生”二分之一伤害值” 上下的浮动。
属性
属性就相当于是给字段(成员变量),加了一层“外层”,主要作用就是用来约束和规范字段中的数据的合理性。
语法:
private 数据类型 成员变量名; public 数据类型 属性名 { get{ […] return 成员变量; […] } set{ […] 成员变量=value; […] } }
属性本身它不是一个变量,属性只是字段(成员变量)的一个外壳,用于将字段的值封装起来,进行约束和规范。其中:
get
代表当需要对字段(成员变量)进行读取操作的时候,需要执行的一系列代码。get的代码是包含在一对{}中, 而且最终必须要通过一个return语句来返回字段的值。
set
代表当需要对字段(成员变量)进行赋值操作的时候,需要执行的一系列代码。set的代码是包含在一对{}中, 而且用户身属性中所赋的值,在set中用value关键字来表示。
补充
通常而言,字段与属性是一 一匹配的,就是一个属性搭配一个字段,而且字段是private (私有)的,属性是public(公有)的。
示例:
class person { int age; public int Age { get { return age; } set { if (value >= 0) age = value; else{ age = 0; Console.WriteLine("年龄不能为负数"); } } } }
小练习:
定义一个类为atm提款机,设置一个money字段和Money属性,要求这个帐户的金额上限不能超过10000,下限不能超过0。而且当读取金额时,如果金额小500,要提示用户“将扣除管理费”。要求用属性的方式来实现。
值类型和引用类型
内存可以分为栈内存和堆内存
栈内存
用于存放一些较小的信息,比如:数字和地址。
堆内存
可以存放一些较大的信息,比如:较长的文本,或者是图片等等。
值类型
int、char、float、bool等等
其特点是,变量名和变量值全都是存在栈内存中的。
引用类型
array、string、用户自定义的类
变量名是存入在栈内存中的(以变量值在堆内存中的地址),变量值是存在堆内存中的。
创建类和实例化对象的过程
就好像是图书馆入库了一本新书,先在堆内存(书库中)中确定这本书存放的位置,然后在栈内存中添加一张卡片,卡片上面写明了变量名(书名)和堆内存地址(图书在书库中的编号)
访问修饰符
public 公有的,任何地方都可以访问。
private 私有的,只能由本类中的成员访问。
protected 受保护的,是指内部保护访问,仅限于本类和本类的子类访问(祖传)
internal 程序集内部访问,当代码经过编译之后,在同一个exe或dll中的类或对象可以相互访问,但是不能跨程序集访问。
protected internal :仅限本项目或子类。
this关键字
就是自身、自己的意思。
一般用于,在一个类之中引用当前类的成员变量或方法。
示例:
class person { public string name = "小明"; public void sayName() { string name = "小白"; Console.WriteLine(name); //方法内部定义的变量,在该方法中优先于方法外部的同名变量。 Console.WriteLine(this.name); //this就是用来调用类成员的,因此this.name调用的是类的name字段。 } }
析构函数
当一个对象被销毁的时候,所执行的函数。
通常它用于清理这个对象所占用的空间,及后续的操作。
语法:
~类名()
{
析构操作
}
注意:
1、只能对类使用析构函数。
2、一个类中只能一个析构函数。
3、析构函数无法手动调用,只能在被销毁的时候自动调用。
4、析构函数没有访问修饰符,也没有传入和返回参数。
一般情况下, .net都可以很好的自动完成对象资源的回收和管理,不需要我们手动干涉析构的过程。