首页 > 编程语言 >C#相关基础知识

C#相关基础知识

时间:2023-02-12 11:57:24浏览次数:45  
标签:重写 C# 子类 接口 基础知识 相关 抽象类 父类 方法

面向对象

1. 面向对象和面向过程

面向过程:具体的,流程化的,解决一个问题,需要一步一步的分析,一步一步的实现;(怎么做)

面向对象:型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,不用关心,会用就可以了。(谁来做,我们只实例化来用)

   面向对象的底层其实还是面向过程,把面向过程抽象成类,然后进行封装,方便我们使用。

2. 相关概念

类:类是一个模板,描述了一个对象的属性和方法

对象:对象是类的一个实例,存在属性和行为。

构造方法:定义在Java中的一个用来初始化对象的方法。

      ①使用new+构造方法 创建一个新的对象。

      ②名称与类名相同且没有返回值。

      ③当没有指定构造方法时,系统会自动添加无参的构造方法。

      ④当有指定构造方法时,无论是有参、无参的构造方法,都不会自动添加无参的构造方法。

      ⑤构造方法可重载:方法名相同,但参数不同,调用时会自动根据不同的参数选择相应的方法。 

      ⑥构造方法不但可以给对象的属性赋值,还可以保证给对象的属性赋一个合理的值(在构造函数中增加判断)。

静态方法:静态方法可以直接调用同类中的静态成员,可以创建类的对象,通过对象访问非静态对象。而非静态方法可以访问类的静态成员,也可以访问类的非静态成员。

  静态方法的调用有两种途径:(1)通过类的实例对象去调用(调用格式为: 对象名.方法名)(2) 通过类名直接调用(调用格式为: 类名.方法名)

  静态方法的好处是不用生成类的实例就可以直接调用,通过类名就可以访问,不需要再消耗资源反复创建对象。在类的第一次加载的时候,static就存在内存中了,直到程序结束后,该内存才会释放。如果不是static修饰的成员函数,在使用完之后就会立即被JVM回收。所以静态类会一直占用内存,访问速度较快。因此静态类不能太大太占用资源。

修饰符的访问范围:

  ①private:只能在本类中访问和使用。

  ②默认:能在本类和同包中访问和使用。

  ③protected:能在本类、同包、子类中使用。

  ④public:在本类、同包、子类、其它类中使用。

this关键字:

  用在实例方法中,指向自身,代表当前对象

    this.属性:操作当前对象的属性

    this.方法:调用当前对象的方法

    “this.”大部分情况下可以省略,但在区分局部变量和实例变量的时候不能省略。

  this不能再静态方法中使用,this代表当前对象,而静态方法中不存在当前对象。

  this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的构造方法,目的是代码复用。

面向对象三大特性

1、封装:

  将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法类实现对隐藏信息的操作和访问。隐藏类的实现细节,方便修改和实现,提高复用性和安全性。

  实现步骤:

① 修改属性的可见性:设为private

② 创建getter/setter方法:用于属性的读写

③ 在getter/setter方法中加入属性控制语句:对属性值的合法性进行判断

2、继承:

子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,子类更加具体,拥有父类的特征和自身的特征,但不能继承父类中private修饰的属性和方法。

子类可以重写父类的方法:

① 子类可重写从父类继承的方法,当调用方法时会优先调用子类的方法。

② 返回值类型、方法名、参数类型及个数 都要与父类继承的方法相同,才叫方法的重写。

super关键字:

  super可以理解为父类,我们可以在子类的方法或构造器中,通过使用“super.属性”或“super.方法”的方式,显示调用父类中声明的属性和方法,但通常情况下,我们习惯省略super。但在父类和子类定义了同名的属性以及子类重写了父类的方法时,若想调用父类的属性和方法,必须显示使用super的方式。

final关键字

  ① 可修饰类、方法、属性和变量

  ② final修饰类,则该类不允许被继承

  ③ final修饰方法,则该方法不允许被重写

  ④ final修饰属性,则该类的属性不会进行隐式初始化(类的初始化属性必须有值)或在构造方法中赋值(只能任选其一)

  ⑤ final修饰变量,则该变量的值只能赋一次值,即变为常量

3、多态

为不同数据类型的实体提供统一的接口。多态意指相同的消息给予不同的对象会引发不同的动作。(去完成某个行为,当不同的对象去完成时会产生出不同的状态。“一个接口,多个功能”)

  多态前提是继承,子类必须重写(override)父类的方法(虚函数:被virtual修饰的类成员函数),使用父类的类型。

子类对象转换为父类对象(此处的父类对象可以是接口或抽象类):向上转型 Animal animal = new Cat();  转换后的父类对象具有父类所有的方法,若方法被子类重写,那么实际在调用时,调用的是重写之后的实现。

父类对象转换为子类对象:向下转型 Cat cat = (Cat) animal; 转换后的子类对象和一般的继承子类对象一样,具有子类所有的方法(包括重写方法)+父类所有的方法(被重写的方法按重写算。)

继承和多态:

继承是子类使用父类的方法: Son son = new Son(); son.isFather();(isFather是父类中的方法。)

多态是父类使用子类的方法: Father father = new Son(); father.getSon();(getSon是子类重写父类的方法。)

重写(override)和重载(overload)

重写:子类对父类的方法的实现过程进行重新编写,返回值和形参都不能改变。(子类重写的方法必须和父类保持完全一致)。重写的好处在于子类可以根据需要,定义特定于自己的行为,可根据需要实现父类的方法。

若需要在子类中调用父类被重写的方法时要使用super关键字。super.getSon();

构造方法、private方法和final方法不能被重写。

重载:在一个类里面,方法名字相同而参数不同,返回类型可以相同也可以不同。(重载只能通过参数类型和参数个数来区分)。重载的好处是让类以统一的方式处理不同类型。调用方法时通过传递给他们的不同个数和类型的参数来决定具体使用哪个方法,这就是多态性。

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

抽象方法(abstract)和虚方法(virtual)

抽象方法是指定义在抽象类中的方法,需要在子类中被实现的方法。

虚方法是指可以被子类重写的方法。

抽象方法:只有方法名,没有方法体,方法名前用abstract关键字定义,必须在抽象类中声明,子类必须重写并实现父类中的抽象方法。

abstract public void eat();

虚方法:有方法名和方法体,方法名前用virtual关键字定义,并不是必须在抽象类中声明,可以在任何非密封类中声明,但是当子类继承了父类后,存在于父类中的虚方法可以被重写,也可以不被重写。

public void eat(){Console.WriteLine("动物吃东西")};

抽象类

一个类中如果有抽象方法,那么这个类就是抽象类。

public abstract class Animal{//抽象类
    public abstract void eat(); //抽象方法,没有方法体,没有大括号
}

 但抽象类中可以没有抽象方法,也可以包含普通的方法。抽象类不能被实例化,其非抽象子类继承该抽象类后必须重写该抽象类中的抽象方法,且此非抽象子类可以被实例化。

 接口(interface)

接口是指定一组函数成员而不实现成员的引用类型,提供一个标准的入口供后续子孙继承使用。

接口是虚的,不能被实例化,一个接口不能实现另一个接口,但它可以继承多个其它接口。子接口可以对父接口的方法和常量进行重写。

一个类可以实现(implements)一个或者多个接口,该类必须重写这些接口中的抽象方法。否则该类必须定义成抽象类。

public interface Animal{
    public void fly();
    public void sleep();
}
public class Cat implements Animal{
    public void fly(){
        Console.WriterLine("不能飞");
    }
    public void sleep(){
        Console.WriterLine("睡很久");
    }
}

接口可以理解为一个特殊的类,由全局常量和公共的抽象方法所组成。

类是一种具体的实现体,而接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部数据,也不关心这些类里方法的实现细节,它只规定这些类里必须提供某些方法。

 对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

 接口和类的区别:

不同点:

  1、接口不能实例化

  2、接口不包含方法的实现

  3、接口可以多继承而类只能单继承 

  4、类定义可以在不同的源文件之间实现

相同点:

  1、接口、类和结构都可以从多个接口继承

  2、接口类似于抽象类(继承接口的任何非抽象类都必须实现接口的所有成员)

  3、接口和类都包含事件、索引器和属性

 抽象类和接口的区别

相同点:

  1、都可以被继承

  2、都不能被实例化

  3、都可以包含方法声明

  4、派生类必须实现未实现的方法

不同的:

  1、抽象基类可以定义字段、属性、方法实现;接口只能定义属性、索引器、事件和方法声明,不能包含字段。

  2、抽象类是一个不完整的类,需要进一步细化;接口是一个行为规范。

  3、接口可以被多重实现,抽象类只能被单一继承。

  4、抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中。

  5、抽象类是从一系列相关对象中抽象出来的概念,因此反映的是事物的内部共性;接口是为了满足外调而定义的一个功能约定,因此反映的是事物的外部特性。

  6、接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法。

  7、接口可以用于支持回调,而继承并不具备这个特点。

  8、抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然也可以声明为虚的。

  9、如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。

 委托和事件:

(百度:   https://baike.baidu.com/item/c%23%E5%A7%94%E6%89%98/6916387?fromtitle=%E5%A7%94%E6%89%98c%23&fromid=16784307&fr=aladdin)

(菜鸟教程:https://www.runoob.com/csharp/csharp-delegate.html

  委托(delegate)允许传递类A的方法M给类B的对象,使得类B的对象能够调用这个方法M,可以把方法当作参数传递。

委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。

例如需要传入的方法为public void MyName(string name);

则定义的委托为public delegate void PersonNameDelegate(string name);

一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。

(百度例子)

using System;
using System.Collections.Generic;
using System.Text;
namespace Delegate
{
    //定义委托,它定义了可以代表的方法的类型
    public delegate void GreetingDelegate(string name);
    class Program
    {
        private static void EnglishGreeting(string name)
        {
            Console.WriteLine("Morning, " + name);
        }
        private static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好, " + name);
        }
        //注意此方法,它接受一个GreetingDelegate类型的参数,该参数是返回值为空,参数为string类型的方法
        private static void GreetPeople(string name, GreetingDelegate MakeGreeting)
        {
            MakeGreeting(name);
        }
        static void Main(string[] args)
        {
            GreetPeople("Jimmy Zhang", EnglishGreeting);
            GreetPeople("张子阳", ChineseGreeting);
            Console.ReadKey();  //Morning, Jimmy Zhang  早上好, 张子阳
        }
    }
}

  委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数地做法,可以避免在程序中大量使用if-else(switch)语句,同时使得程序具有更好地可扩展性。

C#内置委托

(1)Action委托

Action委托用于指向没有返回值的方法

Action action = new Action(Hello);private void Hello(){Console.WriteLine("Hello");}

Action<T> 委托用于指向没有返回值,有一个T类型的参数 的方法。

Action<string> action = new Action<string>(Hello);private void Hello(string name){Console.WriteLine("Hello, "+ name);}

Action<T1, T2> 委托用于指向没有返回值,有两个类型分别为T1, T2的参数 的方法。

以此类推。

(2)Func委托

Func 委托用于指向含有返回值的方法。

Func<TResult> 委托用于指向有TResult类型的返回值,没有参数的方法。

Func<int> func = new Func<int>(GetSum);private int GetSum(){return 0;}

Func<TResult, T1> 委托用于指向有TResult类型的返回值,有一个T1类型的参数 的方法。

Func<int, int> func = new Func<int, int>(GetSum);
private int GetSum(int stop)
{
    int sum = 0;
    for (int i = 1; i <= stop; i++)
    {
        sum += i;
    }
    return sum;
}

Func<TResult, T1, T2> 委托用于指向有TResult类型的返回值,有两个类型分别为T1, T2的参数 的方法。

以此类推。

使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时,可以依次调用所有绑定的方法。

static void Main(string[] args)
{
    GreetingDelegate delegate = new GreetingDelegate(EnglishGreeting);
    delegate += ChineseGreeting; // 给此委托变量再绑定一个方法
    // 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
    GreetPeople("Jimmy Zhang", delegate);
    Console.WriteLine();
    delegate -= EnglishGreeting; //取消对EnglishGreeting方法的绑定
    // 将仅调用 ChineseGreeting
    GreetPeople("张子阳", delegate);
    Console.ReadKey();
}  // Morning, Jimmy Zhang 早上好, Jimmy Zhang 早上好, 张子阳

Even封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。

声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。声明事件后绑定方法不能使用 = ,只能使用 += 和 -= ,这是为了防止客户端使用了=而把之前的委托的方法全部取消。

在类的内部声明事件,首先必须声明该事件的委托类型。public delegate void BoilerLogHandler(string status);

然后,声明事件本身,使用 event 关键字:public event BoilerLogHandler BoilerEventLog;

标签:重写,C#,子类,接口,基础知识,相关,抽象类,父类,方法
From: https://www.cnblogs.com/Joyce-mi7/p/17109494.html

相关文章