第九天覆习
class Person
{
//类和对象,类中包含对象
/*
字段:存储数据,不跟类外的打交道
属性:保护字段,对字段的取值和设值进行限定
方法:描述对象的行为
构造函数:初始化对象(给对象的每个属性依次赋值)
类中的成员,如果不加访问修饰符,默认都是private
*/
string _name;
/// <summary>
/// 属性的本质就是两个方法
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
char _gender;
public char Gender
{
get { return _gender; }
set {
if(value != '男'&&value != '女')
{
value = '男';
}
_gender = value; }
}
int _age;
public int Age
{
get {
if (_age < 0 || _age > 100)
{
return _age = 0;
}
return _age; }
set { _age = value; }
}
//this:1.当前类的对象
public void SayHello()
{
Console.WriteLine("{0},{1},{2}", this.Name, this.Gender, this.Age);
}
//静态方法只能访问静态对象,不能有实例对象,实例对象则可以都有
public static void SayHelloTwo()
{
Console.WriteLine("我是静态方法");
}
/*
构造函数
1.没有返回值,连void也没有
2.构造函数名称跟类型一模一样
*/
public Person(string name,char gender,int age)
{
this.Name = name;
this.Gender = gender;
this.Age = age;
}
//this的第二个作用:调用当前类的构造函数
public Person(string name,char gender) : this(name,gender,0)
{
}
}
调用
static void Main(string[] args)
{
////new:1.在内存中开辟一块空间 2.在开辟的空间创建对象 3.调用对象的构造函数
//Person zsPerson = new Person("张三",'男',18);
//zsPerson.SayHello();
//Person zsPerson = new Person("张三", '中', -18);
//zsPerson.SayHello();
//静态对象的调用 类名.对象名
Person.SayHelloTwo();
Console.ReadKey();
}
第十天新内容
一、命名空间(namespace)
用于解决类重名问题,可以看做“类的文件夹”
如果当前项目中没有这个类的命名空间,需要我们手动的导入这个类所在的命名空间
1.鼠标点
2.alt+shift+F10
3.记住命名空间,手动引用
在一个项目中引用另一个项目的类
1.添加引用 2.引用命名空间
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _01第九天覆习;
namespace _02命名空间
{
class Program
{
static void Main(string[] args)
{
// List<int> list = new List<int>();
Person zsPerson = new Person("张三",'中',-18);
//zsPerson.Name = "张三";
zsPerson.SayHello();
Console.WriteLine(zsPerson.Name);
Console.ReadKey();
}
}
}
二、值类型和引用类型
区别
1.值类型和引用类型在内存上存储的地方不一样
2.在传递值类型和引用类型的时候,传递的方式不一样
值类型称之为值传递,引用类型称之为引用传递
值类型:int、double、bool、char、decimal、struct、enum
引用类型:string、自定义类、数组
存储
值类型的值存储在内存的栈当中
引用类型的值存储在内存的堆当中,引用类型同样在栈上开辟一个空间,存的是堆中的地址,通过栈存的地址来和堆拉上关系
三、字符串
1.字符串的不可变性
当你给一个字符串重新赋值后,旧值并没有被销毁,而是重新再堆当中开辟一个空间用来存新值,这时候栈上的地址也换成了新开辟空间的地址。
当程序结束时,GC扫描整个内存,发现没有指向的内存,GC就释放该内存的资源。
2。我们可以将字符串看做是char类型的一个只读数组
ToCharArray(); 将字符串转换为char数组
new string(char[] chs):将char数组转换为string
static void Main(string[] args)
{
//可以将string类型看做是char类型的只读数组
string s = "abcdefg";
// s[0] = b; 不能这样做,因为是只读的
//首先将字符串转换为char类型的数组
char[] chs = s.ToCharArray();
chs[0] = 'b';
//将字符数组转回字符串
s = new string(chs);
Console.WriteLine(s);
//既然可以将string看做char烈性的只读数组,所以可以通过索引去访问字符串中的某一个元素
Console.WriteLine(s[1]);
Console.ReadKey();
}
关键字:StringBuilder() 不重新开辟空间
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
string str = null;
//创建一个计时器,用来记录程序运行的时间
Stopwatch sw = new Stopwatch();
sw.Start();//开始计时
for (int i = 0; i < 1000; i++)
{
//00:00:00.0017008
//str += i;
//00:00:00.0002480
sb.Append(i);
}
sw.Stop();//结束计时
Console.WriteLine(sb.ToString());
Console.WriteLine(sw.Elapsed);
Console.ReadKey();
}
字符串提供的各种方法
Length:获得字符串的长度
ToUpper() :将字符串转换为大写
ToLower():将字符串转换为小写
Equals(Equals(Two,StringComparison.OrdinalIgnoreCase)):比较字符串,忽略大小写
static void Main(string[] args)
{
////练习1:随机输入一个名字,然后输出他的字符串长度 Length:可以得到字符串的长度
//Console.WriteLine("输入名字");
//string name = Console.ReadLine();
//Console.WriteLine("{0}的长度是{1}", name, name.Length);
//Console.ReadKey();
////练习2:两个学员输入各自最喜欢的课程名称,判断是否一致,如果相等,则输出你们两喜欢相同的课程,
//// 如果不相同,则输出你们两喜欢不相同的课程
//Console.WriteLine("请输入你喜欢的课程");
//string One = Console.ReadLine();
//Console.WriteLine("请输入你喜欢的课程");
//string Two = Console.ReadLine();
//if (One == Two)
//{
// Console.WriteLine("你们喜欢的课程相同");
//}
//else
//{
// Console.WriteLine("你们喜欢的课程不相同");
//}
//Console.ReadKey();
//练习3:上题中两位同学输入C#和c#代表同一门课,怎么办
Console.WriteLine("请输入你喜欢的课程");
string One = Console.ReadLine();
// One = One.ToUpper();//将字符串转换为大写
// One = One.ToLower();//将字符串转换为小写
Console.WriteLine("请输入你喜欢的课程");
string Two = Console.ReadLine();
// Two = Two.ToUpper();//将字符串转换为大写
// Two = Two.ToLower();//将字符串转换为小写
if (One.Equals(Two,StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("你们喜欢的课程相同");
}
else
{
Console.WriteLine("你们喜欢的课程不相同");
}
Console.ReadKey();
}
5.Split():分割字符串,返回字符串类型的数组
////字符串的分割Split
//string s = "a b c sdf _ + = , asd";
//char[] chs = { ' ', '_', '+', '=' };
//string[] str = s.Split(chs,StringSplitOptions.RemoveEmptyEntries);
//Console.ReadKey();
/*
练习:从日期字符串{"2020-08-08"}中分析出年,月,日;2020年08月08日
让用户输入一个日期格式如:2020-01-02,你输入你输入的日期为2020年1月2日
*/
string time = "2020-08-08";
char[] chs = { '-' };
string[] date = time.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("{0}年{1}月{2}日", date[0], date[1], date[2]);
Console.ReadKey();
6.Replace() :替换字符
string str = "关键人物杨老";
if (str.Contains("杨老"))
{
//将杨老替换为**
str = str.Replace("杨老", "**");
}
Console.WriteLine(str);
Console.ReadKey();
7.Substring():截取字符串
//字符串截取
string str = "今天天空晴朗,处处好风光";
//只截取前面两个字符
//str = str.Substring(0,1);
//截掉第一个字符
str = str.Substring(1);
Console.WriteLine(str);
Console.ReadKey();
8.StartsWith()和EndsWith():以什么开头和以什么结尾,返回值都是bool类型
string str = "今天天空晴朗,处处好风光";
if (str.StartsWith("天天"))
{
Console.WriteLine("是的");
}
else
{
Console.WriteLine("不是的");
}
Console.ReadKey();
9.IndexOf和LastIndexOf:查找字符所在字符串中的位置。返回值都是Int类型
//string str = "今天天空晴朗,处处天天好风光";
////从什么位置开始找
//int index = str.IndexOf('天',2);
//Console.WriteLine(index);
//Console.ReadKey();
//string str = "今天天空晴朗,处处天天好风光";
//int index = str.LastIndexOf('天');
//Console.WriteLine(index);
//Console.ReadKey();
//LastIndexOf Substring 配合使用截取字符串
string path = @"C:\a\b\c\d\e\f\g\\hh\苍老师苍.wav";
int index = path.LastIndexOf("\\");
path = path.Substring(index+1);
Console.WriteLine(path);
Console.ReadKey();
10.Trim():去掉字符串中的空格
string str = " hahaha ";
str = str.Trim();//去掉字符串中所有的空格
str = str.TrimStart();//只去掉前面的空格
str = str.TrimEnd();//只去掉后面的空格
Console.Write(str);
Console.ReadKey();
11.IsNullOrEmpty():判断字符串是否为空
string str = null;
if (string.IsNullOrEmpty(str))
{
Console.WriteLine("是的");
}
else
{
Console.WriteLine("不是的");
}
12.Join():将数组按照指定的字符串连接,返回一个字符串
string[] names = { "张三", "李四", "王五", "赵六" };
//string str = string.Join("|", names);
string str = string.Join("|", "张三", "李四", "王五", "赵六");
Console.WriteLine(str);
Console.ReadKey();
字符串的练习(这个一定要练熟)
static void Main(string[] args)
{
////练习1.接收用户输入的字符串,将其中的字符以与输入相反的顺序输出
//Console.WriteLine("请输入一个字符串");
//string str = Console.ReadLine();
//char[] chs = str.ToCharArray();
//char temp = 'a';
//for (int i = 0; i < chs.Length/2; i++)
//{
// temp = chs[i];
// chs[i] = chs[chs.Length - 1 - i];
// chs[chs.Length - 1 - i] = temp;
//}
//str = new string(chs);
//Console.WriteLine(str);
//Console.ReadKey();
////练习2.接收用户输入的依据英文,将其中的单词以反序输出。
//Console.WriteLine("请输入一个字符串");
//string strOne = Console.ReadLine();
//string[] strNew = strOne.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
//for (int i = 0; i < strNew.Length/2; i++)
//{
// string temp = strNew[i];
// strNew[i] = strNew[strNew.Length - 1 - i];
// strNew[strNew.Length - 1 - i] = temp;
//}
////for (int i = 0; i < strNew.Length; i++)
////{
//// Console.Write("{0} ",strNew[i]);
////}
//strOne = string.Join(" ", strNew);
//Console.WriteLine(strOne);
//Console.ReadKey();
////练习3.从Eemail中提取用户名和域名:[email protected]
//string email = "[email protected]";
//int index = email.IndexOf('@');
//string name = email.Substring(0, index);
//string yuMing = email.Substring(index+1);
//Console.WriteLine("用户名:{0},域名:{1}", name, yuMing);
//Console.ReadKey();
/*
文本文件中存储多个文章标题、作者、标题和作者之间用若干空格(数量不定)
隔开,每行一个,标题有长有短,输出到控制台的时候最多标题长度10,如果
超过10,则截取长度8的子串并且最后添加"....",加一个竖线后输出作者的名字
*/
////1.拿到文本文件里面的数据
//string path = @"C:\Users\Administrator\Desktop\1.txt";
//string[] contents = File.ReadAllLines(path, Encoding.Default);
//for (int i = 0; i < contents.Length; i++)
//{
// string[] ss = contents[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
// Console.WriteLine((ss[0].Length>10?ss[0].Substring(0,8)+"......":ss[0]) + "|" + ss[1]);
//}
//Console.ReadKey();
////练习4.让用户输入一句话,找出所有e的位置
//Console.WriteLine("请输入一句话");
//string strTwo = Console.ReadLine();
//int index = strTwo.IndexOf('e');
//Console.WriteLine("第一次出现e的位置是{0}", index);
////循环体:从上一次出现e的位置加1的位置找下一次e出现的位置
////循环条件:index != -1
//int count = 1;
//while (index != -1)
//{
// count++;
// index = strTwo.IndexOf("e", index + 1);
// if (index == -1)
// {
// break;
// }
// Console.WriteLine("第{0}此出现e的位置是{1}", count, index);
//}
//Console.ReadKey();
////练习5.让用户输入一句话,判断这句话有没有邪恶,如有鞋子就替换成**
//Console.WriteLine("请输入一句话");
//string strThere = Console.ReadLine();
//if (strThere.Contains("邪恶"))
//{
// strThere = strThere.Replace("邪恶", "****");
//}
//Console.WriteLine(strThere);
//Console.ReadKey();
////练习6.把{"诸葛亮","卡卡西","鸟叔","卡哇伊"}变成诸葛亮|卡卡西|鸟叔|卡哇伊,然后再把|切割掉
//string[] strs = { "诸葛亮", "卡卡西", "鸟叔", "卡哇伊" };
//string strFor = string.Join("|", strs);
//char[] chs = { '|' };
//strs = strFor.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
//for (int i = 0; i < strs.Length; i++)
//{
// Console.WriteLine(strs[i]);
//}
//Console.WriteLine(strFor);
//Console.ReadKey();
}
四、面向对象(继承)
把多个类中重复的成员单独拿出来封装成一个类,作为这几个类的父类,从而解决多个类中出现重复的成员造成代码冗余
Student、teacher、driver 子类 派生类
Person 父类 基类
子类继承父类的:属性、方法。不能继承父类的私有字段
继承的特性
1、继承的单根性(子类只能继承一个父类)
2、继承的传递性(父类让一个子类继承后,其他子类在继承这个子类时,一样可以访问到父类。多个子类传递继承,则都可以访问到所传递继承的类)
子类不会继承父类的构造函数,但是,子类会默认的调用父类无参数的构造函数。让子类可以使用父类中的成员。
所以,如果在父类中重新写了一个有参数的构造函数之后,那个无参数的就被干掉了,子类就调用不到,所以子类会报错。
解决办法
1.在父类中在写一个无参数的构造函数(一般不这么做)
2.使用关键字:base调用父类中的构造函数
object是所有类的基类。
关键字:new隐藏父类成员
子类有成员跟父类成员重名,父类的会被默认隐藏
继承相关代码
父类
class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
public Person(string name,int age,char gender)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
}
public void SayHello()
{
Console.WriteLine("我是父类的SayHello");
}
}
司机类
class Driver:Person
{
public Driver(string name,int age,char gender,int driverTime):base(name,age,gender)
{
this.DriverTime = driverTime;
}
private int _driverTime;
public int DriverTime
{
get { return _driverTime; }
set { _driverTime = value; }
}
public void DriverSay()
{
Console.WriteLine("我是一名{0},我有{1}岁,我是{2}人,我的驾龄是{3}", this.Name, this.Age, this.Gender, this.DriverTime);
}
public new void SayHello()
{
Console.WriteLine("我是司机类的SayHello");
}
}
记者类
class Reporter:Person
{
public Reporter(string name,int age,char gender,string hobby):base(name,age,gender)
{
this.Hobby = hobby;
}
private string _hobby;
public string Hobby
{
get { return _hobby; }
set { _hobby = value; }
}
public void ReporterSay()
{
Console.WriteLine("我是一名{0},我有{1}岁,我是{2}人,我的爱好是{3}",this.Name,this.Age,this.Gender,this.Hobby);
}
//使用new关键字将从父类中继承的重名方法隐藏
public new void SayHello()
{
Console.WriteLine("我是记者类的SayHello");
}
}
程序员类
class Programmer:Person
{
public Programmer(string name,int age,char gender,int time):base(name,age,gender)
{
this.Time = time;
}
private int _time;
public int Time
{
get { return _time; }
set { _time = value; }
}
public void ProgrammerSay()
{
Console.WriteLine("我是一名{0},我有{1}岁,我是{2}人,我的工龄是{3}", this.Name, this.Age, this.Gender, this.Time);
}
public new void SayHello()
{
Console.WriteLine("我是程序员的SayHello");
}
}
在MAIN函数中调用
static void Main(string[] args)
{
//记者:我是一个狗仔,我爱好是偷拍,我的年龄是34,我是一个男狗仔
//司机:我叫舒马赫 我的年龄是43 我是男人 我的驾龄是23年
//程序员:我叫孙权 我的年龄是23 我是男生 我的工作年限是3年
Reporter reporter = new Reporter("记者",34,'男',"偷拍");
reporter.ReporterSay();
Driver driver = new Driver("司机", 43, '男', 20);
driver.DriverSay();
Programmer programmer = new Programmer("程序员", 25, '男', 3);
programmer.ProgrammerSay();
programmer.SayHello();
Console.ReadKey();
}