第一节 封装
C #中的类和对象
- 在VS中,F9设置断点,然后F5运行,之后F11进行断点的语句。F11如果运行到其他的类的方法中,会自动跳转。
- 字段:就是我之前理解的定义了变量的意思。
C# 属性的封装
- 属性:对字段进行了封,字段的访问修饰符是private。
封装的快捷方式:选中字段(变量),然后CTRL+R+E
,字段的访问修饰符自动变,调用字段的地方也自动变。
//public 公共的 private 私有的(默认的)
private string _name;//姓名字段,访问修饰符是private
/// <summary>
/// 姓名属性
/// </summary>
public string Name {
get { return _name; }//读访问器,注意有分号
set { _name = value; }//写访问器,注意有分号
}
- get方法是读,set方法是写,如果去掉set方法,那么就变成了只读属性,如果想为属性赋值,有两种方法,直接为字段赋值,或者通过构造方法赋值。
- 通过set方法,对属性的赋值进行约束,例如:
public int Age
{
get
{
return age;
}
set
{
if(value<=7 && value>=3)
age = value;
}
}
C# 方法
- 方法的使用(无参):1、声明方法(方法名,小括号,大括号)。2、调用方法(通过类来调用)。例如:
//在Child 类中声明(定义)了两个方法PlayBall()和EatSugar()
class Child{
public void PlayBall() {//方法的使用有两步:1、声明方法
Console.WriteLine("踢足球");
}
public void EatSugar() {
Console.WriteLine("我很喜欢吃糖");
}
}
class Kindergarten{
stativ void Main(string[] args){//程序入口主方法
Child xiaoMing = new Child();//实例化一个对象,通过对象调用方法
xiaoMing.PlayBall();//2、调用方法,通过类来调用
xiaoMing.EatSugar();
}
}
- 方法的使用(有参):1、声明方法 (有形参)。2、调用方法(传递实参,类型的数量要对应)。
class Child{
public void EatSugar(string sugar){//一个字符串类型的无参
if(sugar == "榴莲糖"){
Console.WriteLine("我不喜欢吃榴莲糖!");
}elae{
Console.WriteLine("太好了,我喜欢吃"+sugar+"糖!");
}
}
}
class Kindergarten{
static void Main(string[] args){
Child xiaoMing = new Child();
xiaoMing.EatSugar("棉花糖");//实参的类型,和个数要与方法声明的无参的类型和个数一样
}
}
- 方法的重载:在同一个类中,有多个同名的方法,方法的参数个数或者类型至少要有一项不一样,否则无法通过编译。例如:
class Child{
public void EatSugar(string sugar){//string 类型的参数1个
Console.WriteLine("你喜欢吃的是"+sugar+"糖!?");
}
public void EatSugar(int count){//int 类型的参数1个
Console.WriteLIne("你今天已经吃了"+count+"块糖了吧?");
}
public void EatSugar(string sugar, int count){//string 类型的参数有1个,int 类型的参数有1个
Console.WriteLine("你已经吃了"+count+"块"+sugar+"了!!!");
}
}
- return的作用,当方法执行到return,方法就停止了。
- return的另一个作用,是返回值,声明方法的时候要指定返回值类型,这个类型必需与return返回的值的类型一致。
对比以下两例子,一个直接输出,另一个将结果返回到调用处由调用处进行处理。返回到调用处更好,因为结果可以由调用处决定用来做什么。
- 方法直接输出内容,调用方法不能与对方法运算的结果进行操作了:
public void Add(int a,int b){
int sum = a + b ;
Console.WriteLine("{0}+{1}={2}",a.b.sum);
}
- 方法返回结果给调用处使用,运算结果在调用处可以使用,注意方法声明的时候指定的返回类型要与return返回的类型一致:
public int Add(int a,int b){
int sum = a + b ;
return sum ;
}
C# 构造方法
- 无参构造方法:如果不设置,则将默认无参隐式存在。
1.作用之一是为属性赋值。
2.如果设置了有参的,隐式的无参将不存在。
3.构造方法的唯一一种调用方式:new Child()
,Child为类名。
4.通常声明为pulic类型。
5.返回值类型不用说。
6.构造方法可以重载,构造方法名与类同名。
public Child(){
Name = "周星星" ;
}
- 有参构造方法为属性赋值:
有访问器的条件下,我们是这样通过构造方法为属性赋值的:
Child类:
class Child{
public Child(string name,string sex,int age){
Name = name ;
Sex = sex ;
Age = age ;
}
private string _name;//姓名
private string _sex ;//性别
private int _age ;//年龄
//_name访问器
public string Name{
get{ return _name ; }//注意分号
set{ _name = value ; }
}
//_sex _age访问器类似,省略
}
Kindergarten主类:
class Kindergarten{
static void Main(string[] args){
Child xiaoMing = new Child("小明","男",6);//参数个数、类型、位置都要对应
Console.WriteLine("大家好,我叫"+xiaoMing.Name);//值就放在xiaoMing.Name变量里了
//其他属性调用类似
}
}
- this 关键字,表示当前对象,如果存在重名,则用于区分是哪个字段,属性,或者方法。命名不冲突可以不使用。
- 构造方法的重载。与普通的方法重载一样,找到对应的参数的进行调用。需要注意的就是,如果你手动定义了构造方法,默认的无参构造方法就会不再存在了。
- 对象初始化器:使用的是无参构造方法,无参构造方法必须存在。在实例化对象的时候,在后面增加一双大括号。代码如下:
Child xiaoMing = new Child(){Name = "小白"};//小括号可以不要,大括号后要有分号
C# 值类型和引用类型
- 值类型:int char double bool 之类的,创建副本是重新复制一份出来,修改副本则仅更改此副本的值,其他的值不受影响。
- 引用类型:类,数组,接口,string类型,创建副本时只是将其存储的地址复制一份,指向的是同一个内存空间,修改任何一个副本所有的值都会改变。
值类型:
int x =10 ;
int y = x ;
y++ ;
//更改了 y 的值, x 的值不受影响。
Console.WriteLine(x);//10
Console.WriteLine(y);//11
引用类型:
Child xiaoMing = new Child();//实例化一个对象
xiaoMing.Name = "小明"; // xiaoMing 对象的 Name 属性为小明
Child xiaoYong = xiaoMing ; // 将 xiaoMing 对象赋值给 xiaoYong ,只是将 xiaoMing 的地址复制一份给 xiaoYong,指向的是同一块内存空间.
xiaoYong.Name = "小勇" ;// 在 xiaoYong 对象更改 Name 属性
//更改其中一个副本的值,其他副本也会受到影响
Console.WriteLine(xiaoMing.Name);//小勇
Console.WriteLine(xiaoYong.Name);//小勇
- 结构
1.class 是类,是引用类型。 struct 是结构,是值类型。
2.结构体中可以有字段、属性、方法。
3.结构体不可以直接为字段赋值。
4.结构体不能显式设置无参构造方法,有参构造方法必须为所有的字段初始化,是字段,不是属性。
5.可以不用实例化结构,注意重载方法的使用,要传递一样的参数才会调用。在Main方法的前面就进行了声明。
6.结构也可以调用方法。
结构体的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kindergarten
{
struct Dog //class是引用类型 struct是值类型
{
string _name;//结构可以有字段
int _age;//第二个字段
//_age = 10 ; 不能为字段初始值
public string Name//结构可以有属性
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
public void Sing() {//结构可以有方法
Console.WriteLine("汪汪");
}
//public Dog() { } 结构不能显示定义无参构造方法,并且在调用构造方法中要为所有的属性赋值
public Dog(string name, int age) {
this._name = name;//必须要为所有的字段都赋值,
//Name = name;//需要对字段赋值后才能使用对象
this._age = age;
}
}
}
调用结构体的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kindergarten
{
class Program
{
static Dog dog;//在这个位置声明
static void Main(string[] args)
{
//Dog dog = new Dog();//可以不用实例化对象
dog.Name = "小白";
dog.Age = 1;
Console.WriteLine(dog.Name+dog.Age);
dog.Sing();//也可以调用方法
}
}
}
- 枚举类型,是一种值类型。
1.不能定义字段、属性、方法。
2.作用是限定变量的取值范围,提供一组有限的值,值的索引是从0开始递增的。
3.枚举类型和整型能够相互之间进行类型转换。
在一个单独文件中定义枚举:
enum GenDer {
男,女 //男的下标是0,女的下标是1。结尾不能有分号
}
从此GenDer 就当是一种数据类型来使用。如:
GenDer sex1 ;
sex1 = (GenDer).0 ; //将0 强制转换成GenDer 类型
GenDer sex2 ;
sex2 = GenDer.男 ; //两种使用方法。
- 方法参数中的值类型和引用类型
1.按引用传递,形参改变,实参也会改变。
2.按值传递,形参改变,实参没有改变。
实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kindergarten
{
class Program
{
static void Main(string[] args)
{
Child c1 = new Child("小明",(GenDer)1,12);
//Growth(c1);//按引用传递
Growth(c1.Age);//按值传递
Console.WriteLine("我现在"+c1.Age+"岁了!");//查看原来的值有没有改
}
static void Growth(Child c) {//接收的是对象,按引用传递
c.Age++;//改变Age的值
Console.WriteLine("1长大了一岁");
}
static void Growth(int age) {//接收的是整形,按值传递
age++;
Console.WriteLine("2长大了一岁");
}
}
}
- ref关键字:使按值传递的参数改为按引用传递。
注意:属性或引器不能作为out或ref的参数传递
实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kindergarten
{
class Program
{
static void Main(string[] args)
{
int age = 3;
Growth( ref age);//属性或引器不能作为out或ref的参数传递
Console.WriteLine("我现在"+age+"岁了!");//4
}
static void Growth(ref int age) {//接收的是整形,按值传递
age++;
}
}
}
- out 关键字:
在形参中指定了这个就是用来返回的,return只能返回一个值,out可以返回多个值.实参上也需要指明是out,接收的变量不需要初始化.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kindergarten
{
class Program
{
static void Main(string[] args)
{
int age = 3;
int ly, ny;//去年年龄,明年年龄
Growth(age,out ly,out ny);//out关键字声明的变量是用来接收out的输出的
Console.WriteLine("我今年"+age+"岁了!");//今年年龄
Console.WriteLine("我去年" + ly + "岁了!");
Console.WriteLine("我明年" + ny + "岁了!");
}
static void Growth(int age,out int lastYear,out int nextYear) {//out关键字指明变量是用来输出的
//lastYear = age--;//去年是今年少一岁,错误的做法
//nextYear = age++;//明年是今年加一岁,错误的做法
lastYear = age - 1;//正确做法,不会更改age的值
nextYear = age + 1;
}
}
}