面向对象的三个特征:封装,继承,多态

继承

我们在类中,如果需要写一些重复的成员,我们可以将这些重复的成员单独封装到一个类中,作为子类的父类;

父类也可叫做基类

子类也可叫做派生类

子类继承了父类的属性和方法,但是并没有继承父类的私有字段。
子类并没有继承了父类的构造函数。但是子类会默认的调用父类无参数的构造函数,用于创建父类对象,让子类可以使用父类中的成员。如果在父类中重写了一个有参数的构造函数之后,那个无参数的就被干掉了,子类无法调用,会报错。

解决办法:
1、在父类中重新写一个无参的构造函数
2、在子类中显示的调用父类的构造函数,使用关键字:base()

父类构造函数,

        public Person(string name ,int age ,char gender)
       {
            this.Age = age;
            this.Name = name;
            this.Gender = gender;
        }

子类构造函数

 public Student(string name,int age,char gender,int id)
               :base(name,age,gender)// 使用关键字调用父类的有参构造函数
        {
            this.Id = id;//只需要赋值id即可,其余的在父类的构造函数中已经实现了

        }
继承的特性:

1、继承的单根性:一个子类只能有一个父类
2、继承的传递性

父类
    class Person
    {
        private string _name;
        private int _age;
        private char _gender;

        public string Name { get => _name; set => _name = value; }
        public int Age { get => _age; set => _age = value; }
        public char Gender { get => _gender; set => _gender = value; }

        public void CHLSS()
        {
            Console.WriteLine("吃喝拉撒睡");
        }
    }
子类
class Student:Person
    {
        private int _id;
        public int Id { get => _id; set => _id = value; }
        public void Study()
        {
            Console.WriteLine("学生会学习");
        }


    }

继承于student,拥有student的方法属性。因为student继承与person,所以teacher也拥有person 的方法属性

    class Teacher:Student
    {
        private double _salary;
      public double Salary { get => _salary; set => _salary = value; }
        public void Tech()
        {
            Console.WriteLine("老师会教书");
        }
    }

object是所有类的基类

new关键字

1、创建对象
2、隐藏从父类哪里集成过来的同名成员。
隐藏的后果就是调用不到父类的同名成员。

父类中有 sayhello方法

class Programer:Person
    {
        public Programer(string name,int age,char gender,int workyear)
            :base(age,name,gender)
        {
            this.Workyear = workyear;
        }
        private int _workyear;

        public int Workyear { get => _workyear; set => _workyear = value; }

        public void ProgramerSayHello()
        {
            Console.WriteLine($"我叫{this.Name},我是一名程序员,,我是{this.Gender}生,我今年{this.Age}岁,我的工作年限是{this.Workyear}年");
        }
        public new void SayHello()
        {
            Console.WriteLine("大家好!我是记者。");
        }
    }

子类中有同名成员,此时代码编译能通过但是会有下划线提示错误,加上new关键字可以隐藏父类中的同名方法,不再报错

    class Programer:Person
    {
        public Programer(string name,int age,char gender,int workyear)
            :base(age,name,gender)
        {
            this.Workyear = workyear;
        }
        private int _workyear;

        public int Workyear { get => _workyear; set => _workyear = value; }

        public void ProgramerSayHello()
        {
            Console.WriteLine($"我叫{this.Name},我是一名程序员,,我是{this.Gender}生,我今年{this.Age}岁,我的工作年限是{this.Workyear}年");
        }
        public new void SayHello()//使用new关键字隐藏父类的同名成员
        {
            Console.WriteLine("大家好!我是记者。");
        }
    }

里氏转换

定义:
1、子类可以复制给父类

// 子类可以赋值给父类
 Student s = new Student();
Person p = s;

2、如果父类中装的是子类对象,那么可以将父类强转为子类对象

// 子类可以赋值给父类
//person是student的父类
Student s = new Student();
Person p = new Student();

//如果父类中装的是子类对象,那么可以将父类强转为子类对象
Student ss = (Student)p;
ss.StudentSayHello();

子类对象可以调用父类对象的成员,父类对象不能调用子类对象的成员。

3、
is:表示类型转换,如果能够转换成功,则返回一个true,否则返回false

//is的用法
if (p is Student)
{
    Student ss = (Student)p;
    ss.StudentSayHello();
}
else
{
    Console.WriteLine("转换失败");
}

as:表示类型转换,如果能够转换则返回对应的对象,否则返回一个null

//as的用法
Student t = p as Student;

Protected修饰符

受保护的:可以在当前类的内部以及该类的子类中访问。

ArrayList集合的长度问题

每次集合中实际包含的元素个数(count),超过了可以包含的元素个数(capcity)的时候,集合就会向内存中申请多一倍的空间,来保证集合的长度一直够用。

hashrable集合(键值对集合)

在键值对集合当中,我们是根据键去找值的。
键值对象[键]=值;
键值对集合中,键只能是唯一的但是值可以是重复的。
1、ContainsKey(键名);判断是否有指定键名,返回值为bool
2、ContainsValue(键值);判断是否有指定键值,返回值为bool
3、Remove(键名);移除指定键名所对应的元素
4、Clear();清空集合中的所有元素

   Hashtable ht = new Hashtable();
   ht.Add(1, "张三");
   ht.Add(2,true);
   ht.Add(false, "错误的");
    ht[1]=250;//这也是一种添加数据的方式
    if (ht.ContainsKey(true))
      {
           Console.WriteLine("已经包含true这个键了");
      }
      if (ht.ContainsValue("张三"))
      {
           Console.WriteLine("已经包含张三这个键值了");
      }
    ht.Clear();//清空集合内所有的元素
    ht.Remove(false);//移除键名为false元素

   //在键值对集合中是根据键去找值
   //ht.Keys 键的集合
   //ht.Values值的集合
    //循环打印对应键的值
   foreach (var item in ht.Keys)
   {
       Console.WriteLine($"键是==={item};值是==={ht[item]}");
   }

c#:强类型语言。在代码中必须多每一个变量类型有一个明确的定义

foreach循环

static void Main(string[] args)
        {
            int[] nums = { 1, 2, 3, 5, 6, 3, 2, 3, 2, 1, 5, 2 };
            for (int i = 0; i < nums.Length; i++)
            {
                Console.WriteLine(nums[i]);
            }
            Console.WriteLine("=============");
            foreach (var item in nums)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();


        }

简体字转繁体字

//将用户输入的简体字转为繁体字

 class Program
    {
        private const string jian = "啊飞好就看了我饿人他才";//简体字集合
        private const string fan = "123就看了我饿人他才";//繁体字集合

        static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            for (int i = 0; i < jian.Length; i++)
            {
                ht.Add(jian[i], fan[i]);
            }
            Console.WriteLine("请随便输入");
            string input = Console.ReadLine();
            for (int i = 0; i < input.Length; i++)
            {
                if (ht.ContainsKey(input[i]))
                {
                    Console.WriteLine(ht[input[i]]);
                }
                else
                {
                    Console.WriteLine(input[i]);
                }
            }
            Console.ReadKey();

        }
    }

patch类,

patch是一个静态类,不需要创建对象, 直接类名.方法名即可
1、Patch.GetFileNmae();//获取文件名以及扩展名
2、Path.GetFileNameWithoutExtension(str);//获取文件名
3、Path.GetFullPath(str);//获取文件绝对路径
4、Path.GetExtension(str);//获取文件的扩展名
5、Path.GetDirectoryName(str);//获取文件的目录信息
6、Console.WriteLine(Path.Combine(@”c:\a\c”,”b.txt”));连接两个字符串作为路径

            string str = @"e:\Users\Lenovo\Desktop\start.wav";
            //获取文件名
            Console.WriteLine(Path.GetFileNameWithoutExtension(str));
            //获取文件全路径
            Console.WriteLine(Path.GetFullPath(str));
            //获取文件扩展名
            Console.WriteLine(Path.GetExtension(str));

            //获取文件路径
            Console.WriteLine(Path.GetDirectoryName(str));
            //获取文件名称以及扩展名
            Console.WriteLine(Path.GetFileName(str));
            //连接两个字符串作为路径
            Console.WriteLine(Path.Combine(@"c:\a\c","b.txt"));
            Console.ReadKey();

File类

File是一个静态类,不需要创建对象, 直接类名.方法名即可
1、File.Create(path);//创建文件
2、File.Copy(path);//复制文件
3、File.Delete(path);//删除文件
4、File.Move(path);//移动文件
5、File.Exists(path);//检查文件是否存在 返回bool

            //创建文件
            File.Create( @"e:\Users\Lenovo\Desktop\start.txt");
            //复制文件
            File.Copy(@"e:\Users\Lenovo\Desktop\start.wav", @"e:\Users\Lenovo\Desktop\start.zip");
            //删除文件
            File.Delete(@"e:\Users\Lenovo\Desktop\start - 副本.wav");
            //移动文件
            File.Move(@"e:\Users\Lenovo\Desktop\start.wav", @"d:\start.wav");
            //检查指定文件是否存在,返回bool
            File.Exists(@"e:\Users\Lenovo\Desktop\start.txt");

6、File.ReadAllBytes(path);//打开一个二进制文件,读入到字节数组中,然后关闭文件

        byte[] buffer = File.ReadAllBytes(@"e:\Users\Lenovo\Desktop\start.txt");
        //将字节数组中的每一个元素都按照编码格式解码成字符串
        string s = Encoding.GetEncoding("UTF-8").GetString(buffer);
        Console.WriteLine(s);
        Console.ReadKey();

7、File.WriteAllBytes(path,buffer);//以字节数组的方式写入文件,文件如果不存在则创建,若存在则覆盖

            //写入文件,如果文件存在则覆盖没有则创建
            string str = "今天天气不错";
            byte[] buffer = Encoding.Default.GetBytes(str);
            File.WriteAllBytes(@"e:\Users\Lenovo\Desktop\test.txt",buffer);

8、 File.ReadAllText读取所有文本 File.ReadAllLines读取所有行

            string str = "今天天气不错";
            byte[] buffer = Encoding.Default.GetBytes(str);
            File.WriteAllBytes(@"e:\Users\Lenovo\Desktop\test.txt", buffer);
            string str1 = File.ReadAllText(@"e:\Users\Lenovo\Desktop\test.txt",Encoding.Default);
            Console.WriteLine(str1);
            string[] contens = File.ReadAllLines(@"e:\Users\Lenovo\Desktop\test.txt",Encoding.Default);
            foreach (var item in contens)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();

9、 File.WriteAllLines:以行的形式写入文件,写入一个字符串就换一行
File.WriteAllText:以文本的形式写入文件
两个方法都会覆盖原本的类型

File.WriteAllLines(@"e:\Users\Lenovo\Desktop\start.txt",new string[] { "aoe","ewu"});
 File.WriteAllText(@"e:\Users\Lenovo\Desktop\start.txt","你好,世界!");

10、File.AppendAllText 追加写入文件,不会覆盖原本的类容

File.AppendAllText(@"e:\Users\Lenovo\Desktop\start.txt", "你好,世界!");

相对路径与绝对路径

绝对路径:通过给定的这个路径直接能在我的电脑中找到这个文件。
相对路径:文件相对于应用程序的路径。
结论:
在开发过程中尽量使用相对路径。

装箱、拆箱

装箱:就是将值类型转换为引用类型。
拆箱:将引用类型转换为值类型。

FileStream(文件流)

读取数据:

            //FileStream
            //1、创建FileStream对象
            //==========================读取数据
            FileStream fs = new FileStream(@"e:\Users\Lenovo\Desktop\start.txt",FileMode.OpenOrCreate,FileAccess.Read);
            byte[] buffer = new byte[1024 * 1024*5];//声明字节数组,并设置大小为5
            // 读取的返回数据字节数组,存放数据的首地址,最多读取的数量
            //r为读取的实际字节数
            int r= fs.Read(buffer,0,buffer.Length);
            //将字节数组中每一个元素按照指定的编码格式解码成字符串(需要按转换的字节数组,开始转换的序号,转换个数)
            string s = Encoding.UTF8.GetString(buffer,0,r);
            //关闭流,
            fs.Close();
            //释放流所占用的资源
            fs.Dispose();
            Console.WriteLine(s);
            Console.ReadKey();
        }

上面可以看到,我们在使用完成后需要关闭文件流和手动释放文件资源。这对我们来说很不习惯,还有另一种方法就是将创建文件流对象的过程写在using当中,会自动的帮助我们释放流所占用的资源。

            //使用filestream写入数据
            using (FileStream fsWrite=new FileStream(@"e:\Users\Lenovo\Desktop\start.txt", FileMode.OpenOrCreate, FileAccess.Write))
            {
                string str = "你好,义昆!";
                byte[] buffer = Encoding.UTF8.GetBytes(str);
                fsWrite.Write(buffer, 0, buffer.Length);
            }

StreamReader读取文本文件

        static void Main(string[] args)
        {
            //使用StreamReader来读取文件
            using (StreamReader sr = new StreamReader(@"e:\Users\Lenovo\Desktop\start.txt"))
            {
                while(!sr.EndOfStream)//没有读取到最后一行,就一直循环读取
                {
                    Console.WriteLine(sr.ReadLine());
                }
                Console.ReadKey();
            }
        }

StreamWriter写入文本文件

            //使用StreamWrter写入文本文件
            ////(路径 ,是否追加)
            using (StreamWriter sw = new StreamWriter(@"e:\Users\Lenovo\Desktop\start1.txt",true))
            {
                sw.Write("今天天气不错");
            }