C# 面向对象学习笔记

1、面向对象基本概念

例如把大象塞进冰箱里

面向过程:执行这件事的人不同时,需要为每个不同的人量身定做解决事情的方法,如每个人把大象塞进冰箱的方式不一样

面向对象:找个对象帮你做事,如把冰箱作为对象。也就是写出一个通用的代码,屏蔽差异。
描述一个对象,是通过描述这个对象的属性和方法进行的
对象必须是看得见摸得着的

我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念
类就是个模子,确定了对象应该具有的属性和方法。
对象是根据类创建出来的,也就是实例化

2、类

1. 语法:
[public] class 类名
{
    字段;_字段名  存储数据 必须是private类型
    属性;public
    方法;描述对象的行为
    构造函数;
}

2. 类的实例化
写好一个类之后,需要创建这个类的对象
使用关键字 new 创建这个类的对象的过程称为 类的实例化

3. this
Person p = new Person();
public class Person
{
	private string _name;
	public string Name
	{
		get{ return _name; }
		set{ _name = value; }
	}
	public void SayHello()
	{
		Console.Writeline("我叫{0}",this.Name);
	}
}

this: 表示当前这个类的对象 如Person类的对象是p
类不占内存,而对象是占内存的

3、属性

1. 作用
保护字段、对字段的赋值set和取值get进行限定

2. 本质
两个方法set get

3. 例子
public class Person
{
	private string _name;
	public string Name
	{
    	get { return _name; }
    	set { _name = value; }
	}
}

4. 注意事项
ctrl+R+E 快速给字段设置属性
只能通过属性给字段进行赋值,字段是私有的
通过属性这个中介来对字段进行保护,防止字段被随意修改

4、对象初始化

当我们创建好一个类的对象后,需要给这个对象的每个属性去赋值

在该类中访问字段使用 this.属性名

5、静态和非静态的区别(也就是加不加static)

加了static 是静态的,不加是非静态

区别:
1. 在非静态 类 中,既可以有实例成员,也可以有静态成员
2. 在调用实例成员时,需要使用对象名.实例成员();
   调用静态成员,类名.静态成员()
   
总结:
静态成员必须使用类名去调用,而实例成员使用对象名调用
静态 函数 中,只能访问静态成员,不允许访问实例成员
实例 函数 中,既可以使用静态成员,也可以使用实例成员
静态 类 中只允许有静态成员,不允许出现实例成员

使用:
1. 如果想要一个类当做工具类(经常使用的),可以考虑将这个类写成静态的
2. 静态类在整个项目中资源共享

6、构造函数

1. 语法
public 类名()
{
	
}

2. 作用
  初始化对象,也就是给对象的每个属性依次赋值
  
3. 初始化对象的方法
 (1) 对象名.属性名 = 值 如p.Name = "张三";
 (2) 构造函数初始化,如Person p = new Person("张三");
 
4. 构造函数是一个特殊的方法:
(1) 构造函数没有返回值,并且不能写void
(2) 构造函数的名称必须与类名一样

5. 执行时间
创建对象的时候会首先执行构造函数,通过构造函数传递给每个属性,对字段进行赋值
也就是 类名 对象名 = new 构造函数();Person p = new Person();
将鼠标光标放在后面那个Person()上,发现是Person.Person(),也就是构造函数

6. 构造函数可以重载,也就是可以有多个 名相同 参数数量或类型不同的构造函数

7. 类中会有一个默认的无参数的构造函数,当你写了一个新的构造函数,不管是有参数的,还是无参数的,那个默认的无参数的构造函数都被干掉了。

7、函数重载

函数名一样 参数的数目或类型不一样

8、new 关键字

Student stu = new Student();
new 帮助我们做了3件事:
(1) 在内存中开辟一块空间
(2) 在开辟的空间中创建对象
(3) 调用对象的构造函数 进行初始化对象

9、this 关键字

(1) 代表当前类的对象
如下面的例子,此时this代表Perosn实例化对象p
Peron p = new Person();
public class Person
{
	private string _name;
	public string Name
	{
		get { return _name; }
    	set { _name = value; }
    }
    public void SayHello()
    {
    	Console.WriteLine("我叫{0}", this.Name);
    }
}

(2) 在类中显式的调用本类的构造函数 
语法: 构造函数(参数):this(参数名与前面的参数名一致)

public class Person
{
	private string _name;
	private int _age;
	private char _gender;
	public string Name
	{
		get { return _name; }
    	set { _name = value; }
    }
    public int Age
	{
		get { return _age; }
    	set { _age = value; }
    }
    public int Gender
	{
		get { return _gender; }
    	set { _gender = value; }
    }
    public Person(string name, int age, char gender)
    {
    	this.Name = name;
    	this.Age = age;
    	this.Gender = gender;
    }
    public Person(string name, int age):this(name, age, '男')
    {
    	// this.Name = name;
    	// this.Age = age;
    }
}

10、析构函数

public class Person
{
	// 析构函数
	~Person()
	{
		
	}
}
帮助我们马上释放资源

11、命名空间

可以认为类是属于命名空间的

如果在当前项目中没有这个类的命名空间,需要我们手动导入这个类所在的命名空间

用鼠标点
alt + shift + f10
手动写

在一个项目中引用另一个项目中的类

添加引用
引用命名空间

12、值类型和引用类型

1. 区别
(1) 值类型和引用类型在内存上存储的地方不一样
(2) 在传递值类型和传递引用类型的时候,传递的方式不一样

2. 值类型称之为值传递,引用类型称之为引用传递
我们学过的值类型和引用类型:
值类型:intdoubleboolchardecimalstructenum
引用类型:string、自定义类

3. 值类型的值是存储在内存的栈中,引用类型的值是存储在堆中

13、继承

1. 语法
public class 子类名():父类名
{
	
}

2. 由来
我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员,
单独封装到一个类中,作为这些类的父类。
Student、Teacher、Driver  子类  派生类
Person                    父类  基类

3. 具体使用
(1) 子类继承了父类,那么子类从父类那里继承过来了什么?
首先,子类继承了父类的属性和方法,没有继承父类的私有字段
(2) 子类有没有继承父类的构造函数?
子类没有继承父类的构造函数,但是子类会默认的调用父类的无参数的构造函数,
创建父类对象,让子类可以使用父类中的成员。

所以,在父类中重新写了一个有参数的构造函数之后,那个无参数的就被干掉了,
子类就调用不到,所以子类会报错。
解决办法:
(1) 在父类中,重新写一个无参数的构造函数(一般不用)
(2) 子类的构造函数调用父类的有参数的构造函数
语法:
public 类名(参数):base(参数名)
{
    this.特有的参数 = 特有的参数
}

4. 实例
// 父类
public class Person
{
	private string _name;
	private int _age;
	public string Name
	{
		get { return _name; }
		set { _name = value; }
	}
	public int Age
	{
		get { return _age; }
		set { _age = value; }
	}
	// 构造函数
	public Person(string name, int age)
	{
		this.Name = name;
		this.Age = age;
	}
}
// 子类
public class Student:Person
{
	private int _id;
	public int Id
	{
		get { return _id; }
		set { _id = value; }
	}
	// 构造函数
	public Student(string name, int age, int id)
		:base(name, age)
	{
		// this.Name = name;
		// this.Age = age;
		this.Id = id;
	}
}

14、继承的特性

继承的单根性:一个子类只能有一个父类
继承的传递性:父类的迟早是子类的

15、object类是所有类的基类

16、关键字new

1. 创建对象,如 Person p = new Person();
2. 隐藏子类从父类那里继承过来的同名成员,隐藏的后果就是子类调用不到父类的成员
public class Person
{
	public void SayHello()
	{
		Console.WriteLine("这里是父类");
	}
}
public class Student:Person
{
	public new void SayHello()
	{
		Console.WriteLine("这里是子类");
	}
}
Student stu = new Student();
stu.SayHello();

使用前, 输出父类的结果
使用后,输出子类的结果

17、里氏转换

1. 子类可以赋值给父类
如果有一个地方需要父类作为参数,我们可以给一个子类代替

// Student stu = new Student();
// Person p = stu;
Person p = new Student();

public class Person
{
	public void PersonSayHello()
	{
		Console.WriteLine("我是父类");
	}
}
public class Student:Person
{
	public void StudentSayHello()
	{
		Console.WriteLine("我是学生");
	}
}
2. 如果父类中装的是子类对象,那么可以将这个父类强转成子类对象
Student stu_2 = (Student)p;

3. 子类对象可以调用父类中的成员,但是父类对象永远只能调用自己的成员

4. 判断里氏转换是否成功
(1) is 表示类型转换,如果能够转换成功,则返回一个true,否则返回false
if(p is Student)
{
	Student stu_2 = (Student)p;
	stu_2.StudentSayHello();
}
else
{
	Console.WriteLine("转换失败");
}
(2) as 表示类型转换,如果能够转换则返回对应的对象,否则返回一个null
Student stu_2 = p as Studnet;
if(stu_2 != null) stu_2.StudentSayHello();

18、多态

1、基本概念

多态就是 让一个对象能够表现出多种的状态(类型)

实现多态的三种方法:

1、虚方法
2、抽象类
3、接口

2、虚方法

1. 将父类的方法标记为虚方法,使用关键字 virtual,子类方法使用关键字 override 
结果是 父类的方法可以被子类重新写一遍

2. 实际效果
程序运行 调用方法的时候是调用父类的方法,但是父类的方法被子类重写,不再调用父类的方法。
而是调用被子类重写的方法,具体调用哪个子类重写的方法 取决于父类对象中装的是哪个子类的对象。
如 Person p = new Chinese(); 那么就调用Chinese中的方法
如果此时父类对象中装的是自己的对象,那就调用父类自己的方法。

3. 实例
Person p = new Person();
Chinese ch = new Chinese();
English en = new English();
Person[] pers = {p, ch, en};

for (int i = 0;i < pers.Length; i++)
{
	// if(pers[i] is Chinese)  ((Chinese)pers[i]).SayHello();
	// else ((English)pers[i]).SayHello();
	pers[i].SayHello();
}
Console.ReadKey();
public class Person
{
	public virtual void SayHello()
	{
		Console.WriteLine("我是人类");
	}
}

public class Chinese:Person
{
	public override void SayHello()
	{
		Console.WriteLine("我是中国人");
	}
}

public class English:Person
{
	public override void SayHello()
	{
		Console.WriteLine("我是英国人");
	}
}

3、抽象类

1. 具体使用场景
如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类。(当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法)
如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法来实现多态。(如果知道父类中的方法能写什么内容时,可以考虑使用虚方法实现)

2. 抽象方法存在的唯一意义 就是让子类重写抽象方法来实现多态;

3. 抽象类的特点
(1) 抽象成员必须标记为 abstract,并且不能有任何实现,也就是抽象函数(方法)没有方法体
(2) 抽象成员必须在抽象类中
(3) 抽象类不允许创建对象(实例化)
(4) 子类继承抽象类之后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,则可以不重写)
(5) 抽象成员的访问修饰符不能是private
(6) 在抽象类中可以包含实例成员,并且抽象类的实例成员可以不被子类实现
(7) 抽象类是有构造函数的,虽然不能被实例化
(8) 如果父类的抽象方法中有参数,那么继承这个抽象父类的子类,在重写父类的方法时,必须传入对应的参数
如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候 也必须要传入返回值

4. 实例
// Animal a = new Animal(); 抽象类不允许创建对象
Animal dog = new Dog();
dog.Bark();
Console.ReadKey();

public abstract class Animal
{
	public abstract void Bark();
}

public class Dog:Animal
{
	public override void Bark()
	{
		Console.WriteLine("汪汪");
	}
}

public class Cat:Animal
{
	public override void Bark()
	{
		Console.WriteLine("喵喵");
	}
}

4、简单工厂设计模式

class Program
{
	static void Main(string args[])
	{
		Console.WriteLine("请输入您想要的笔记本品牌: ");
		string brand = Console.ReadLine();
		NoteBook nb = GetNoteBook(brand);
		// 执行哪个类的SayHello函数 取决于父类对象装的是哪个子类
		nb.SayHello();
		Console.ReadKey();
		
	}
	public static NoteBook GetNoteBook(string brand)
	{
		NoteBook nb = null;
		switch(brand)
		{
			// 子类对象装进父类对象中
			case "Lenovo": nb = new Lenovo();
				break;
			case "Acer": nb = new Acer();
				break;
		}
		return nb;
	}
}

public abstract class NoteBook
{
	public abstract void SayHello();
}

public class Lenovo:NoteBook
{
	public ovveride void SayHello()
	{
		Console.WriteLine("联想笔记本");
	}
}

public class Acer:NoteBook
{
	public override void SayHello()
	{
		Console.WriteLine("鸿基笔记本");
	}
}

5、值传递和引用传递

1. 值类型在复制的时候,传递的是这个值的本身

2. 引用类型在复制的时候,传递的是这个对象的地址

3. 字符串不可变性
// 每次赋值新的字符串都等于开辟了一个新的空间,所以结果一个是张三 一个是李四
string s1 = "张三";
string s2 = s1;
s2 = "李思";
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.ReadKey();

4. ref
class Program
{
	static void Main(string args[])
	{
		// ref 把一个变量以参数的形式带到方法中进行改变
		// 再将改变后的值带出来
		int num = 10;
		Test(ref num);
		Console.WriteLine(num);
		Console.ReadKey();
	}
	
	public static void Test(ref int n)
	{
		n += 10;
	}
}

6、特殊的类

1. 部分类 多人开发写一个类
// 这两个部分共同组成了Person类
public partial class Person
{
	
}

public partial class Person
{
	
}
2. 密封类 sealed
// 不能被其他类继承,但是可以继承别的类
public sealed class Person
{
	
}

19、接口

1、接口简介

1. 语法简介
接口就是一个规范(能力)
[public] interface I...able
{
	成员;
}


2. 实例
继承具有单根性,一个子类只允许有一个父类
Student类想要继承多个类,这时可以考虑接口
一个类继承一个接口,必须实现这个接口中的所有成员

public class Person
{
	public void SayHello()
	{
		Console.WriteLine("我是人类");
	}
}

public class Student : Person, IKouLanable
{
	public void KouLan()
	{
		Console.WriteLine("我是学生,我也可以扣篮");
	}
}

public interface IKouLanable
{
	// 接口中的成员不允许添加访问修饰符,默认public
	// 接口中的成员可以有返回值
	// string Test();
	// 接口中的方法 没有方法体
	// 没有字段,因为它不是存储数据的
	void KouLan();
	string Name
	{
		get;
		set;
	}
}

3. 自动属性和普通属性
自动属性编译时,自动生成字段,不允许写方法体(不能对字段进行限定,但可以通过构造函数限定)

public class Person
{
	private string _name;
	// 普通属性
	public string Name
	{
		get { return _name; }
		set { _name = value; }
	}
	
	// 自动属性
	public int Age
	{
		get;
		set;
	}
}

2、接口的特点

1. 接口中的成员不允许添加访问修饰符,默认就是public

2. 不允许写具有方法体的成员,只是定义了一组未实现的成员

3.  只要一个类继承一个接口,这个类必须实现这个接口中所有的成员(实现接口的子类必须实现该接口的全部成员)

4. 为了多态,接口不能被实例化,也就是,接口不能new(不能创建对象)
接口、抽象类、静态类不能被实例化

5. 接口中只能有方法,属性(自动属性),索引器,事件 不能有字段和构造函数

6. 接口与接口之间可以继承,并且可以多继承。类有单根性,一个子类只能有一个父类

7. 接口不能去继承一个类,类可以继承接口(接口只能继承接口,类既可以继承类,也可继承接口)

8. 一个类可以同时继承一个类并实现多个接口,一个子类同时继承父类A并实现接口IA,语法上父类A必须写在接口IA前面
class 类名:A, IA(){}
类是单继承

9. 显式实现接口的目的,解决方法的重名问题
// 接口的方法 
IFlyable fly = new Bird();
fly.Fly();

// 自己的方法
Bird bird = new Bird();
bird.Fly();

Console.ReadKey();
 
public class Bird:IFlyable
{
 	// Bird自己的方法
 	public void Fly()
 	{
 		Console.WriteLine("鸟会飞");
 	}
 	// 接口中要实现的方法
 	void IFlyable.Fly()
 	{
 		Console.WriteLine("我是接口");
 	}
 }
public interface IFlyable
{
	void Fly();
}
 
10.什么时候显式的去实现接口:当继承的接口中的方法和参数一模一样的时候,用显式的实现接口
当一个抽象类实现接口时,需要子类去实现接口 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值