c#基础二(类和对象,构造器调用顺序、访问级别、重写和多态、抽象类和接口)

一、类

1.0对象初始化器

class Student
{public String name;public int age { get; set; }
}
internal class Program
{static void Main(string[] args){  //写法一Student stu=new Student();stu.name="Tom";stu.age=20;//写法二Student stu2 = new Student { name = "Tom", age = 20 };

在 C# 中, Student stu2 = new Student { name = "Tom", age = 20 }中的 {} 称为对象初始化器(Object Initializer),它是 C# 3.0 引入的语法糖,用于在创建对象时使用键对值方式直接初始化对象的公共属性或公共字段,简化代码书写,等同于写法一;

1.1构造器(构造函数)

特点:

与类同名,没有返回值

不自己定义系统会生成一个默认的构造器,就是将给成员属性赋该类型默认值

自己定义默认构造器会被覆盖,而不是重载(因为无法再调用系统自动生成的构造器)

1.1.1实例构造器和静态构造器

静态构造器不能有修饰限定符

静态构造器不能有参数

静态构造器不能重载

 class student{public int score { get; set; }public static int num { get; set; }//实例构造器public student(int score){this.score = score;num++;}//静态构造器static student(){num = 100;}}

1.1.2实例构造器和静态构造器的调用时机

实例构造器
  1. 每次使用 new 关键字创建类的实例时,必然会调用实例构造器(如果有多个重载,会根据new 后的参数匹配对应的构造器)。
  2. 类有继承关系,创建派生类实例时,会先调用基类的实例构造器,再调用派生类的实例构造器(确保基类的实例成员先初始化)
静态构造器

静态构造器是类被首次 “访问” 时自动调用的方法,用于初始化类的静态成员(静态字段、静态属性等),与实例无关

  1. 首次创建该类的实例new实例时)。
  2. 首次访问该类的静态成员(静态字段、静态属性、静态方法)。
  3. 首次使用该类作为泛型类型参数(如 List<MyClass> 首次被使用时,若 MyClass 未初始化则触发其静态构造器
  4. 类有继承关系,基类的静态构造器先于派生类的静态构造器执行

1.2析构器(析构函数)

不加修饰限定符,使用(~类名)方式来定义函数

c#有资源回收器(GC),但是调用底层资源时有用

2、类的声明

c#类的声明和定义不分家

声明位置

  1. 把类声明在名称空间中
  2. 也可以把类声明在文件的名称空间外,但是c#有一个global名称空间,因此也在名称空间内部(不推荐)
  3. 可以声明在类中(成员类)

3、类的继承和类成员的访问控制

“是一个”规则:父类引用变量可以存储子类实例的地址,含义为:car是一个vehicle   

   static void Main(string[] args){vehicle v = new car();object o = new vehicle();object o1 = new car();      }}class vehicle
{}
class car : vehicle
{}
  • sealed关键字:封闭类,不能当作基类来使用,下例:编译器报错
  • 一个类只能继承一个基类
  • 一个类可以实现多个基接口
  • 子类的访问级别不能超过基类
  • 父类的构造器是不能被继承的

3.2编译器的调用规则

当创建子类实例时,父类的构造器先被启动,作用是初始化子类中继承的属性的值,下例中我们可以看到car中没有对owner进行赋值,但是任然可以输出值vehicle,而如果子类构造器对他赋值了,那么会覆盖这个结果。

    static void Main(string[] args){car mycar = new car();Console.WriteLine(mycar.owner);   }
}class vehicle
{   public vehicle() { this.owner = "vehilce";}public string owner { get; set; }}
class car : vehicle
{public car(){    }
}

上例是父与子类构造函数无需参数情况,需要参数时需要使用base关键字,下例

 class vehicle
{   public vehicle(string own) { this.owner = own;}public string owner { get; set; }}
class car : vehicle
{public car(string own):base(own){  }
}

3.3类的访问级别和类成员的关系

类成员的访问级别的上限是类的访问级别

类的默认访问级别是internal,成员的默认访问级别是private

protected:是可以跨程序集的,也就是说实际上,四种访问级别并不是严格的大小关系

3.4类的重写和多态

重写就是对父类成员的版本更新

重写需要父类成员对子类是可见的,即不能为private

需要重写的父类类成员(字段除外),要加关键字virtual(标识为可重写),子类类成员要加override

注意:我们使用父类的引用变量指向了子类的实例,这个方法调用的版本是由子类实例来决定的,在这时调用的重写的方法是继承链上最新的(到这个类),这就是多态,下例中将car的实例给到父类的引用变量,调用的是继承链到car的最新函数。

    static void Main(string[] args){vehicle c = new car();c.run();//运行结果为:I am driving}
}class vehicle
{public virtual void run(){Console.WriteLine("I am running");}
}
class car : vehicle
{   public override void run(){Console.WriteLine("I am driving");}
}
class racecar : car
{public override void run(){Console.WriteLine("I am racing");}
}

3.5类的组合

在类的继承中,我们提到了”是一个“原则,即car是子类,vehicle是父类,那么car是一个vehicle,同时父类引用变量可以指向子类的实例;类的组合是”有一个“原则,一个类完全可以将另一个类作为自己的属性。

举个栗子:

 class people {public Address address { get; set; }}class Address { public string city { get; set; }}internal class Program{static void Main(string[] args){   //分别实例化两个类people p=new people();Address a = new Address { city = "New York" };p.address = a;Console.WriteLine(p.address.city);//简化写法people p2 = new people { address=new Address { city="AAA" } };Console.WriteLine(p2.address.city);}}

上面代码定义了两个类,people这个类直接使用Address作为他的属性,在我们给people这个类赋值的时候,有两种方式:

方式一:分别实例化两个类,将a这个Address类的引用变量赋值给p.address。

方式二:直接嵌套两个初始化器,在people的初始化器中给address创建一个实例,并且也使用初始化器。

二、抽象类和开闭原则

抽象类

含有抽象方法的类叫做抽象类(只要有一个就行),抽象类和抽象方法要用abstract来修饰,抽象类不能被实例化

抽象方法是指没有方法体的方法,抽象方法不能是private的,没有意义

开闭原则

应该将固定的,稳定的成员封装,不确定的成员应该声明为抽象成员,留给子类实现

实例:

  • 类和方法都要加abstract
  • 对抽象方法的重新也要加override
  • 抽象类无法创建实例
 abstract class vehicle
{public abstract void run();
}
class car : vehicle
{   public override void run(){Console.WriteLine("car am driving");}
}

三、接口

  • 接口使用interface来定义,类似于类的class,接口本身的访问修饰符是可以定义的
  • 接口的成员的访问修饰符固定为public的,不需要写,也不允许写
  • 在抽象类和抽象函数中,我们需要加上abstract来修饰这是一个抽象类(函数),但是接口不能写,直接就是最简单的函数写法,下例
  • 接口的方法不行全部被实现,如果一个类实现了接口但是没有实现全部方法,也就是说内部有抽象方法,这个类是抽象类(符合定义),在继承链上想要实例化一个类,那么这个类肯定是这个抽象类的子孙类
   interface Iphone{void Dail();void Pickup();void Send();void Receive();}class Nokia : Iphone{public void Dail(){Console.WriteLine("Nokia is dailing");}public void Pickup(){Console.WriteLine("Nokia is picking up");}public void Receive(){Console.WriteLine("Nokia is receiving");}public void Send(){Console.WriteLine("Nokia is sending");}}class userphone{private Iphone _phone;public userphone(Iphone phone){_phone = phone;}public void Usephone() { _phone.Dail();_phone.Pickup();_phone.Send();_phone.Receive();}}internal class Program{static void Main(string[] args){userphone user = new userphone(new Nokia());}}

在这个例子中,我们可以看到虽然无法创建接口的实例,但是可以创建接口类型的引用变量指向子类实例实现多态,在userphone中调用Nokia类中函数

如果再有一个另外品牌的手机我们只需要修改传入的实例即可,例如:(new huawei()),这样我们可以通过

3.2依赖反转

由这张图解释上面代码

不使用接口时:

例如:有两个品牌的手机(Nokia和huawei)需要创建两个类(这一步都一样),手机的使用者(userphone)需要使用不同的手机(在这个类中调用手机类的方法)那么要不然就是创建两个(userphone)类似的类分别实例化,要不只能在一个类中写两个不同名的方法(不同点1),这时,手机和手机的使用者,是手机使用者依赖于手机,因为需要在手机使用者方法(Usephone)中实例化手机类才能调用手机中的方法(不同点2)对应图中左上角

使用接口时:

我们创建一个接口(Iphone),两个品牌的手机依赖于Iphone因为实现接口,使用者(userphone)依赖于(Iphone),这时依赖关系发生了变化,并且现在在使用者(userphone)中想要实现不同手机类中的方法,只需要使用接口类的引用类型,当实例时传入Nokia时调用Nokia的方法,传入huawei时调用huawei的方法

使用接口的优势:

当我们需要增加一个手机品牌例如三星,不使用接口时,除了写上三星类,我们需要修改手机使用者类,增加函数,或者直接专门写一个三星手机使用者的类,对应上图左上角

使用接口时:只需要写上三星类,然后调用时把三星类的实例作为实际参数传给使用者类中的函数的接口的引用变量就可以了(对应上图右上角)

在修改代码时不需要改变userphone类的成员,因为userphone不依赖于某个手机品牌的类,只依赖于接口,这样增加了类的独立性,我们称为解耦合

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/99113.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/99113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt之快捷键、事件处理、自定义按键——完成记事本项目

快捷键我们电脑中的记事本中还支持快捷键&#xff0c;如“CTRLO”打开文件、“CTRLS”保存文件在Qt中使用QShortcut这个类创建快捷键在.cpp文件的构造函数中创建QShortcut对象&#xff0c;绑定打开文件和保存文件的槽函数放大缩小字体还是在.cpp的构造函数中编写代码Widget::Wi…

Open cascade中如何使用BRepAlgoAPI_Splitter分割一个Face

理论介绍 在OpenCASCADE几何建模内核中&#xff0c;BRepAlgoAPI_Splitter是一个强大的工具&#xff0c;用于将一个形状&#xff08;Shape&#xff09;用另一个形状&#xff08;Tool&#xff09;进行分割。这种操作在CAD建模中非常常见&#xff0c;比如用平面切割实体、用曲线分…

【医疗 AI】Baichuan-M2 医疗大模型:技术解读与使用方法

【医疗 AI】Baichuan-M2 医疗大模型&#xff1a;技术解读与使用方法1. Baichuan-M2 医疗大模型简介1.1 基本信息1.2 下载地址1.3 技术特点2. Baichuan-M2 模型技术报告2.1 摘要2.2 医学性能评估2.2.1 HealthBench基准2.2.2 中国医疗场景对比评估2.3 系统架构2.3.1 验证器系统2.…

unity pcd 二进制版 简单显示文件对象(单色)

unity Point Cloud Viewer and Tool 那个插件不支持pcd二进制&#xff0c;而且网上到处都是AI 我恨这种AI滥用&#xff0c;提供不了一点价值 好了&#xff0c;言归正传 可以在Point Cloud Viewer and Tool这个插件报错地方转用这个代码&#xff0c;具体咋结合请自行研究。 …

强大的开源文档问答工具-Kotaemon

Kotaemon 是一个基于 RAG&#xff08;Retrieval-Augmented Generation&#xff09;架构的开源文档问答工具&#xff0c;为用户提供与文档对话的智能交互体验。该项目同时服务于终端用户和开发者&#xff0c;具有高度的可扩展性和定制化能力。技术栈分析核心技术栈后端框架Pytho…

区块链:搭建简单Fabric网络并调用智能合约

使用docker服务搭建Hyperledger/fabric网络的详细教程&#xff0c;实现构建多节点的简单联盟链&#xff0c;并编写、调用智能合约实现投票业务。 目录 背景知识 Hyperledger Fabric 基本组件 交易(Transaction) 智能合约 实验目的 实验环境 基础依赖 安装Golang 安装do…

Web前端面试题(2)

Web前端面试题(附答案及解析)&#xff08;2025.9月最新版&#xff09;-CSDN博客 1.link 与 import 的区别和用法 主要区别 特性<link>import语法类型HTML标签CSS规则加载方式并行加载&#xff08;与其他资源同时加载&#xff09;串行加载&#xff08;必须等待主CSS文件…

Paxos协议

目录 Paxos 是什么&#xff08;What&#xff09; Paxos 的目的&#xff08;Why&#xff09; 角色与职责&#xff08;Who&#xff09; 基本流程&#xff08;How&#xff09; 常见问题与对策 什么是多数派&#xff08;Quorum&#xff09; Paxos vs Raft 异同点 Paxos 是什…

第十二篇:Qcom Camx打印实时帧率 FPS

一、第一种方式(有些低平台可能没有) adb shell setprop persist.vendor.camera.enableFPSLog TRUE adb shell setprop persist.vendor.camera.systemLogEnable TRUE adb shell setprop vendor.debug.camera.overrideLogLevels 0xff chi-cdk/core/chiframework/chxextensi…

TRAE通用6A规则+敏捷开发5S规则

网上研究别人的一些规则,也搞一份给大家 6A工作流项目规则 身份定义 你是一位资深的软件架构师和工程师,具备丰富的项目经验和系统思维能力。你的核心优势在于: 上下文工程专家:构建完整的任务上下文,而非简单的提示响应 规范驱动思维:将模糊需求转化为精确、可执行的规…

【Nginx开荒攻略】Nginx主配置文件结构与核心模块详解:从0到1掌握nginx.conf:

目录 引言 1 nginx.conf的整体结构 2 main全局块详解 2.1 核心指令解析 2.1.1 user&#xff1a;运行用户 2.1.2 worker_processes&#xff1a;工作进程数 2.1.3 pid&#xff1a;PID文件路径 2.1.4 worker_rlimit_nofile&#xff1a;文件描述符限制 2.2 main块配置示例…

【前端教程】从基础到优化:一个登录页面的完善过程

最近做了一个简单的登录页面,主要练习了文本框的onfocus与onblur事件的使用。虽然功能实现了,但仔细想想还有不少可以改进的地方。今天就来分享一下这个登录页面的开发过程和优化思路。 初始实现与解析 先来看一下最初的实现代码: <!DOCTYPE html> <html> &l…

独家 | 抖音生活服务调整:涂晴接管市场和达人运营,旭凯担任北部大区负责人

文/刀客doc(头条精选作者)刀客doc独家获悉&#xff0c;9月8日抖音生活服务完成新一轮组织调整&#xff0c;并已在内部all hands完成官宣。此次调整主要涉及北部大区、达人运营与市场部三大条线的人事轮换与汇报关系变更。核心变动如下&#xff1a;涂晴&#xff0c;原抖音生活服…

class_9:java 抽象类和接口

抽象类 需要用abstract 修饰类和接口abstract class Person{String address;String name;abstract public void eat();abstract public void drink();public void printInfo(){System.out.println("name " name);}} class Student extends Person{public void eat()…

【C++】队列queue的使用

语法 在 C 中&#xff0c;队列的语法如下&#xff1a; #include <queue>// 声明队列 std::queue<Type> q;这里 Type 是队列中存储元素的数据类型。 常用操作 队列提供了以下常用操作&#xff1a; empty(): 检查队列是否为空。 size(): 返回队列中的元素数量。 fron…

HTTP 协议的基本格式

目录 &#xff08;一&#xff09;HTTP是什么 &#xff08;二&#xff09;报文格式 &#xff08;1&#xff09;请求 ①首行 1.URL 2.方法&#xff08;method&#xff09; Ⅰ.GET Ⅱ.POST Ⅲ.PUT Ⅳ.DELETE 3.版本号 ②请求头&#xff08;header&#xff09; 1.键值对…

计算机网络的基本概念-2

1、数据交换技术&#xff1a;电路交换、报文交换与分组交换网络核心部分的关键设备是路由器&#xff0c;其工作方式是分组交换。要理解分组交换&#xff0c;必须先了解其前两种技术。1. 电路交换 (Circuit Switching)核心思想&#xff1a;通信前必须预先建立一条专用的物理通路…

车载网络技术--SOME_IP协议详解

文章目录前言SOME/IP概念SOME/IP协议格式SOME/IP功能介绍序列化序列化规则发布和订阅服务发现&#xff08;SOME/IP-SD&#xff09;SOME/IP-TP协议使用场景SOME/IP-TP协议参考文章&#xff1a;前言 本文介绍了SOME/IP协议的具体内容&#xff0c;包括报文格式&#xff0c;协议选…

JVM 核心知识全解析:从类加载到垃圾回收的深度认知

什么是JVM&#xff1f; JVM全称&#xff08;Java Virtual Machine&#xff09;&#xff0c;中译为&#xff1a;Java虚拟机 本质&#xff1a;是一个运行在计算机上的程序 职责&#xff1a;运行Java字节码文件&#xff08;因为计算机只能认识机器码文件&#xff0c;所以需要JVM将…

Keepalived 负载均衡

Keepalived 负载均衡 Keepalived 可以与 LVS&#xff08;Linux Virtual Server&#xff09;结合&#xff0c;提供强大的四层负载均衡功能。它通过 IPVS&#xff08;IP Virtual Server&#xff09;内核模块实现高性能的负载分发。 核心组件 Virtual Server&#xff1a;虚拟服务器…