目录
[1. 核心概念](#1. 核心概念)
[2. 调用规则](#2. 调用规则)
[3. 静态成员共享特性测试](#3. 静态成员共享特性测试)
[1. 继承基础规则](#1. 继承基础规则)
[2. 访问权限(继承相关)](#2. 访问权限(继承相关))
[1. 本项目测试代码](#1. 本项目测试代码)
[2. 跨项目测试代码(引用上方命名空间)](#2. 跨项目测试代码(引用上方命名空间))
[1. 多态分类](#1. 多态分类)
[2. 函数重载条件(必须全部满足)](#2. 函数重载条件(必须全部满足))
一、静态成员(static)
1. 核心概念
- 非静态成员 :属于对象(实例) ,每个对象拥有独立的数据,必须
new实例后调用。 - 静态成员 :属于类本身 ,全局共享一份数据,通过
类名.成员直接调用,所有实例共用。
2. 调用规则
- 非静态方法:可以访问 静态 / 非静态 成员
- 静态方法:只能访问静态成员,不能直接调用实例成员(需手动创建对象)
完整代码示例
cs
using System;
namespace _2静态成员
{
internal class Program
{
static void Main(string[] args)
{
// 非静态成员:实例对象调用
People p1 = new People();
p1.F1();
p1.Id = 1;
// 静态成员:类名直接调用
People.Age = 10;
People.F2();
}
}
public class People
{
// 非静态字段 + 属性
private int id;
public int Id
{
get { return id; }
set
{
Console.WriteLine("给Id赋值");
id = value;
// 禁止写 Id = value,会造成属性死递归
}
}
// 非静态方法
public void F1()
{
Console.WriteLine("非静态方法 F1");
}
// 静态自动属性
public static int Age { get; set; }
// 静态方法
public static void F2()
{
Console.WriteLine("静态方法 F2");
}
}
}
3. 静态成员共享特性测试
静态属性全局共享,一个实例修改,所有实例读取到的值都会变化:
cs
using System;
namespace _3静态成员测试
{
internal class Program
{
static void Main(string[] args)
{
People p1 = new People();
p1.AddNum();
People p2 = new People();
p2.AddNum();
// 静态Num全局共享,结果均为 2
Console.WriteLine(p1.GetNum());
Console.WriteLine(p2.GetNum());
}
}
public class People
{
public int Age { get; set; }
public static int Num { get; set; }
public void AddNum()
{
Num++;
}
public int GetNum()
{
return Num;
}
}
}
二、只读(readonly)与常量(const)
核心区别
- const 常量
- 编译时常量,隐式 static,必须定义时直接赋值
- 全局不能修改,通过
类名.常量名访问
- readonly 只读字段
- 运行时常量,分实例只读 和静态只读
- 实例只读:只能在实例构造函数中赋值
- 静态只读:只能在静态构造函数中赋值
- 静态构造函数
- 无访问修饰符、无参数
- 全局仅执行一次,首次使用类 / 创建实例时触发
完整代码
cs
using System;
namespace _4只读和常量
{
internal class Program
{
static void Main(string[] args)
{
People p1 = new People();
// p1.a = 30; 报错:只读字段不能在构造函数外修改
Console.WriteLine(People.b);
Console.WriteLine(People.c);
}
}
public class People
{
// 实例只读字段
public readonly int a = 10;
// 静态只读字段
public static readonly int b = 20;
// 常量(隐式static)
public const int c = 30;
// 实例构造函数:修改实例只读 a
public People()
{
a = 20;
Console.WriteLine(a);
}
// 静态构造函数:修改静态只读 b,仅执行一次
static People()
{
b = 40;
Console.WriteLine(b);
}
}
}
三、类的继承
1. 继承基础规则
- 语法:
子类 : 父类 - C# 为单继承:一个类只能直接继承一个父类,支持链式继承
- 所有类默认隐式继承
object(顶级基类) - 作用:代码复用、拓展功能
2. 访问权限(继承相关)
private私有:仅当前类内部访问,子类无法继承protected受保护:当前类 + 子类可访问,外部实例无法访问public公共:全场景可访问
完整代码
cs
using System;
namespace _5继承
{
internal class Program
{
static void Main(string[] args)
{
Student s1 = new Student();
s1.Name = "Test";
s1.Address = "地址";
s1.F1();
}
}
// 父类
public class People
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
// 私有成员:子类不可访问
private int Age = 1000;
// 受保护成员:子类可访问,外部实例不可访问
protected int CC { get; set; }
public void F1()
{
Console.WriteLine("父类方法 F1");
}
}
// 子类 Student 继承父类 People
public class Student : People
{
public void F2()
{
// 继承父类 public / protected 成员
Console.WriteLine($"{Name} {Id} {CC}");
}
}
}
四、父子类构造函数执行顺序
核心规则
- 创建子类对象时,优先执行父类构造函数,再执行子类构造
- 默认自动调用父类无参构造 ,可通过
base(参数)指定调用父类有参构造 - 简写总结:
- 子类构造不写
base→ 父类必须有无参构造 - 子类构造写
base(参数)→ 父类可省略无参构造
- 子类构造不写
完整代码
cs
using System;
namespace _6子类构造和父类构造执行顺序
{
internal class Program
{
static void Main(string[] args)
{
// 先执行父类有参构造 → 再执行子类有参构造
Student s2 = new Student(10, "张三");
}
}
public class People
{
public string Name { get; set; }
// 父类无参构造
public People()
{
Console.WriteLine("父类无参构造");
}
// 父类有参构造
public People(string name)
{
Name = name;
Console.WriteLine("父类有参构造");
}
}
public class Student : People
{
public int Age { get; set; }
// base() 可省略,默认调用父类无参构造
public Student() : base()
{
Console.WriteLine("子类无参构造");
}
// base(n) 主动调用父类有参构造
public Student(int age, string n) : base(n)
{
Age = age;
Console.WriteLine("子类有参构造:" + Name);
}
}
}
五、五大访问修饰符
权限对照表
| 修饰符 | 本类 | 子类 | 本项目实例 | 跨项目子类 | 跨项目实例 |
|---|---|---|---|---|---|
| public | ✅ | ✅ | ✅ | ✅ | ✅ |
| private | ✅ | ❌ | ❌ | ❌ | ❌ |
| protected | ✅ | ✅ | ❌ | ✅ | ❌ |
| internal | ✅ | ✅ | ✅ | ❌ | ❌ |
| protected internal | ✅ | ✅ | ✅ | ✅ | ❌ |
1. 本项目测试代码
cs
using System;
namespace _7属性访问修饰符
{
internal class Program
{
static void Main(string[] args)
{
People p = new People();
Console.WriteLine(p.a);
Console.WriteLine(p.d);
Console.WriteLine(p.e);
}
}
public class People
{
public int a = 10;
private int b = 20;
protected int c = 30;
protected internal int d = 30;
internal int e = 30;
public void F1()
{
// 本类中所有修饰符都可访问
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
// 本项目子类
public class Man : People
{
public void F2()
{
Console.WriteLine(a);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
}
2. 跨项目测试代码(引用上方命名空间)
cs
using System;
using _7属性访问修饰符;
namespace _8测试访问修饰符
{
internal class Program
{
static void Main(string[] args)
{
People p = new People();
Console.WriteLine(p.a); // public 跨项目可访问
}
}
// 跨项目子类
public class Woman : People
{
public void F3()
{
Console.WriteLine(a);
Console.WriteLine(c);
Console.WriteLine(d);
// Console.WriteLine(e); internal 跨项目不可访问
}
}
}
六、多态:函数重载(静态多态)
1. 多态分类
- 静态多态(编译期):函数重载、运算符重载
- 动态多态(运行期):虚方法、抽象类、接口
2. 函数重载条件(必须全部满足)
- 方法名完全相同
- 参数个数 / 类型 / 顺序不同
- 仅返回值不同,不构成重载
代码示例
cs
using System;
namespace _9多态_函数重载
{
internal class Program
{
static void Main(string[] args)
{
}
public static void F1()
{
Console.WriteLine("无参方法");
}
public static void F1(int a)
{
Console.WriteLine("int 参数");
}
public static void F1(string a)
{
Console.WriteLine("string 参数");
}
public static void F1(string a, int b)
{
Console.WriteLine("两个参数");
}
public static int F1(bool b)
{
Console.WriteLine("bool 参数");
return 10;
}
}
}
七、运算符重载
规则
- 使用
public static operator 运算符语法 - 必须为静态方法,参数至少包含一个当前类类型
- 常用重载:
+、-、++、>、<等
完整代码(盒子对象运算)
cs
using System;
namespace _10运算符号重载
{
internal class Program
{
static void Main(string[] args)
{
Box b1 = new Box(10, 20, 30);
Box b2 = new Box(30, 40, 50);
// 重载 +
Box b3 = b1 + b2;
Console.WriteLine($"{b3.Length} {b3.Width} {b3.Height}");
// 重载 -
int b4 = b1 - b2;
Console.WriteLine(b4);
// 重载 ++
Box b5 = b1++;
Console.WriteLine(b1.Length);
Console.WriteLine(b5.Length);
// 重载 > <
Console.WriteLine(b1 > b2);
Console.WriteLine(b1 < b2);
}
}
public class Box
{
public int Length { get; set; }
public int Width { get; set; }
public int Height { get; set; }
// 体积
public int Volume
{
get { return Length * Width * Height; }
}
public Box() { }
public Box(int l, int w, int h)
{
Length = l;
Width = w;
Height = h;
}
// 重载 +
public static Box operator +(Box b1, Box b2)
{
return new Box
{
Length = b1.Length + b2.Length,
Width = b1.Width + b2.Width,
Height = b1.Height + b2.Height
};
}
// 重载 -
public static int operator -(Box b1, Box b2)
{
return b1.Volume - b2.Volume;
}
// 重载 ++
public static Box operator ++(Box b1)
{
return new Box
{
Length = b1.Length + 1,
Width = b1.Width + 1,
Height = b1.Height + 1
};
}
// 重载 >
public static bool operator >(Box b1, Box b2)
{
return b1.Volume > b2.Volume;
}
// 重载 <
public static bool operator <(Box b1, Box b2)
{
return b1.Volume < b2.Volume;
}
}
}
八、抽象类(abstract)
核心特点
- 用
abstract修饰,不能实例化,专门用于被继承 - 可包含:普通属性、普通方法、抽象属性 / 抽象方法
- 抽象方法:无方法体
{},子类必须用override重写实现 - 子类如果也是抽象类,可选择性不实现抽象成员;非抽象子类必须实现所有抽象成员
完整代码
cs
using System;
namespace _11抽象类
{
internal class Program
{
static void Main(string[] args)
{
// People p = new People(); 报错:抽象类无法实例化
}
}
// 抽象父类
abstract class People
{
// 普通属性
public int Age { get; set; }
// 普通方法
public void F2()
{
Console.WriteLine("普通方法");
}
// 抽象属性(无实现)
public abstract string Name { get; set; }
// 抽象方法(无方法体)
public abstract void F1();
}
// 非抽象子类:必须重写所有抽象成员
class Student : People
{
public override string Name { get; set; } = "学生";
public override void F1()
{
Console.WriteLine("子类实现抽象方法 F1");
}
}
}
总结
- 静态成员:类共享,静态方法只能访问静态成员
- readonly / const:const 编译常量,readonly 运行只读,赋值位置有严格限制
- 继承:C# 单继承,构造函数永远先执行父类
- 访问修饰符:控制跨类、跨项目、子类的访问权限
- 静态多态:函数重载、运算符重载,依赖参数区分
- 抽象类:模板类,强制子类实现抽象方法,不可实例化