面向对象_4_静态类、结构体、ref

静态变量

也可以称为全局变量,静态变量就是可以不通过实例化而能够直接使用的类成员变量。

语法:

[修饰符] static 变量名 [= 变量值] ;

注意:

类中的普通成员,可以调用静态成员。

类中的静态成员无法调用非静态的普通成员。

项目中的所有静态成员,都会在这个项目一开始时被运行,就是被创建并存在于内存之中,即使它所在的类没有被实例化。

如果没有明确的对静态变量赋值,那么,数值类型将自动赋值为0,引用类型将自动赋值为nullbool类型将被自动赋值为false。因此,我们可以说static静态变量始终是有一个值的。

 示例1

static void Main(string[] args)
{
student.age = 18;
      Console.WriteLine( student.age);
}
class student  {
       public static int age = 21;
}

示例2,利用静态变量来统计一个类共有多少个实例对象:

static void Main(string[] args)
{
    dog 小白 = new dog();
    dog 小黑 = new dog();
    dog 小黄 = new dog();
    dog 小二黑 = new dog();
    Console.WriteLine("我家有{0}小狗", dog.littleDog);
}
class dog 
{
    public static int littleDog;
    public dog() 
   {
          littleDog++;
   }
}

小练习:

1、定义一个student类,并为其添加一个字符型静态变量classRoom,然后在main主函数中,对该变量进行赋值后,显出来。该类还有一个普通字段name,同时也要对该字段进行赋值。

静态方法

它与静态的相似之处在于,该方法可以在不实例化的情况下直接用类名来调用。

只要程序开始运行,那么我们随时都可以在其他地方调用该方法,而不需要进行实例化。

注意:

静态方法中不能使用this

在静态方法中不能使用非静态的属性、字段、方法,除非在该方法中先实例化了这个类的对象。

非静态方法中可以调用静态方法。

示例:

public static void showMessage() 
{
     Console.WriteLine("您收到一条信息");
}

静态类

从语法上来说,静态类的定义和非静态类的区别,就是多了一个static关键字。

通常静态类在程序中都是一些使用较频繁的类,为了避免每次都实例化的麻烦和性能的浪费,而被直接定义为静态类。

静态类在程序的一开始运行就会被加载到内存之中,而且它不能够被实例化,也不需要实例化,直接用它的类名访问即可。

示例:

static class tools 
{
      public static float add(float n1, float n2) {
      return n1 + n2;
}
public static float jian(float n1, float n2) {
          return n1 - n2;
      }
}

语法:

[访问修饰符] static 类名
{
         静态成员 //静态类中的所有成员都必须是静态的。
}

注意:

静态类不能够被实例化

静态类中的所有成员都必须是静态的。

静态构造函数

1、静态类可以有构造函数,但必须是静态构造函数。

2、静态构造函数不能有访问修饰符,而且不能有任何传入参数。只能有一个static

3、静态构造函数不能被直接调用,只有在调用静态类的中的静态成员之前,静态构造函数会被自动执行,并且只执行一次。

非静态类使用完后系统会自动在内存中将其清理掉。

静态类则是在程序启动时被创建,在程序结束时被清理。这期间它是一直驻留在内存之中的。

小练习:

利用静态变量来统计cat类有多少个实例对象。

常量

它是指已知的,不能修改的值。

1、常量是静态的,但是不能使用static修饰它。

2、常量只能在声明的时候赋值,它的值在程序编译运行的时候已经确定了,在程序中不能改变。

语法

const 数据类型 常量名 = 常量值;

通常常量名是大写字母

 示例:

static void Main(string[] args)
{
      Console.WriteLine(dog.HEAVY);
      //没有实例化,而是像静态变量一样直接调用
}
class dog  {
      public const float HEAVY = 10.3f;
}

类的只读字段

如果你希望类听某个成员变量只能读取而不能修改的话,那么只需要在它的前面加一个关键字readonly

示例

static void Main(string[] args)
{
      dog 小白 = new dog();
      //小白.legTotal = 5; 报错,只读取字段不能修改值
      Console.WriteLine("小白有{0}条腿",小白.legTotal);
}
class dog 
{
     public readonly int legTotal;
     public dog() 
     {
           this.legTotal = 4;
     }
}

注意:

只读字段可以在声明时或者构造函数内赋值。但不能在其他的地方赋值。

只读字段可以用static声明为静态只读字段。

枚举类型

它用来列举出多个可选攻。

enum关键字用来表示枚举类型,枚举类型是一种特殊的类型。它与class类是同一级别的,因此可以定义在class的外面。

示例:

enum weekDay {unday,monday,tuesday,wednesday,thursday=50,friday,saturday}
class Program
{
       static void Main(string[] args)
{
weekDay wd = weekDay.sunday;
//声明一个枚举类型的变量,它的值只能是该枚举类型的可选值之一
Console.WriteLine(wd);
Console.WriteLine((int)wd);
//枚举类型的数值可以转换为int类型
//它的值就代表了枚举类型中的次序和下标
wd += 2;
Console.WriteLine(wd);
//加2之后,枚举值变为了次序向后2个位置的那个值。
weekDay wd2 = weekDay.friday;
Console.WriteLine((int)wd2); //在前一个值的基础之上加一
}

小练习:

定义一个枚举类型 ”十二星座”,再定义一个类”学生”,其中有一个属性是”星座”(“星座”的类型是”十二星座”),然后实例化三个学生,赋值并显示他们的星座。比如:

张三是射手座

结构体

我们可以将结构体看作是一种简化版本的类。

因为结构体在语法和功能上与类非常相似,都可以具有成员变量、成员方法。

结构体可以实现的功能,类都可以实现,但是结构体的性能要优于类。

语法:

定义结构体

[访问修饰符] struct [名称]
{
      //字段、属性、方法
}

示例:

static void Main(string[] args)
{
     //book 新华字典 = new book();
     book 新华字典; //结构体不是必须用new 来构造的。
     新华字典.bookName = "新华字典";
     新华字典.pageNum = 700;
     新华字典.showIntro();
}
public struct book 
{
     public string bookName;
     public int pageNum;
     public void showIntro() 
    {
          Console.WriteLine("这本书名是{0},有{1}页", bookName, pageNum);
    }
}

结构体与类的对比

结构体

数据类型

值类型

引用类型

是否必须new实例化

是否可以声明无参的构造函数

成员变量是声明的时候赋初值

否,但是常量和静态变量可以

父类

System.valueType

是否有析构函数

是否可以继承父类

可以

是否可以继承并实现接口

可以

可以

实例化时在栈内存还是堆内存

栈内存

堆内存,变量名在栈内存

该类型的变量(实例对象)是否可以为null

是否始终有一个默认的无参的构造函数

否,(中要有用户自定久的构造函数,那么原来的默认的构造函数就不存在了)

小练习:

定义一个结构体computer,包含成员变量string cupstring 内存、string 主板、string 硬盘 、string 显卡、string 品牌、float 价格。

然后实例化至少一台电脑,并显示出这台电脑的配置信息。

方法的传入参数

ref参数

对于值类型来说,如果将一个变量作为参数传入方法,那么在方法内部相当于是新建了一个变量,它与方法外的那个传入的变量是没有联系的。因此在方法内部改变这个变量的值,不会影响到方法外部的那个变量。

 但是如果将引用类型的变量作为参数传入到方法内部的话,在方法内部对这个参数所做的改变,将会影响到原来的那个方法外部的变量。

但是如果必须将值类型的变量传入方法,并在方法内部改变且影响方法外原来那个变量的话,就要使用ref参数了。

示例:

static void Main(string[] args)
{
     float i = 5.3f;
     changeF(ref i);
     Console.WriteLine("i在方法外的值" + i);
}
public static void changeF(ref float s)
{
      s += 1;
      Console.WriteLine("i在方法内的值" + s);
}

注意:方法定义和方法调用时都要加ref关键字

out参数

outref功能类似,都是用于让值类型变量作为方法的传入参数时,能够拥有引用类型那样影响到原变量的特征。它与ref的区别在于,ref参数变量在传入方法之前必须得赋值,但是out参数变量在传入方法之前可以不赋初值。

示例:

static void Main(string[] args)
{
     float i;
     changeF(out i);
     Console.WriteLine("i在方法外的值" + i);
}
public static void changeF(out float s)
{
     s = 1;
     s += 1;
     Console.WriteLine("i在方法内的值" + i);
}

注意:

out参数变量在传入方法前可以为空,也可以赋初值 。

但是,无论有无初值,out参数变量在方法内必须进行赋值操作,即使原来已经有值了。

params不定传入参数个数

在有些特殊情况下,传入一个方法的参数的数量是不固定的,比如:加法操作,每次需要相加的数字的个数都不确定。我们就需要使用params关键字。

params实际上是声明并接收了一个数组。这个数组可以接收0到若干个相同类型的参数。

示例:

static void Main(string[] args)
{
      班级总分("666", 81, 45, 90, 20, 59.9f, 60.01f, 100, 70);
      班级总分("665", 81, 45, 90, 20, 59.9f, 60.01f, 100, 70,80,90);
}
static void 班级总分(string cName, params float[] scores) 
{
     float SCount = scores.Sum();
     //数组的sum方法用于得到所有元素之和
     Console.WriteLine("{0}班的总分是{1}",cName,SCount);
}

注意:

params所对应的参数必须都与数组的类型一致。

params允许出现在方法的多个传入参数之中,但是params参数必须得是所有参数的最后一个。

一个方法中最多只能有一个params参数。

猜你喜欢

转载自www.cnblogs.com/yigegaozhongsheng/p/9439186.html