c#基础4

1.访问修饰符

作用

所有类型和类型成员都具有可访问性级别.

分类

public : 同一程序集的其他任何代码或引用该程序集的其他程序集都可以访问该类型或成员。
internal : 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集不可以访问。
private : 同一类和结构的代码可以访问该类型和成员。
protected : 同一类和派生(继承特性)类中的代码可以访问该类型和成员。
protected internal :  同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。
private protected:该类型或成员可以通过从 class 派生的类型访问

C#的默认修饰符

    类、结构体的默认修饰符是internal。
    类中所有的成员默认修饰符是private。
    接口默认修饰符是internal。
    接口的成员默认修饰符是public。
    枚举类型成员默认修饰符是public。
    委托的默认修饰符是internal。

  2.C# 方法(函数)
 

作用:

    方法是包含一系列语句的代码块。方法必须在类或结构中声明

优点:

减少代码重复率

方法体现了c#语言的封装性

方法的分为 声明方法 和调用方法

声明方法基本结构:

    访问权限  返回值类型   代表方法 是否具有 return 数据的类型

       void  和 其他明确的数据类型 (int  float 。。 string。。。)
    方法名称     大驼峰   见名之意
    方法参数    实参(调用方法) 和形参(声明方法)
    括号{     

     语句块

    }
   调用方法:

     在哪调用(在方法内部调用    Main 入口方法  程序运行时 自动执行   Main方法是静态方法   自定义静态方法直接使用, 自定义非静态方法 需要对象打点调用)

  

  方法的分类:

   从访问权限分类
  从有无参数和有无返回值分类
  从静态和非静态分类

  参数传递 形式:

  值参数

   特点:

  1.参数传递的默认方式 

  2.当调用一个方法时,会为每个值参数创建一个新的存储位置。

  3.当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全

  总结:无论参数的类型是值类型还是引用类型  都遵循值传递的特性

  引用参数 

   特点:

   1.引用参数是一个对变量的内存位置的引用 不会创建一个新的存储位置

   2. 参数关键字 ref

  

 int a = 10;
            int b = 20;
            Program  program = new Program();
            program.swap( ref a,ref b);
            Console.WriteLine("调用方法后a的值{0}",a);
            Console.WriteLine("调用方法后b的值{0}",b);


            string stra = "123";
            string strb = "456";
            program.swapString(ref stra,ref strb);
            Console.WriteLine("调用方法后 stra的值{0}", stra);
            Console.WriteLine("调用方法后strb的值{0}", strb);

            int[] intArray1 = new int[] { 1, 2 };
            int[] intArray2 = new int[] { 3, 4 };

            program.swapIntArray(ref intArray1,ref intArray2);
            foreach (int i in intArray1)
            {
                Console.WriteLine(i);
            }

            foreach (int i in intArray2)
            {
                Console.WriteLine(i);
            }

            People people = new People() { Id = 1000 };
            People people1 = new People() { Id = 2000 };
            program.swapPeople(ref people, ref people1);
            Console.WriteLine(people.Id);
            Console.WriteLine(people1.Id);

输出参数

  特点:

1. 是对于方法返回值的补充。return 语句可用于函数中返回一个值  输出参数可以返回多个值

2.关键字 out    out输出参数在方法中 必须被使用,且和retrun保持一致

3. 其他方面与引用参数相似

 public static int AddMothod(int a,int b,out string x) { 
        
            x = a.ToString()+b.ToString();
            int v = a + b;
            return v;
        
        }   

可变参数params (讲完数组再说)

1.params是ParamArrayAttribute(参数数组属性)的缩写
2.param解决了C#中不定参数的传递的问题

3.params参数必须定义在参数列表最后面。
   4.params必须对一维数组描述
     5.params只能在一个方法中 定义一个一维数组

static void ParamtesDemo(string className, params string[] names)
        {
               string tempStr = "";
              foreach (string name in names)
               {
                    tempStr += name;  
               }
                Console.WriteLine($"{className}的学生有:{tempStr}");
         }
ParamtesDemo("223班级", "张三", "李四", "王五", "赵六");

C# 空类型(Null)

1.Null

特点:

1.表示不引用任何对象的空引用,没有创建内存空间,存放的是空引用指针;

2.Null类型是System.Nullable这个struct的类型

3.对于值类型 赋值不能直接为null    引用类型可以

4.null引用类型变量的默认值

值类型如何赋值为null?

1.Nullable结构体

Nullable intNumber = null;

2.类型之后添加 单 ?

int? intNumber = null;

使用场景

当我们想要对于一个值类型变量进行 判断 是否 存在时,为了节约内存 可以赋值为null

null和字符串空值和字符串空格的区别

1.null是没有创建内存空间,

2.字符串空值  为"" 或者string.Empty  实际上都会分配空间;

3.字符串空格 "    "  会分配空间 空格也是ACSII  对应的符号

            string str = "123"; //正常字符串,有值非空
            string str1 = null;  //值为null
            string str2 = "";    //是个空字符串
            string str3 = "    ";//空白字符串,双引号之间是空格或者Tab键
            Console.WriteLine(string.IsInterned(str));
            Console.WriteLine(string.IsInterned(str1));
            Console.WriteLine(string.IsInterned(str2));
            Console.WriteLine(string.IsInterned(str3));


             IsInterned方法 判断数据是否已经存在于内存中

 双问号 ??(合并运算符)

作用:

用于判断一个变量在为 null 的时候返回一个指定的值

使用场景

Null 合并运算符为类型转换定义了一个预设值,以防可空类型的值为 Null

         double? num1 = null;
         double? num2 = 3.14157;
         double num3;
         num3 = num1 ?? 5.34;      // num1 如果为空值则返回 5.34
         Console.WriteLine("num3 的值: {0}", num3);
         num3 = num2 ?? 5.34;
         Console.WriteLine("num3 的值: {0}", num3);

不可变数组

含义:

不可变数组是一个存储相同类型元素的固定大小的顺序集合

特点:

数组属于引用类型

数组只能包含类型相同的元素

数组通过下标(索引值)标记元素

格式:

声明数组:

datatype[] arrayName;

  • datatype 用于指定被存储在数组中的元素的类型。
  • 指定数组的秩(维度)。秩指定数组的大小。
  • arrayName 指定数组的名称。

初始化数组中的元素的方式

数据类型[] 数组名 = new 数据类型[长度];
数据类型[] 数组名 = {值 1, 值 2, …}
数据类型[] 数组名 = new 数据类型[长度]{值 1,值 2,…}

数据类型[] 数组名 = new 数据类型[长度可忽略]{值 1,值 2,…}

数组访问元素:

修改数组元素:

遍历数组方式:

for

foreach

数组越界

例子:在控制台中录入学生成绩

要求:成绩范围0–100
“请输入学生总数:”
“请输入学生成绩:”
"输入的成绩有误 : "

多维数组

含义:数组嵌套数组形式   一般常用二维数组

二位数组格式:string [,] strArray =new string[数组个数,数组元素个数]

初始化二维数组

 /* 一个带有 5 行 2 列的数组 */
            int[,] a = new int[5, 2] {{0,0}, {1,2}, {2,4}, {3,6}, {4,8} };

二维数组访问元素:

  int val = a[2,3];

二维数组修改元素:

a[2,3]=10;

遍历二维数组元素

     for (int i = 0; i < studentArray.GetLength(0); i++) {

                for (int j = 0; j < studentArray.GetLength(1);j++) {

                    Console.WriteLine(studentArray[i, j]);
                }
                
            }

 

 

其他多维数组格式: 例如三维数组 string [,,] strArray =new string[数组个数,数组元素个数]

int[,,] val = new int[3, 3, 3]    { { { 10, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } },

                          { { 10, 11, 12 }, { 13, 14, 15 }, { 16, 17, 18 } },

{ { 19, 20, 21 }, {22, 23, 24 }, { 25, 26, 27 } } };

三维数组访问元素:

  int val = a[2,2,2];

三维数组修改元素:

a[2,2,2]=10;

遍历三维数组元素

  int[,,] tempArray = new int[2, 2, 2] { { {1,2 },{3,4 } },{ {5,6 },{7,8 } } };

            for (int i = 0; i < tempArray.GetLength(0); i++)
            {

                for (int j = 0; j < tempArray.GetLength(1); j++)
                {

                    for (int k = 0; k < tempArray.GetLength(2); k++) {
                        Console.WriteLine(tempArray[i,j,k]);

                    }
                 
                }

            }

交错数组 了解

含义

交错数组是数组的数组,交错数组是一维数组。

交错数组格式:

int [][] scores;

初始化交错数组中的元素的方式

    int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};

交错数组访问元素:

scores[0][1]

交错修改数组元素:

scores[0][1]  =10;

例子:在控制台中录入学生姓名 年龄 分数 性别

要求:成绩范围0–100  年龄要求18-20   性别要求 0对应女和 1 对应男
“请输入学生总数:

 添加学生姓名

展示所有学生信息

提示退出程序 或者是修改学生信息(Y/X)

提示修改第几个学生信息(一种有几个学生)?请输入对应的编号(1,2,3,4)

修改学生姓名

。。。。。

展示所有学生信息

提示退出程序 或者是修改学生信息(Y/X)

Array 类

含义:

是 C# 中所有数组的基类,它是在 System 命名空间中定义  提供了各种用于数组的属性和方法

常用属性 和方法

CreateInstance(typeof(int), 5);  //创建一维数组

 Array aa=     Array.CreateInstance(typeof(int), 5);
  aa.SetValue(0, 1);
  aa.GetValue(0);

   Array asa  =Array.CreateInstance(typeof(int), 2,2);//创建二维数组
    asa.SetValue(0, 1);

    asa.SetValue(0, 2)

     asa.SetValue(1, 2);

     asa.GetValue(1, 1);

Indexof(Array array, Obejct)    返回第一次出现的下标
Sort(Array array)    从小到大排序 (仅支持一维数组)
Reverse(Array array)    数组逆置
Clear(Array array, int index, int length)    将某个范围内的所有元素设为初始值
Copy      深复制   数组内容到另一个数组

//作业:1.写 四和5维数组  并且遍历   2.学生信息表 3.实现 sort  reverse  indexof 原理

不可变字符串
含义:

string,引用类型,string类型表示零或更多 Unicode 字符组成的序列,

string 是 .NET Framework 中 String 的别名。

初始化字符串方式
            //方式1 字面量创建字符串
            string str1 = "abc";
            string str2  = @"abc";
            //方式2
            char[] charArray = new char[5] { 'a','b','c','d','f'};
            string str3 = new string(charArray);
            //方式3
             string str4   = string.Format("123");

            //字符串本质也是单字符的集合
            string str5 = "abcdefg";
            Console.WriteLine(str5.Length);

            char charNumber1 =  str5[0];
            Console.WriteLine(charNumber1);
            //str5[0] = 'w';  无法直接修改某个单字符
            for (int i = 0; i < str5.Length; i++)
            {
                Console.WriteLine(str5[i]);
            }
            foreach (var item in str5)
            {
                Console.WriteLine(item);
            }

字符串常用API

    1.Length 获取字符串的长度,即字符串中字符的个数.
    2.IndexOf 返回整数,得到指定的字符串在原字符串中第一次出现的位置.
    3.LastlndexOf 返回整数,得到指定的字符串在原字符串中最后一次出现的位置.

    4. StartsWith 返回布尔型的值,判断某个字符串是否以指定的字符串开头.
       
    5. EndsWith 返回布尔型的值,判断某个字符串是否以指定的字符串结尾.
       
    6. ToLower 返回一个新的字符串,将字符串中的大写字母转换成小写字母.
       
    7. ToUpper 返回一个新的字符串,将字符串中的小写字母转换成大写字母.
       
    8. Trim返回一个新的字符串,不带任何参数时表示将原字符串中前后的空格删除.
       
    9. Remove 返回一个新的字符串,将字符串中指定位置的字符串移除.
    10. TrimStart 返回一个新的字符串,将字符串中左侧的空格删除.
       
    11. TrimEnd 返回一个新的字符串,将字符串中右侧的空格删除。
       
    12. PadLeft 返回一个新的字符串,从字符串的左侧填充空格达到指定的字符串长度.
       
    13. PadRight 返回一个新的字符串,从字符串的右侧填充空格达到指定的字符串长度.
       
    14. Substring 返回一个新的字符串,用于截取指定的字符串.
       
    15. Insert 返回一个新的字符串,将一个字符串插入到另一个字符串中指定索引的位置.
        

     16.concat

   17.contain

   18.IsNullOrEmpty

   19. char[] charArray = str.ToCharArray();

  20.str1.Split(',')

StringBuilder类的使用                 

特点:

1.可以定义可变字符串,实现字符串的添加

2.对于高频率字符串拼接可以使用

3.如果普通拼接 可以使用上节课所以将的字符串格式化方式

常用方法如下:

Append  末尾追加

Insert 在指定位置插入指定字符串

Remover 移除指定字符串

         

//普通拼接方法  (低效率 会频繁开辟不连续的内存空间 )
            string str = string.Empty;
            str += "abc";
            str += "efg";


            //(高效率 StringBuilder(可变字符串)在创建后 追加新的内容 是在原有内存中连续创建 提高效率)
            StringBuilder sb = new StringBuilder();
            //追加
            sb.Append("你好");
            sb.Append("吃饭了么");
            Console.WriteLine(sb.ToString());
              //插入
            sb.Insert(0, "abc", 2);
            Console.WriteLine(sb.ToString());
            //移除
            sb.Remove(0, 2);
            Console.WriteLine(sb.ToString());
            //清空
            sb.Clear();
            Console.WriteLine(sb.ToString());

                                

格式化字符串

  含义:用{ }来表示,在{ }内填写所占的位的序号,从0开始

            string name = "可乐";
            int age = 3;
            Console.WriteLine("{0}今年{1}岁",name,age);

string.Fromat() 

			string name = "可乐";
            int age = 3;
            string.Format("{0}今年{1}岁",name,age");
格式化标识符
字母 含义
C或c Currency 货币格式
D或d Decimal 十进制格式(十进制整数,不要和.Net的Decimal数据类型混淆了)
E或e Exponent 指数格式
F或f Fixed point 固定精度格式
G或g General 常用格式
N或n 用逗号分割千位的数字,比如1234将会被变成1,234
P或p Percentage 百分符号格式
R或r Round-trip 圆整(只用于浮点数)保证一个数字被转化成字符串以后可以再被转回成同样的数字
X或x Hex 16进制格式
static void Main()   
         {
                   int i=12345;
                   Console.WriteLine("{0:C}",i);   //货币
                   Console.WriteLine("{0:D}",i);   //十进制数
                   Console.WriteLine("{0:E}",i);    //科学技术法
                   Console.WriteLine("{0:F}",i);   // 浮点数表示法
                   Console.WriteLine("{0:G}",i);   //G或g General 常用格式
                   Console.WriteLine("{0:N}",i);   //N或n 用逗号分割千位的数字

                   精度控制标识控制了有效数字的个数或者十进制数小数的位数
                    例如{0:C5}   C 代表类型  5代表精度
    
                    Console.WriteLine("{0:C5}", i); // ¥123,456.00
                    Console.WriteLine("{0:D5}", i); // 123456
                    Console.WriteLine("{0:E5}", i); // 1.23456E+005
                    Console.WriteLine("{0:F5}", i); // 123456.00000
                    Console.WriteLine("{0:G5}", i); // 1.23456E5
                    Console.WriteLine("{0:N5}", i); // 123,456.00000
                    Console.WriteLine("{0:P5}", i); // 12,345,600.00000 %
                    Console.WriteLine("{0:X5}", i); // 1E240
            
         }

时间格式化符号
d MM/dd/yyyy ShortDatePattern(短日期模式)
D dddd,MMMM dd,yyyy LongDatePattern(长日期模式)
F dddd,MMMM dd,yyyy HH:mm Full date and time (long date and short time)(全日期和时间模式)
F dddd,MMMM dd,yyyy HH:mm:ss FullDateTimePattern (long date and long time)(长日期和长时间)
G MM/dd/yyyy HH:mm General (short date and short time)(通用模式,短日期和短时间)
G MM/dd/yyyy HH:mm:ss General (short date and long time)(通用模式,短日期和长时间)
M,M MMMM dd MonthDayPattern(月天模式)
r,R ddd,dd MMM yyyy,HH':'mm':'ss 'GMT' RFC1123Pattern (RFC1123模式)
S yyyy-MM-dd HH:mm:ss SortableDateTimePattern (conforms to ISO 8601) using local time(使用本地时间的可排序模式)
T HH:mm ShortTimePattern (短时间模式)
T HH:mm:ss LongTimePattern(长时间模式)
U yyyy-MM-dd HH:mm:ss UniversalSortable-DateTimePattern (conforms to ISO 8601) using universal time(通用可排序模式)
U dddd,MMMM dd,yyyy,HH:mm:ss UniversalSortable-DateTimePattern(通用可排序模式)
y,Y MMMM,yyyy YearMonthPattern(年月模式)
static void Main()   
         {
                   Console.WriteLine("{0:D}",DateTime.Now);   //输出到天
                   Console.WriteLine("{0:y}",DateTime.Now);   //输出到月
                   Console.WriteLine("{0:m}",DateTime.Now);    //取出是那个月
                   Console.WriteLine("{0:T}",DateTime.Now);   // 取长时间到秒
                   Console.WriteLine("{0:t}",DateTime.Now);   //取短时间到分
                   Console.WriteLine("{0:tt}",DateTime.Now);   //取出是上午还是下午     
            
         }

模板字符串 $"{变量1},{变量2}"

            string name = "可乐";
            int age = 3;
            Console.WriteLine($"{name}今年{age}岁");

一、概述

一、关于类与对象

1、为什么要学习面向对象编程?
答:面向过程编程,很难解决复杂业务逻辑和适应业务需求的变化。面向对象能够将程序很好的“模块化设计“,清晰的“分层组合”,方便的“业务扩展”。

2、从生活中的“类”转换到程序中的“类”
答:生活中很多东西都可以归为一个类。人:(男人、女人)
软件中的类,是为了处理相关的数据。

4、类的规范(组成)

访问修饰符  class  类的名称

    成员变量

     //字段部分

   成员函数
    
      //属性部分

      //方法部分
}

1..访问修饰符:默认是internal (内部的) 也可以定义为public

2..类的名字:使用大驼峰l命名法(首字母大写)

3.类可以只有属性、只有方法、也可以属性、方法全部都有。

什么是字段

       /成员变量 (字段)
        //(1)字段是类型的成员,也称为成员变量 在类中字段也可以叫全局变量 在整个类中可以使用
        //(2)字段是定义在类中方法之外的 局部变量是定义在方法内部的
        // (3) 字段的格式: 访问修饰符(默认访问修饰符 private ) 数据类型  字段名
        // (4) 字段是有默认值的  值类型默认值为 0  引用类型默认值为null  局部变量没有默认值
        //(5) 字段的类型为值类型和字符串类型 使用时是深拷贝(会克隆)  其他的引用类型 默认是浅拷贝(不克隆 给原值)
        //(6) 字段的访问修饰符  学过的修饰符字段都能使用
        //(7) 在一个类中 不能重复定义字段  但是允许定义相同名字的字段和局部变量   使用规则:就近原则
        //(8) 字段的命名规则  _+小驼峰  保持和系统框架中的字段名字一致
        //(9) 字段包含 静态字段和非静态字段(实例字段)
        //(10) const描述的字段 不能使用staitc  原因 const描述的字段 本质就是包含静态的含义
        //(11)  readonly描述的字段  可以使用staitc  可以在定义字段时赋值或者在其构造函数中赋值
        //(12) 一般使用字段时 都使用private的   为了内部的字段不暴漏给其他类
        //但是使用private后 字段的灵活消失  ,使用类的成员-属性 来解决 字段灵活性的问题
        //实例字段 随着new对象的创建而创建
        //静态字段 在类加载的时候创建 且创建一次

三、对象的实例化

如何对象的实例化   使用new关键字  new 开辟内存空间为对应类的对象 (内存保存的时实例字段和实例方法和实例属性)

实例化一个对象语法是:
类名 对象名=new 类名()  

 属性 和字段的关系


           //属性 和字段的关系
            //1.属性是类的成员函数
            //2.属性其实外界访问私有字段的入口
            //3.属性本质就是方法  一个属性可以分别有一个set 和get 方法组成。(或者称为访问器)\
            //4.属性的名字用大驼峰命名  一般和对应的私有字段名字保持一致
            //5.属性的扩展 ---增加字段的业务判断逻辑。

属性的基本格式

public string Code
{
   get
   {
      return code;
   }
   set
   {
      code = value;
   }
}

三、属性(Property)
1、使用ILDasm反汇编工具发现get和set其实是两个方法,并且每一个属性都有对应的私有字段。
2、断点观察get和set发现,当我们给属性赋值的时候,其实是调用set方法,给对应的私有字段赋值,当读取属性值的时候,其实是调用了get方法,从对应的私有字段里面把值取出来。

属性:本身其实并没有保存数据,数据是保存到属性对应的私有字段中。。

属性是为了更好的实现需求的变化的扩展,从而让一个属性可以实现多样的需求!

3、属性的扩展
【1】增加业务判断逻辑。

  private int _test;
        public int Test
        {   
            set {
                if (value > 100)
                {

                    _test = 100;
                }
                else { 
                     _test = value;
                 }
            }
            get {
                return _test;
            } }


【2】设置只读字段功能

  private int _test =10;
       
        public int Test
        {   
            get {
                return _test;
            } }


【3】设置只读业务逻辑。(可以没有私有字段)

  public string Number  只读
        {
            get {
                string name = "zhangsan";
                return name;
            }  
           
        }

5、属性和字段对比

【1】字段,又称为“成员变量”
第一、目的:字段是为类的内部方法,或者方法之间传递数据使用,强调对内使用。
第二、修饰:字段一般用private修饰,很少用public。
第三、读写:字段可以读写均可,也可以用readonly限制为只读,但是不能添加业务逻辑。

【2】属性
第一、目的:属性是对外提供数据访问、本身不保存数据,强调对外使用。
第二、修饰:属性都是public,从来不用private。
第三、读写:属性可以轻松的实现单独读写控制,并且可以添加任意需要的业务逻辑。

   public int Test { get; set; } 可读可写
    
 

结论: 开发中,只要对外使用数据,都用属性,即使没有任何扩展业务,我也不建议使用public类型的字段(强烈建议)。过多使用public类型的字段,会显得你不专业。

6、属性使用的新特性扩展(4.6或以上版本)
【1】属性直接初始化 

public string StrNumber { get; set; } = "属性直接初始化";


【2】属性表达式

public string StrNumber2 { get => "属性表达式"; }
        public string StrNumber3 => "属性表达式";

7、对象类型的属性使用

总结:类本身就是一种数据类型(引用类型)所以,类中的属性或者变量(成员变量、局部变量)也可以是类类型(对象类型)

  • 什么是方法

  • 回顾以前内容
  • 方法--构造函数

  •             //构造函数  
                //1.本质就是方法
                //2.作用 类创建对象时 使用的特殊方法
                //3.类默认存在构造函数   
                //4.构造函数的名字 一定要和类名相同
                //5.构造函数分为实例构造函数、私有构造函数和静态构造函数
                //6.构造函数没有返回类型,它可以带参数,也可以不带参数
                //7.构造函数自己定义时,会覆盖系统默认的    自己定义构造函数 原因:系统默认的功能无法满足需求
                //8.实例构造一般使用public
                //9.私有构造函数使用private  不希望其他类 创建自身的对象时  (没有实例成员时)
                //10.静态构造函数  默认系统会自带   在类创建时 用来初始化 所有的 静态成员   
                //11.静态构造函数既没有访问修饰符,也没有参数
                //12.无参数的实例构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类 ,一个属于实例,所以不会冲突

   public class MyClass1 
    {


        /*
         私有构造函数可用于阻止外部创建类的实例 
         如果内部调回构造函数  还是可以创建对象  
         如果想要一个类 真正的没有对象创建  使用静态类
         */
        private static int _age;
        private static string _name;

        private MyClass1() {
            _age = 10;
            _name = "张三";
        }

        public static MyClass1 Create()
        {

            MyClass1 myClass1 = new MyClass1();
            return myClass1;

        }

} 

 静态类
           

//1.使用static描述的类
            //2.不能创建实例对象 也不能定义实例成员  只能定义静态相关成员
            //3.制作工具类时  可以使用
            //4.私有构造函数  限制了外部创建对象   静态类任何地方无法创建对象 没有提供实例构造函数 有静态构造函数
            //5.静态类 无法被继承

//静态类  一般用于工具类 
    public static class MyClass2
    {

        //静态类中无法创建构造函数
        // public MyClass2() { }
        //静态类中的所有成员为静态
        private static int _age;
        private static string _name;
        public static string Name { set { _name = value; } get { return _name; }  }
        public static int Age { set { _age = value; } get { return _age; } }

        public static void MyClass2StaticMothod()
        {

            Console.WriteLine("MyClass2StaticMothod");

        }

    }

  

 析构函数:

垃圾回收程序最终销毁对象之前调用的方法,该方法称为析构函数

析构函数通常形式如下:
~类名()
{

 }

析构函数的声明类似构造函数,除了在析构函数开头要使用 ‘~’,另外要注意,析构函数,没有返回值,且不带任何参数。

析构函数的功能是用来释放一个对象的。在对象删除前,用它来做一些清理工作,它与构造函数的功能正好相反。

什么是垃圾回收

在编写程序时,会产生很多的数据 比如:int string 变量,这些数据都存储在内存里,如果不合理的管理他们,就会内存溢出导致程序崩溃

C#内置了自动垃圾回收GC,在编写代码时可以不需要担心内存溢出的问题 变量失去引用后 GC会帮我们自动回收.

什么样子的对象才会给回收?

1.GC只会回收 的内存 ,而 值类型在 中的使用完后马上就会给释放,并不需要 GC 进行处理,

2.堆中的没有被引用或者null的对象才会被回收,会调用析构函数通知程序 对象将要释放

3.静态的成员 会在程序结束后销毁。

什么时候进行垃圾回收?

什么时候回收这些都由操作系统决定,一般不需要进行理会全由系统调用,,明确如有特殊情况的需要进行释放 也可以强制的垃圾回收


namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Test test = new Test();
            test = null;
            //强制开启回收
            GC.Collect();
            Console.ReadKey();
        }
    }

    public class Test {
        public int a;
        ~Test() {
            Console.WriteLine("ZHIXINGLE");
        }

   }

C#封装,继承,多态

面向对象特性: 封装、继承、多态 

三个特性主要目标:重用性(安全性)、灵活性和扩展性。

一,封装
什么是封装?

将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的公共属性

来实现对隐藏信息的操作和访问。

封装可以通过以下方式实现:

属性(Property):通过Get和Set方法实现对数据的读写操作,并可以在进行数据读写时添加自定义的逻辑。在C#中,属性可用于将实例变量封装到类中

访问修饰符: C#中有四种访问修饰符:public、private、protected和internal。这些访问修饰符可用于控制类中数据和方法的访问权限.

方法:实现细节可以隐藏起来并只暴露实现所需的最小接口。这样可以保证类的内部细节安全,并且仅在类的外部提供必要的接口.


二.继承

什么是继承?

        继承的作用:解决类与类直接 属性或者方法重复的问题
   1.一个类继承另一个类  其中被继承的类(父类 超类 基类)  继承的类(子类 派生类)
       2.继承的格式  A类(子类) : B类(父类)  
       3.继承关系建立后  子类拥有父类的成员  反之父类不继承子类成员。 父类私有成员 子类无法使用  
       4.C#中类与类之间是单继承关系(子类只能同时继承一个父类)   利用接口实现多继承(后续讲)
       5.一个父类可以同时被多个子类继承    子类可以间接继承父类  
       6.object是所有类的父类   如果一个类 没有明确继承关系   默认继承于object类
       7.创建子类对象时,系统默认先调用父类构造方法,然后再调用子类构造方法
       8.当父类有有参构造方法时.必须提供一个无参构造函数 供子类调用
       9.子类在调用其有参或者无参构造函数时,默认调用父类的 无参构造函数
       如果想要调用父类有参构造函数  使用在子类构造函数后添加:base(参数名)

      10.覆盖,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字

  多态

什么是多态?

即一个接口,多个功能  同一种操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

包含: 

重写    抽象类  接口   重载  

重载

在一个类中或者子类中函数名相同,参数类型或者顺序不同构成重载,与返回类型无关
 

重写

在子类和父类中,子类中的方法名称和父类方法名称相同,参数相同  

使用关键字 virtual,将父类的方法标记为虚方法,用 override  关键字,虚方法可以被子类重写

 public class Person
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public Person(string  name)
        {
            this.Name = name;
        }

        public virtual void SayHello()
        {
            Console.WriteLine("我是人类");
        }
    }

    public class Chinese:Person
    {
        public Chinese(string name)
            :base(name)
        {

        }

        public override void SayHello()
        {
            Console.WriteLine("我是中国人,我叫{0}", this.Name);
        }
    }

this

  • 当前类的对象
  • 静态成员方法中不能使用this关键字,this关键字只能在实例构造函数、实例方法或实例访问器中使用

base

  • base关键字用于从派生类中访问基类的成员;
  • 派生类对象调用基类构造函数;
  • 调用基类上已被重写的方法
  • 不能从静态方法中使用base关键字,base关键字只能在实例构造函数、实例方法或实例访问器中使用

抽象类  
 //抽象类
            //1关键字 abstract
            //2.不能被实例化    不能创建对象
            //3.普通类继承抽象类   抽象类可以继承抽象
            //4.抽象类可以包括抽象方法和抽象属性但是不能定义抽象字段,或者能定义普通方法属性字段
            //5.普通类继承了具有抽象成员的 抽象类  必须在其内部重写抽象的抽象成员  (使用override)
            //6.静态成员不能定义为抽象

用简单的话来说抽象类的功能就是:我是师傅(抽象类),你要是跟了(继承)师傅,你就必须得会干什么

例如:师傅会打人,那你也必须会打人,但你是轻轻的打,还是狠狠的打,你自己决定,但你必须得会打人。

类 DerivedClass 派生自抽象类 BaseClass。 抽象类包含抽象方法 AbstractMethod,以及两个抽象属性 X 和 Y
abstract class BaseClass  
{
    protected int _x = 100;
    protected int _y = 150;
    public abstract void AbstractMethod();   // Abstract method
    public abstract int X    { get; }
    public abstract int Y    { get; }
}
 
class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }
 
    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }
 
    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }
 
    static void Main()
    {
        var o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine($"x = {o.X}, y = {o.Y}");
    }
}

接口

含义

接口定义了所有类继承接口时应遵循的语法合同 .用接口可以使程序更加清晰和条理化

1.接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的

2.接口只包含了成员的声明( 方法 属性声明) 

3.接口中只能包含方法、属性、索引器和事件的声明。不允许声明成员上的修饰符,即使是pubilc都不行,因为接口成员总是公有的,也不能声明为虚拟和静态的。如果需要修饰符,最好让实现类来声明。

4.接口中定义的成员 需要继承类 来进行实现

5.接口也可以继承接口

6.一个类 可以继承多个接口  (接口就是c#实现多继承的方式)

接口和抽象类 区别和相同点

相同点: 不能实例对象    都可以被继承   都可以给继承类提供成员模板

不同点:接口只能有成员定义  抽象类 也可以包含成员的实现    接口可以实现多继承  抽象类只能单继承

密封类 
     1.密封类可以用来限制继承性
     2.声明密封类时需要使用sealed关键字
     3.密封类和普通类一样 都可以定义属性和方法
     4.密封类不能作为基类被继承,但它可以继承别的类或接口
     5.密封类可以实例化对象  系统中String 就是密封类
     6.在密封类中不能声明受保护成员或虚成员
     */

//生成 随机数

Random random = new Random();  得到的random就是一个随机数生成器,它可以用来生成随机数。

int Next(int minValue, int maxValue);

  这个方法能指定随机数的生成范围,左闭右开区间,即生成的数能包含minValue,不包含maxValue。可以包含负数。但是maxValue的值不能大于minValue的值,否则运行时会抛出异常。

int Next(int maxValue);

  这个方法指定随机数的最大值(不包含maxValue),并且它也只能生成非负整数,与Next(0, maxValue)是一个道理,如果传入的maxValue为负数,那么运行时抛出异常,如果maxValue的值为0或1,那么生成的随机数只能是0。

double NextDouble();

这个方法能返回一个大于或等于 0.0 且小于 1.0 的随机浮点数。

你可能感兴趣的:(c#,c++,开发语言)