复习:J&C:面向对象:构造函数 / 禁止继承 / 现代接口
类文件.cs后缀指示编译器使用C#语法进行编译。(如果代码以VB.NET书写,就以.vb为后缀)
.cs文件名可以和类名不一致:本质上,.cs的文件名不影响类名,文件名和class冲突,以class后面定义的类名为准。
且一个.cs文件里也可以有多个public的class(Java不行)。
C#中的类默认内部的,仅可以在当前项目中使用。(演示:添加引用)
对应的修饰符是internal,可以显式的声明(Java没有这个访问修饰符)
可以使用partial关键字生成部分类(不是内部类):
partial class Student { } partial class Student { }
(同名的)部分类会在编译的时候被合成为一个类,所以我们完全可以把部分类当成一个类使用。
但这些都是非常规的做法,我们一般不要使用,还是尽量一个类一个类文件。
另外,类上也用static修饰,这样的类被称之为
通常用于将静态方法归类。我们常用的Console和Math都是静态类:
public static class Console{ //.... public static class Math{ //....
静态类不能被实例化,其中只能有静态成员,不能有实例成员。(对比:Java中仅内部类上可以修饰static)
C#不要求(但默认是)名称空间和类文件所在文件夹路径必须对应。
当不得不使用类的全名,且全名很长不方便的时候,还可以使用名称空间别名:
using Practise = CS.Senior.Practise; using Theory = CS.Senior.Theory;
new Practise.Teacher(); new Theory.Teacher();
using static System.Console;然后直接调用其静态方法:
WriteLine();
他们都是只能读不能改的:
internal readonly string at = "源栈"; internal const string BELONG = "源栈"; //建议const名称全大写
但是,注意他们的语法区别:#常见面试题#
internal readonly string name; //internal const string BELONG; //报错
public Student(string name) { this.name = name; }
internal readonly Teacher fg = new Teacher(); //internal const Teacher xy = new Teacher(); //报错 internal const Teacher xy = null; //OK
Console.WriteLine(Student.BELONG); Console.WriteLine(new Student().name);
此外,const还可用于方法体内修饰变量,readonly不行。
有点特别:
internal class Student { static Student() //它不能有访问修饰符,也不能有参数 { } }
因为静态构造函数不能被开发人员调用,只能由.NET运行时在使用类之前,自动调用一次且仅仅调用一次:所以访问修饰符和参数对它都没有意义。
静态构造函数的调用时间,我们只需要掌握一点:很早,早在其他静态方法或构造函数之前就会运行,.NET会确保静态构造函数的运行(比如赋值)不滞后于其他代码。(断点演示)
实际开发中经常会有这样的代码:(复习构造函数重载)
public Student(string name) { this.name = name; //代码行 1 } public Student(string name, int age) { this.name = name; //代码行 2 this.age = age; }
代码行1和代码行2有些重复,是不是?所以我们可以这样写:
public Student(string name) // 构造函数 1 { this.name = name; } public Student(string name, int age) : this(name) // 使用this()调用构造函数 1 { this.age = age; }
这里this代表当前对象的构造函数,然后按参数进行重载匹配。
这样,当运行Student(name, age)之前,会首先运行Student(name),这在构造函数内部的逻辑复杂,代码量大的时候尤其有用。
C#一开始就专门定义了属性,如下所示:
private int _age; //仍然需要字段_age public int Age //通常和字段同名,但首字母大写 { get { return _age; } //当需要获取属性值的时候,返回字段_age的值 set { _age = value; } //当给属性赋值的时候,将值存放到_age中 }然后,就可以像使用字段一样使用属性(虽然属性本质上是方法):
Student zjq = new Student(); zjq.Age = 25; //赋值,运行属性中的set{} Console.WriteLine(zjq.Age); //取值,运行属性中的get{}
当然,你也可以同时在set和get中添加逻辑。
如果get只有一行的话,我们还可以使用表达式体:
private int _score; public int Score { get => _score; //等同于: get { return _score; } }
很多时候,我们其实不需要添加什么额外的逻辑。这种情况,C#为我们很贴心的设计了一个“语法糖(仅在语法层面上的细微改善)”:自动属性,如下所示:
//注意不再需要_scroe字段 public int Score { get; set; }这样的写法,C#编译器会为我们自动的声明一个字段来存放属性的值。我们还可以:
public int Score { get; } //让Score只读 //public int Score { set; } //但不能让Score只写 //让Score外部可读,内部可写 public int Score { get; private set; }
#常见面试题:private set和没有set的区别#
但是,自动属性中,我们不能在set或get中添加使用任何逻辑。一旦添加逻辑,我们就像之前那样,配合字段使用属性。
可以在属性声明时就直接赋值
我们还可以在实例化类的同时,给属性赋值(语法上公开字段也可以,但字段不建议暴露):
Student zjq = new Student() { Name = "曾俊清", Age = 23, //多个属性之间用逗号隔开 };
还可以“嵌套”:
Student zjq = new Student { Name = "张俊清", Teacher = new Teacher { Majors = new string[] { "CSharp", "SQL"} } };
调用的是无参构造函数,圆括号可以省略,
Student zjq = new Student {
有参构造函数也可以直接传入构造函数参数:
Student zjq = new Student(28) {
这种形式更进一步,就变成了
即没有类名,也不需要声明,可以直接使用的类。比如:
var zjq = new /*注意:没有类名了*/ { Name = "曾俊清", Age = 23, }; Console.WriteLine(zjq.Name);
注意其语法特点:
var wx = new { Name = "王新", Age = 25, }; //再new一个匿名类给变量wx wx = zjq; //wx和zjq之间可以互相赋值
PS:区别Java中的匿名类。
类似于属性,都是一种往对象里存值取值的方式。
但索引器通常用于封装具有多个元素的数组或集合(后文详述)。
其声明语法如下所示:
//也需要一个字段来实质上保存数据 private string[] _courses = { "SQL", "C#", "JavaScript" }; //和属性一样可以指定访问修饰符,需要指定返回类型 public string this[int index] //不同:this关键字和[]运算符 //index还可以是其他类型,比如string { //get和set的使用和属性几乎一样 get { return _courses[index]; } //一样可以只读只写 set { _courses[index] = value; } }
调用时:
Student wx = new Student(); Console.WriteLine(wx[1]);
多快好省!前端后端,线上线下,名师精讲
更多了解 加: