【c#基础】5.类、对象、方法
目录
一、类与对象的核心定义
1. 类(Class)
类是对象的模板/蓝图,是具有相同属性、字段和方法的一组对象的集合。
通俗理解:类就像“人类”—— 定义了人类共有的特征(年龄、性别)和行为(吃喝拉撒),是一个抽象的模板。
2. 对象(Object)
对象是类的实例化,是类这个模板的具体实现。
通俗理解:对象就像“张三、李四”—— 是“人类”这个类的具体个体,拥有类定义的特征和行为。
3. 类与对象的核心作用
类的作用:定义属性、字段、方法,为构建对象提供模板(规定对象有哪些特征和行为);
对象的作用:给具体对象的属性、字段赋值,以及调用类中定义的方法(实现类的具体功能)。
二、类的定义(语法+规则)
1.核心语法
// 语法格式:修饰符 class 类名
// 修饰符:常用public、internal(默认internal)
// 类名:必须遵循大驼峰命名法则(首字母大写,后续每个单词首字母也大写)
public class 类名
{
// 类的内部:定义字段、属性、方法
}
// 创建对象: 类名 对象名 = new 类名()
Student zhangsan = new Student();
//对象属性赋值 对象.属性=值
zhangsan.Name = "张三";
zhangsan.Age = 10;
zhangsan.Sex = "男";
//访问对象属性 对象.属性=值
Console.WriteLine(zhangsan.Age);
//创建对象 对象赋值的第二种方式
Student lisi = new Student() { Name="李四",Age = 20,Sex="女"};
Console.WriteLine(lisi.Name);
//创建多个对象
string s = "";
for (int i = 0; i < 10; i++)
{
//创建对象
Student s1 = new Student(); //
s1.Name = "吴亦凡" + i + "号";
s1.Age = i * 10;
s1.Sex = i % 2 == 0 ? "男" : "女";
s += s1.Name + ":" + s1.Age + ":" + s1.Sex + "\n";
}
Console.WriteLine(s);
//定义类: public class Student
//一般类的修饰符选择 public/internal
//class 类的关键字
//Student 类名 大驼峰命名法则
//public修饰符:公共的公开的类
//private 私有的类
//internal 内部的修饰
//protected 受保护的
public class Student
{
//字段:在类内部使用时候一般定义成字段并且为私有的, 并且名字一般添加_单词首字母小写
private int _age;
//属性: 定义公共的 并且首字母要大写, 并且加上set和get访问器。属性一般对外调用。 属性内部本质是访问内部私有的字段
public int Age { get; set; } // get set属于属性
public string Name { get; set; } //name属性
public string Sex { get; set; } // sex属性
}
2. 类的修饰符说明(重点)
- public(公共的):所有窗体、所有类都能访问,跨窗体传数据必用;
- private (私有的(默认)):只能当前窗体 / 当前类内部用,外面访问不到;
- internal (内部的):整个项目里都能用,别的项目不行;
- protected( 受保护的):仅在自己 + 子类中可以访问
3. 字段 vs 属性
1、字段(Field)
-
作用:用于在类内部存储数据,相当于“类的内部变量”;
-
命名规则:一般定义为私有(private),名字前加下划线(_),后续单词首字母小写(小驼峰);
-
使用场景:仅在类内部使用,不对外暴露。
// 示例:类内部的私有字段
private int _age; // 私有字段,仅类内部使用,命名为_age(下划线+小驼峰)
2、属性(Property)
作用:对外暴露类的数据,提供统一的访问方式(读取/修改),本质是访问类内部的私有字段;
命名规则:定义为公共(public),首字母大写(大驼峰);
核心组成:get访问器(读取属性值)和set访问器(修改属性值),可省略其中一个(只读/只写);
使用场景:供类外部的对象访问、赋值。
// 示例:类的公共属性(自动实现属性,简化写法)
public int Age { get; set; } // get(读取Age值)、set(修改Age值)
public string Name { get; set; }
public string Sex { get; set; }
3、static 静态类修饰符
- 属于类,不属于窗体对象
- 程序全局共享,跨窗体取值必备
- 不用
new实例化就能直接调用
// 公共 + 静态 (跨窗体万能写法)
public static List<string> str1 = new List<string>();
// 私有 + 静态 (只当前窗体用)
private static int num = 0;
三、方法
实参: 在调用方法传递的实际的值
形参: 在定义方法时候小括号里面(int a) a就是形参,形式上参数。
返回值:是方法的具体结果 //Console.ReadLine() 有结果的方法
string name = Console.ReadLine();
方法:把相关功能的代码添加一个方法体里面,以后有需要相关功能时候,只需要调用方法即可,减少代码的重复率。可以定义方法时候带参数,在调用的时候把实参传递方法里面形参,可以通过形参实现不同功能 ,方法也可以通过返回值把方法结果拿到其他地方去使用。
1、方法定义及调用
//2方法调用:
//如果方法是static 使用类名打点去调用
//如果方法是没有static 使用对象.调用, 前提先new 一个对象
Program.Test();// 调用方法的时候会把方法里面全部执行一遍,
Test();// 可以把类名省掉
//方法一定要去调用
Test2();
//1定义方法
//public 方法修饰符,一般定义公共的
//static 静态的方法(目前使用static) ,不写static 非静态方法
//void 方法的返回值,无返回值 不能赋值给一个变量
//Test 方法名字 符合大驼峰命名规则
//int a, int b, 参数列表
//{} 方法体
public static void Test()
{
Console.WriteLine("范");
}
// 1 个引用
public static void Test2()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("赵");
}
}
2、带参方法
//调用方法 把实参值传递给了形参
Test("张娜"); // "张娜" 属于实参
Test("邓");
string name = "郑";
Test(name); // 传递一个变量
//调用两个参数Test1方法
Test1(100, "房祖");
//定义一个静态的 无返回值的 带一个参数的方法
//name 形参
public static void Test(string name)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(name);
}
}
//要求次数也是不定 名字也是不定需要传递多个参数
public static void Test1(int count, string name)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(name);
}
}
3、返回值(return)
static void Main(string[] args)
{
//调用带返回值的方法Test2
int s1 = Test2(99, 99);
Console.WriteLine(s1);
// 调用返回值为对象类型的Test3方法
Student zs = Test3("张三");
Console.WriteLine(zs.Name);
//调用Max方法
Console.WriteLine(Max(1, 1, 9));
}
// 有返回值的方法的定义方式:把void改成返回值的类型
// 有返回值的方法一定要添加return关键字 return 后面数据类型一定和返回值类型保持一致
// 计算数字和 返回值类型可以写成int
1 个引用
public static int Test2(int a, int b)
{
int sum = a + b;
return sum; // return返回 得到 跳出方法体, return类型给方法返回值类型保持一致。
}
//返回值是一个对象 并且是一个学生对象
//返回值类型为Student 传递参数字符串类型
//要求把参数赋值给对象的属性上
1 个引用
public static Student Test3(string n) //n值张三
{
//1先定义一个Student类型的数据(就是Student对象)
Student zhangsan = new Student(); // 对象为空的化 报未将对象引用设置到对象的实例。 对象没new的原因
zhangsan.Name = n;
return zhangsan;
}
//7. 定义一个函数,输入三个值, 找出三个数中的最大值
1 个引用
public static int Max(int a, int b, int c)
{
int max = 0;
int temp = a;
temp = a <= b ? b : a;// temp 是 a,b中最大值
max = temp <= c ? c : temp;//temp 和c 之间的最大值
return max;
}
4 个引用
public class Student
{
2 个引用
public string Name { get; set; }
}
四、值类型与引用类型
1.什么是值类型? 直接存储数据本身,赋值是拷贝一份新数据,常见:
- 基本类型:int /float/bool /char/double
- 结构体:struct、DateTime、TimeSpan
- 枚举:enum
2.什么是引用类型? 存储的是数据的引用(内存地址),数据本体在堆,赋值是拷贝引用,常见:
类:string、object、自定义 class
接口、数组、委托
| 特性 | 值类型 | 引用类型 |
|---|---|---|
| 存储内容 | 数据本身 | 数据的引用(地址) |
| 赋值行为 | 深拷贝(独立副本) | 浅拷贝(共享数据) |
| 内存位置 | 栈 / 堆(看声明位置) | 地址在栈,数据在堆 |
| 释放方式 | 自动释放(出作用域) | GC 自动回收 |
| 空值 | 不能为 null(可空类型除外) | 默认为 null |
- 深拷贝 vs 浅拷贝:值类型赋值时会复制一份独立数据,修改新变量不影响原变量;引用类型赋值只复制地址,两个变量指向同一个对象,修改会互相影响。
- GC 回收:引用类型的堆内存由.NET 的垃圾回收器自动管理,值类型出作用域后直接从栈上释放,效率更高。
- 空值:值类型默认不能为
null,如果需要可空,要加?(如int?);引用类型默认值就是null,表示还没有指向任何对象。
// 值类型:变量存储值本身,存在栈空间中,在赋值过程中,把值本身复制拷贝一份,把拷贝一份给新变量了,在去修改其中一个时候,另外一个不会受影响
// 值类型:int float double bool char long uint sbyte ushort ulong 枚举 结构体类型
int a = 10;
int b = a; // 出现赋值过程,把值拷贝了一份赋值给b,b当成副本
a = 30;
Console.WriteLine(b); // 输出:10(值类型互不影响)
// 引用类型:变量存储的对象的引用,或者说变量保存是内存地址,存储在堆空间,在赋值过程中把内存地址复制一份,新变量和之前变量这两个变量是指向同一个内存地址,再去修改其中一个另一个会被修改。
// 引用类型:string(特殊的引用类型)、class、数组、集合 Random等
// 创建对象
Book b1 = new Book();
b1.Name = "明朝那些事";
Book b2 = b1; // 赋值过程:复制的是内存地址,不是对象本身
b2.Name = "清朝";
Console.WriteLine(b1.Name); // 输出:清朝(引用类型一改全改)
public class Book
{
public string Name { get; set; }
}
五、值传递、引用传递、参数
1、值传递
值传递传递是值类型的时候:把实参值拷贝一份传递给形参,在方法体里面修改形参的值,不会影响外部实参的值。默认情况下发生值传递 ;
把变量的副本 / 拷贝传给方法,方法里改的是拷贝,不会影响外面原来的变量。
static void Main(string[] args)
{
int a1 = 10;
Test1(a1); //把实参传递给形参 把a1赋值a
Console.WriteLine("a1的值是" + a1);
}
public static void Test1(int a) //
{
Console.WriteLine("a修改之前的值" + a);
a = 20; // 修改a的值
}
值传递传递是引用类型的时候: 把实参对象地址赋值给形参,形参和实参指向同一个地址,证明是同一个对象。
(1)方法内 修改对象属性 (对象.属性名)→ 会影响到实参的对象值。
(2)方法内 new 一个新对象 → 不会影响到实参的对象值。
People p = new People(){ Name="张三" };
Test(p);
void Test(People people)
{
people.Name = "李四"; // 改属性(对象.属性) → 外面变
people = new People(); // new新对象 → 外面不变
}
internal class Program
{
static void Main(string[] args)
{
//2 值传递传递是引用类型的时候: 把实参对象地址赋值给形参,形参和实参指向同一个地址,证
//明是同一个对象,
//如果在方法中通过对象.属性这种方式进行修改的时候,会影响到实参的对象值
People p1 = new People() { Name = "张三" };
Test2(p1); //修改了对象的属性值
Console.WriteLine("p1对象name值" + p1.Name); // 李四
}
//传递参数是引用类型
public static void Test2(People p) //
{
Console.WriteLine("修改之前" + p.Name); //张三
//修改传递过来实参的俩中方式
//第一种修改:对象.属性这种方式进行修改
p.Name = "李四";
}
}
public class People
{
public string Name { get; set; }
}
2、引用传递(ref参数)
(1)引用传递:在方法内部修改形参会影响到外部实参的值,ref关键字;
传的不是拷贝,是变量本身,方法内外是同一个东西,修改会互相影响。
(2)第一种修改:对象.属性进行修改;
(3)第二种方式:通过new的方法修改整个对象。
(4)调用前必须赋值,方法内外共享同一个变量,修改 → 外面一定变。
static void Main(string[] args)
{
//引用传递:在方法内部修改形参会影响到外部实参的值
int a1 = 10; //ref参数必须赋初始值
Test1(ref a1); //如果参数有ref关键字,需要调用的时候实参前面添加ref关键字
Console.WriteLine("a的值为" + a1);//20
//验证参数是对象类型的时候: 前提参数使用ref关键字进行修饰,不管对象.属性方式修改还是整体new对象方式修改 都会影响到实参。
People p1 = new People() { Name = "烧饼" };
Test2(ref p1);
Console.WriteLine(p1.Name); // 对象.属性方式进行修改的话 这地方也会跟着变化武大郎
// 如果通过new修改整体对象 这地方也会跟着变化武大郎
}
//ref:关键字的作用 把形参传值改成引用类型传值的形式, 通俗讲把方法内部形参和外部实参表示同一个,
1 个引用
public static void Test1(ref int a)
{
a = 20;//此处修改影响到外部a1值
}
// 传递People类型
1 个引用
public static void Test2(ref People a)
{
//第一种修改 对象.属性进行
//a.Name = "武大郎";
//第二种方式 通过new的方法修改整个对象
a = new People() { Name = "武大郎" };
}
4 个引用
public class People
{
3 个引用
public string Name { get; set; }
}
值传递和引用传递的区别:
(1)值传递在方法内部修改变量,不会影响到外部(对象.属性这种方式会影响到外部)
(2)引用传递(必须有ref) 在方法内部修改变量,会影响到外部
3、引用传递(out参数)
out参数作用:
(1)实现一个方法有多个返回值;
(2)实现引用传递;
(3)方法内必须赋值;
(4)调用前可以不赋值。
static void Main(string[] args)
{
//out参数作用:
Test1(out int a1, out int b1);
Console.WriteLine("a1的值"+a1+";b1的值"+b1);
// ref:
int a2 = 0;
int a3 = 0;
Test2(ref a2, ref a3);
Console.WriteLine(a2+":"+a3);//10000 10000
}
// 使用out输出参数定义方法的时候,先在参数前添加out关键字
// out参数必须在方法内部赋初始值
public static void Test1(out int a, out int b)
{
a = 90; // 修改a
b = 90; // 修改b
a = a + b;// 和180
b = (a-b)*b;//乘积8100
}
public static void Test2(ref int a, ref int b)
{
a = 10000;
b = 10000;
}
4、ref 和 out 区别
ref和out的区别:
- 调用处:ref 实参必须提前赋值;out 实参可无需赋值
- 方法内:ref 参数可无需赋值;out 参数必须赋值
- 取值规则:ref 可直接读取原值;out 赋值前不能读取
- 用途:ref 兼顾传入、带回数据;out 多用于向外输出结果
| 关键字 | 调用前赋值 | 方法内赋值 | 用途 |
|---|---|---|---|
| ref | 必须赋值 | 可选 | 修改原值、交换值 |
| out | 不用赋值 | 必须赋值 | 多返回值 |
5、in 参数
(1)定位:只读引用参数
(2)作用:
- 不开辟新内存,不复制数据,直接引用原变量
- 方法内部禁止修改参数值,只读保护
- 优化大结构体、大数据传参性能
(3)语法:
public static void 方法名(in 数据类型 变量名)
static void Main(string[] args)
{
Test1(10);
People p1 = new People() { Name = "李四" };
Test2(p1);
Console.WriteLine(p1.Name); //值传递,通过属性进行修改的话 会影响到外部
}
public static void Test1(in int a)
{
//a = 100; //in 使参数变成只读的,不能修改
int sum = a + 19;
Console.WriteLine(sum);
}
//in 作用对象,可以通过改属性值 可以修改
// in 作用对象, 对形参整体不能修改
public static void Test2( in People a)
{
//1只改属性值 可以修改
//a.Name = "foo";
//2 修改形参指向 new新的 报错
//a = new People() { Name = "foo" };
}
}
public class People
{
public string Name { get; set; }
}
6、params 参数
(1)作用:允许方法传入任意多个同类型实参,编译器自动把零散参数打包成数组。
(2)语法: 修饰符 返回值 方法名(params 数据类型[] 数组名)
params int[] a:
params:参数列表 允许传递不定数量的参数;
int[] a;参数a就是整型的容器,可以存储多个整型的数;
a.Length 就是容器的长度;string[] a 存放字符串的容器;
bool[] b 存放bool的容器。
- params 只能修饰一维数组
- 必须是形参列表最后一个参数
- 一个方法只能有一个 params
- 不能搭配
ref / out / in使用- 调用时可传:0 个、1 个、多个、数组
练习:
1、定义一个函数,传递一个数组参数(参数列表),找出参数当中的最大值 FindMax(1,2,3,6,10)返回10
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(FindMax(1, 2, 3, 6, 10));
}
public static int FindMax(params int[] num) {
int max = 0;
for (int i = 0; i < num.Length; i++) {
if (max < num[i]) {
max = num[i];
}
}
return max;
}
2、定义一个方法,传入一个字符串类型的数组参数,输出倒叙的字符串, ReverseString("a", "c", "e")返回 “eca”
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(ReverseString("a", "c", "e"));
}
public static string ReverseString(params string[] s)
{
string str = "";
for (int i = s.Length-1; i >=0; i--) {
str+= s[i];
}
return str;
}
}
3、定义一个方法,传入一个字符串类型的数组参数,输出这些字符是否为回文串( 一个字符串,正着和倒着是一样的)
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(IsHuiWen(out string mess,"1", "2", "3", "2", "1"));
Console.WriteLine(mess);
}
public static bool IsHuiWen(out string msg,params string[] str) // 12321
{
for (int i = 0; i < str.Length/2; i++)
{
if (str[i] != str[str.Length-1-i]) {
msg = "不是回文数据";
return false;
}
}
msg = "是回文数据";
return true;
}
}更多推荐

所有评论(0)