第二周——C#学习-编程语言基础相关

一、万物皆Object:

  1. 自定义类怎样继承自Object,源于编译器的自动添加继承声明
以下代码作用完全一致
public class A {}
public class A : Object {}
  1. 有关类型转换:
  • try……catch固然方便常用,但每次处理会新建异常堆栈,影响性能。
  • .NET中提供了类型之间的判断和转换方法,不会抛出异常。(as、is)
    – is:检查两类型是否兼容,返回true/false
    在这里插入图片描述

– as:as 不仅负责检查兼容性还会进行类型转换,并返回结果,如果不兼容则null
介绍

  • 实际操作代码
using System;
public class test
{
//学生类
    public class Student
    {
        public string Name
        {
            set;get;
        }
        //重写ToString()方法
        public override string ToString()
        {
            return $"name:{Name}";
        }
    }
    public static void Main()
    {
        Student student = new Student();
        student.Name = "xiaoming";
        if (student is Object)	//判断是否兼容
        {
            Object o = student as Object;	//判断兼容并返回对象或null
            Console.WriteLine(o.ToString());
        }
        else Console.WriteLine(false);
    }
}

在这里插入图片描述

二、值类型与引用类型

  1. 无论值类型/引用类型皆继承自System.Object,区别在于值类型继承自System.Object.ValueType。(恰好值类型又将Object.Equal()方法重写为值比较,引出Equal、== 、ReferenceEqual()、===、的区别)
  • 由此引出拆箱封箱的概念。
  • 封箱与拆箱涉及了堆与栈的来回复制移动,影响性能,编程原则就是避免任何没必要的装箱拆箱操作。代码中提供两种解决方式。
public void Method(){
int i = 4;
object O = i;	//装箱操作
int j = (int) O;	//拆箱操作
//1、值类型的格式化输出,此处重写了Object中的虚方法ToString(),不会出现类型转换。
int i = 10;
Console.WirteLine("Value is {0}",i.ToString());
//2、利用泛型避免大规模的装箱拆箱。
ArrayList arrList = new ArrayList();	//内部实现是将对象当作object来对待,隐含了装箱拆箱操作。
arrList.Add(0);
arrList.Add("1");
// 使用泛型数据结构代替ArrayList,提高性能。
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
}

一)传参方式

  1. 由此再学习C#中三种传递参数的方式:
  • ref关键字:要求参数在传入前被初始化;
    错误案例
  • out关键字:要求参数在方法返回前被初始化;
    错误案例
  • params关键字:允许方法在定义时不确定参数的数量,但params参数后不允许再有其他任何参数
    错误案例

二)深拷贝与浅拷贝

  1. 传参涉及了拷贝,由此延申深拷贝与浅拷贝,实际区别体现在引用类型中。
    -1. .NET中,基类Object为所有类型实现浅拷贝。
    -2. System.Object.MemberWiseClone();方法为浅拷贝
    -3. 深拷贝的实现:

1、依次实例化新的对象并赋予相同的值。
2、利用序列化/反序列化来对对象进行深度复制

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace System
{
    [Serializable]
    public class DeepCopy : ICloneable
    {
        public object Clone()
        {
        //序列化反序列化具体实现
        	 //以简单的二进制数据流以及某些附加的类型信息,实现持久化。XmlSerializer( );
            BinaryFormatter bf = new BinaryFormatter();
            //创建内存流ms
            MemoryStream ms = new MemoryStream();
            //将this=>DeepCopy类序列化入内存流ms
            bf.Serialize(ms, this);
            //将ms存入流中的0位置。
            ms.Position = 0;
            //反序列化得到的是object对象
            return bf.Deserialize(ms);
        }

    }
    public class Program
    {
        static void Main()
        {
            //创建实例
            DeepCopy copy = new DeepCopy();
             //实例调用方法,通过序列化反序列化深拷贝操作
            DeepCopy deepCopy =(DeepCopy)copy.Clone();
            //浅拷贝操作 
            DeepCopy shadowCopy = copy; 
           Console.WriteLine("原对象哈希码:{0}", copy.GetHashCode());
            Console.WriteLine("浅拷贝对象哈希码:{0} 浅拷贝引用比较:{1}", shadowCopy.GetHashCode(),Object.ReferenceEquals(copy,shadowCopy));
            Console.WriteLine("深拷贝对象哈希码:{0} 深拷贝引用比较:{1}", deepCopy.GetHashCode(), Object.ReferenceEquals(copy, deepCopy));
        }
    }
}

结果

三)堆栈、托管堆、非托管堆、GC

  1. 类型的存储总要存入堆或栈中,.NET开辟三块内存作为 堆栈、托管堆、非托管堆
  • 堆栈:存储值类型的对象和引用类型的引用
  • 托管堆:也是连续的,还存在着暂时不能被分配但已无用的对象内存块,当内存不够时才进行GC机制。GC不仅仅释放资源,还负责移动合并内存块。~Object();(Finalize,非实时释放资源;)
  • 非托管堆:无法合并移动,所以不连续分布。非.NET托管,需程序员手动分配和释放。Dispose();(操作系统资源的对象、文件流、数据库连接等属于非托管资源)
  1. GC(Garbage Collect)垃圾回收机制
  • 清理托管堆上不会再被使用的对象内存,并且移动仍在被使用的对象使它们紧靠托管堆的一边。
  • Finalize(~Object())的机制:
  1. NET将每个带有Finalize的对象引用添加到一个“带析构表”。
  2. GC检测到不被使用的对象时,进一步检查带析构表。无则认为垃圾,有则入“待析构表”。
  3. CLR一个单独线程处理“待析构表”,就是调用Finalize方法。
  4. 下个GC执行时,将释放已调用Finalize方法的对象实例和垃圾。

三、特殊的String

一)StringBuilder

  1. 内部以字符数组char[ ]为基础维护一个链表来进行操作。

二)字符串常量池(字符串驻留池)

  1. 字符串常量池机制:
  • 当一个新的字符串对象需要分配时,CLR首先监测内部容器中是否已经存在该字符串对象。
  • 如果已经包含则直接返回已经存在的字符串对象引用
  • 如果不存在,则新分配一个字符串对象,同时把其添加到内部容器中。
  • new申请新的分配空间,所以该机制不会有作用。
    class Program
    {
        static void Main(string[] args)
        {
            // 1.两个字符串对象,理论上引用应该不相等
            // 但是由于字符串池机制,二者指向了同一对象
            string a = "abcde";
            string b = "abcde";
            Console.WriteLine("a=b(引用)?{0}", Object.ReferenceEquals(a, b));
            // 2.由于编译器的优化,所以下面这个c仍然指向了同一引用地址
            string c = "a" + "bc" + "de";
            Console.WriteLine("a=c(引用)?{0}", Object.ReferenceEquals(a, c));
            // 3.显示地使用new来分配内存,这时候字符串池不起作用
            char[] arr = { 'a', 'b', 'c', 'd', 'e' };
            string d = new string(arr);
            Console.WriteLine("a=d(引用)?{0}", Object.ReferenceEquals(a, d));

            Console.ReadKey();
        }
    }

结果

四、数组

一)数组的类型

无论存储值类型或引用类型,其本身都是引用类型。
在这里插入图片描述

二)数组的转换

  1. 数组直接转换的条件
  • 包含值类型的数组不能被隐式转换成其他任何类型;
  • 两个数组类型能够相互转换的一个前提是两者维数相同
    在这里插入图片描述
 //
        // 摘要:
        //     将一种类型的数组转换为另一种类型的数组。
        // 参数:
        //   array:
        //     要转换为目标类型的从零开始的一维 System.Array。
        //   converter:
        //     用于将每个元素从一种类型转换为另一种类型的 System.Converter`2。
        // 类型参数:
        //   TInput:
        //     源数组元素的类型。
        //   TOutput:
        //     目标数组元素的类型。
        // 返回结果:
        //     目标类型的数组,包含从源数组转换而来的元素。
        // 异常:
        //   T:System.ArgumentNullException:
        //     array 为 null。 - 或 - converter 为 null。
        public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter);
  • 只需指定原数组的类型对象数组的类型和具体的转换算法
 class Program
    {
        static void Main(string[] args)
        {
        int[] sz = { 1, 2, 3 };
            object[] o = Array.ConvertAll(sz, new Converter<int, object>(IntToObject));
            Console.WriteLine("sz的类型:{0},o的类型:{1}",sz.GetType().ToString(),o.GetType().ToString());

        }
        public static object  IntToObject(int temp)
        {
            return (object)temp;
        }
    }

在这里插入图片描述

五、面向对象编程

一)父类子类构造顺序

public class Program
    {
        public static void Main(string[] args)
        {
            // 构造了一个最底层的子类类型实例
            C newObj = new C();
            Console.ReadKey();
        }
    }

    // 基类类型
    public class Base
    {
        public Ref baseString = new Ref("Base 初始化表达式");
        public Base()
        {
            Console.WriteLine("Base 构造方法");
        }
    }

    // 继承基类
    public class A : Base
    {
        public Ref aString = new Ref("A 初始化表达式");
        public A():base()	//显示调用父类的无参构造
        {
            Console.WriteLine("A 构造方法");
        }
    }

    // 继承A
    public class B : A
    {
        public Ref bString = new Ref("B 初始化表达式");
        public B()	//隐式调用父类的无参构造
        {
            Console.WriteLine("B 构造方法");
        }
    }

    // 继承B
    public class C : B
    {
        public Ref cString = new Ref("C 初始化表达式");
        public C()
        {
            Console.WriteLine("C 构造方法");
        }
    }

    // 一个简单的引用类型
    public class Ref
    {
        public Ref(string str)
        {
            Console.WriteLine(str);
        }
    }

结果
在这里插入图片描述

二)基本特性

1、封装

public class test
{
    public class Student
    {
        //C#1中,调用构造函数和方法
        int sno;
        public int Sno { get { return sno; } }
        public Student(int sno) { this.sno = sno; }
        //C#2私有赋值方法
        string name;
        public string Name
        {
            private  set { name = value; }
            get { return name; }
        }
        //C#3中自动实现了属性,是代码更为简单。
        public int Age { set; get; }
    }
}

2、继承

  • 减少复用,is-a的关系(Bird is a Animal),解决复用,子类(Birds)可实现父类(Animal)的Sleep、Eat和自己的Fly,父类有的子类都有。
    在这里插入图片描述
  • 里氏替换
public class test
{
    public class Animal{ }
    public class Birds : Animal{ }
    public static void Main()
    {
        //里氏替换:子类对象可以代替父类对象。
        Animal animal = new Birds();
        //反之不行,系统报错无法转换。
        Animal animal1 = new Animal();
        if (animal1 as Birds == null)
        {
            Console.WriteLine("Birds birds = new Animal();转换失败。\r\n");
        }
        else Console.WriteLine("Birds birds = new Animal();转换成功。\r\n");
        //可以把  指向子类对象的父类变量  转换为  子类对象。
        if (animal as Birds == null)
        {
            Console.WriteLine("Birds birds = (Birds)animal;转换失败。");
        }
        else Console.WriteLine("Animal animal = new Birds();\r\nBirds birds = (Birds)animal;转换成功。");
    }
}

在这里插入图片描述

  • 堆栈的展示:
    在这里插入图片描述

3、多态

① 方法多态性
  • 重写、重载、隐藏
  1. 重写:子类用Override关键字重新实现定义在基类中的虚方法,并且在实际运行时根据对象类型来调用相应的方法。
  2. 隐藏:子类用new关键字重新实现定义在基类中的方法,但在实际运行时只能根据引用来调用相应的方法。其作用个人理解就是子类对父类的方法扩展私有化,不能被父类的引用变量调用,只能自己的引用变量才能调用。
    public class Father
    {
        public virtual void Say()
        {
            Console.WriteLine("I am Father."); 
        }
    }
    public class Son : Father
    {
        //new关键字
        public new void Say()
        {
            Console.WriteLine("new关键字方法:I am Son.");
        }
        //override关键字
        /*public override void Say()
        {
            Console.WriteLine("override关键方法:I am Son.");
        }*/
        
    }
    public static void Main()
    {
        Father father = new Son();
        father.Say();
    }

override关键字结果:调用子类的重写方法。根据对象类型来调用。
在这里插入图片描述
new关键字结果:隐藏了子类特有方法,调用父类的虚方法。根据引用类型来调用。
在这里插入图片描述

  1. 重载:拥有相同名字和返回值的方法却拥有不同的参数列表,实现多态。
② 对象多态性
③ 抽象
  1. 抽象类:
  • 子类必须实现抽象类中的 抽象方法
    在这里插入图片描述
  • 抽象方法不能有方法体,因为要依靠子类实现。
    在这里插入图片描述
  • 对于非抽象方法:1、可以通过子类实例来调用。2、可以通过虚函数让子类重写或隐藏。
    在这里插入图片描述
  • 抽象类中可以定义方法的具体实现,调用方法如下:
public class test
{
    public abstract class Animal
    {
    	public abstract void Eat();
        public void Walk(string name) { Console.WriteLine("I am {0},I am walking.", name); }
    }
    public class Cat : Animal
    {
        public override void Eat()      //override
        {
            Console.WriteLine("I am Cat,I eat fish.");
        }
    }
    public static void Main()
    {
        Cat cat = new Cat();
        cat.Eat();		//调用子类实现的抽象方法
        cat.Walk("Cat");  //调用抽象类中已实现的方法

    }

在这里插入图片描述
2. 接口类:

  • 接口的子类必须全部实现接口类方法和属性。
    在这里插入图片描述
  • 实现多接口继承:
public class test
{
    public interface  PaxingAnimal   //爬行动物
    {
        void Walk();
    }
    public interface MiaoAnimal     //猫科动物
    {
        void Voice();
    }
    public class Cat : MiaoAnimal,PaxingAnimal
    {
        public void Walk() { Console.WriteLine("I am a Cat, I am walking."); }
        public void Voice() { Console.WriteLine("I am a Cat, Miao~~~."); }
    }
    public static void Main()
    {
        Cat cat = new Cat();
        cat.Walk();
        cat.Voice();

    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值