1、类
定义类的语法:
[访问修饰符] class类名
{
成员;字段、属性、方法都可以叫做类的成员,他们都需要定义访问的级别
}
最好一个类定义成一个cs文件并且类名和文件名起相同
类名一般使用pascal命名法
对象:
特征:属性:对象具有的各种属性:属性的值
行为:方法:执行的操作
怎么产生一个对象?
类是对象的类型
通过属性和方法来描述一个对象
类的实例化:
通过类来产生一个对象的过程叫做类的实例化(对象名或者叫做实例名)
语法:
类名实例名=new类()//new一下别忘了括号
Person zsperson=new person()
Person zsperson;
zsperson=new person;
相当于先定义一个变量zsperson,然后通过new产生一个对象并把产生的对象赋给变量zsperson
类的成员的访问:
实例名.属性 实例名.方法名()
Person zsperson=new person()
zsperson.name=“张三”
zsperson.sayhello()
program p=new program();
p.aaa();
附:String name=null与string name=“”区别?
例子:
class person
{
public int age //建议加public,不加public则访问不到了
public char sex
public string name
public void sayhello()在自己定义的类中,写方法时先不加static!!
静态方法只能访问静态的属性,所以用非静态的
{
Console.Writeline(“输出“)
}
//Static void method()静态方法:
//此处的method就可以不用实例化直接类名.方法名person.method就可以了因此
//这种情况可以单独定义个类而不用和不加的混在一起导致混乱(个人理解)
{
}
static void main(string[] args)
{
Person zsperson=null;只声明了变量没有实例化这个属性,
Person zsperson=new Person();
zsperson.name=“张三”;
zsperson.age=10;
zsperson.sex=’男’;
zsperson.sayhello();
string name= zsperson.name;
}
只要是没有加static的方法和属性,都必须先实例化()new,再通过实例名.方法名或者实例名.属性来访问
加static的方法或者属性可以直接通过类名.方法名或类名.属性名来访问
Class program
{
int test;
void method()
static void main(string[] args)
{
test是访问不到的,program.test也访问不到
必须先实例化类Program p=new Program
p.test=””;
p.method();就可以访问了
Class program
{
static int test;
static void method()在main方法同一个类内部定义的方法一般都加static
Static void main(string[] args)
{
//直接可以通过类名.方法,名类名.属性名访问
program.test;
Program.method();可以访问到
如果是访问本类(同在program一个类中)的属性和方法还可以省略类名进行访问test;method();这样就和之前的感觉一样了
Console.writeline为什么可以访问到就是加了static
类中定义方法时前面不要加static,因为在静态访问时只能访问静态的属性不能访问实例属性,main方法是static静态的
不需要new时加static 需要new后再调用则不加static
所以会出现在自己定义的类中定义方法时不加static
在main方法内部调用定义的方法时要加static
所以:在自己定义的类中,写方法时先不加static!!!!!!!!!!!!!!!!!!
附:
不仅类能定义方法,结构也可以定义方法int.tryparse就是结构中定义的类
2、public访问修饰符引申
访问级别的用处在于控制成员在哪些地方可以被访问,这样达到面向对象中封装的目的
四个访问修饰符:
public private( internal protected)
Public可以在任何地方被访问
Private只能在本类中被访问
Internal只能在本项目中被访问
Protected只能在本类中和子类中被访问
如果一个类中定义变量或方法时,没加public则默认为private
在类的里面方法的外面默认访问修饰符为private
在命名空间内,在类这个级别不写访问修饰符默认为internal (如结构、枚举)
多个项目之间的调用时才考虑到internal
讲三层架构时:
层与层之间类的调用,自己手动加上public
3、字段和属性
类中直接定义的变量其实应该叫做字段,不能叫做属性。
方法中定义的变量没有访问修饰符这一说,不允许加访问修饰符
定义的变量称为局部变量,只在方法内有效
属性:
定义一个public变量,变量中含有get和set两个方法,我们就叫做属性(跟定义字段时差不多)
属性是为了保护与之相对应的字段的,保证对字段的读取和赋值符合要求
凡是允许外部访问的变量一定要声明为属性,通过属性保护起来才能保证赋值的合法性
先进行判断先set判断然后通过get返回
这样age的值就能很好的保护起来,我们只要引用Age就行了
实例:
classPerson
{
publicchar sex;
publicstring name;
privateint age; //先改为私有的
publicint Age //通过一个公共属性(变量)保护一个私有变量
{ //我们只看到Age而没有看到age,从而通过访问属性来保护字段的过程就是封装的概念
get
{
return age;//返回小写的age
}
set
{
if (value >= 0)//这里有个关键字,value中存储着用户赋的那个值
{
age =value;
}
else
{
age = 0;
}
}
}
}
classProgram
{
staticvoid Main(string[] args)
{
Person zsperson =new Person();
zsperson.sex ='男';
zsperson.name ="张三";
zsperson.Age = 15;
int aaa = zsperson.Age;
Console.WriteLine("我是{0},性别{1},年龄{2}", zsperson.sex,zsperson.name, zsperson.Age);
}
}
微软自动生成get set属性的过程:
{
privateint age; //先private保护起来不让用户访问到
//int age; //在类中不写修饰符默认为private
publicint Age //公有的用大写开头pascal 私有的用小写开头camel
{
get
{
return age;
} //取值
set
{
age =value;
} //赋值(检测)value就是存储用户赋的那个值
}
privatechar sex;//在这一行右键重构,点封装,确定就变成了 或者使用快捷键Ctrl R+E
publicchar Sex
{
get {return sex; }
set { sex =value; }
}
//不管前面是private还是public封装之后就都是private了
}
读写属性:
只读只写读写区别就是get/set的拥有个数、
只读;有get没set
只写;没get有set
读写;get set两个方法都有
4、构造方法
当我们实例化一个类的时候,系统会自动对这个类的属性进行初始化。
然后我们赋值,所以对象中必须对属性赋值
为什么会出现构造方法:
1、有只读属性的时候在什么地方赋值
2、一旦只读则在实例化时也将不能赋值了
3、不能在类定义中直接赋值,因为以后调用时实例化的其他对象将会一样
使用构造方法的好处:
1、对多个属性进行赋值时,不需要重复的写实例名
2、可以保证用户在new一个对象的时候必须对某一个属性进行赋值
3、在创建对象时,对只读属性可以进行初始化
怎么创建构造方法:如何定义构造方法:
当我们定义好一个类之后,如果我们没有写构造方法,那么系统就会自动给我们加上一个默认的没有参数的构造方法,在这个构造方法中什么也不做,我们也看不到
这就是即使没有写构造方法格式也得这样写的原因。
Student zsstudent=new Student();创建对象时,有这个括号其实就是在调用构造方法
构造方法特点:构造方法是一个特殊的方法,他的名字和类的名字相同,并且没有返回值,连void都可以省了不写,我们一旦手写一个构造方法后,系统原先默认给我们添加的那个无参的构造方法就不会再为我们添加了
构造方法:方法的名称和类的名称一样,并且没有返回值
什么时候调用构造方法? 在初始化类的成员时
要实例化一个类必须调用它的构造方法
构造方法传参来对变量进行初始化
构造方法可以有多个参数,将参数赋给相应的字段,也可以赋给属性。
例子:
namespace构造方法练习
{
///<summary>
///类中设置构造方法
///</summary>
classStudent
{
//***怎么确定是构造方法?方法的名称与类名相同并且没有返回值!!!!!!!!***
public Student() //如果定义了有参构造方法的时候,就把默认的屏蔽掉了
//要想调用无参数的构造方法则必须重新定义
//根据重载可以自己再写一个无参的构造方法,本身就构成了重载
{
}
public Student(stringname,intage) //定义构造方法,不加public是访问不到的
{
//字段this.name=参数name; //this.name指示代词当前类中的字段
//字段颜色一样的是指向一个字段this.name=参数name;
this.name=name;
this.age =age;
}
public Student(string name,int age, char sex,int chinese,int math,int english)
//构造方法的重载
{
this.name = name;
this.age = age;
this.sex = sex;
this.chinese = chinese;
this.math = math;
this.english = english;
}
//一般使用构造方法都是用于对类的成员进行初始化
//定义构造方法时内部的参数必须在下面有相对应
string name;
publicstring Name
{
get {return name; }
}
//set{ } 只有get没有set变成只读的!!
int age;
publicint Age
{
get {return age; }
set { age =value; }
}
char sex;
publicchar Sex
{
get {return sex; }
set { sex =value; }
}
int math;
publicint Math
{
get {return math; }
set { math =value; }
}
int chinese;
publicint Chinese
{
get {return chinese; }
set { chinese =value; }
}
int english;
publicint English
{
get {return english; }
set { english =value; }
}
publicvoid SayHello()
{
Console.WriteLine("我是{0},我的性别是{1},年龄是{2}", name, sex, age);
}
publicvoid ShowScore()
{
Console.WriteLine("数学成绩{0},语文成绩{1},英语成绩{2}", math, chinese, english);
}
}
}
namespace构造方法练习
{
classProgram
{
staticvoid Main(string[] args)
{
//要实例化一个类必须调用它的构造方法
Student aa =newStudent();//自己定义的一个无参数的构造方法,默认自动赋初值
Student zsStudent =new Student("张三", 18);
//再zsstudent.name=“张四”;是错误的
只读属性只能在构造方法实例化的时候赋值
//zsStudent.Name="张三";
//zsStudent.Age=18;
zsStudent.Sex ='男';//等其他一样
zsStudent.Math = 87;
zsStudent.Chinese = 98;
zsStudent.English = 86;
Student xlStudent =new Student("小兰", 16,'女', 85, 68, 96);//要实例化一个类必须调用它的构造方法,只能调用有参数的构造方法,并且参数个数对应相同
//zsStudent.Name="小路";
//zsStudent.Age=16;
//zsStudent.Sex='女';
//zsStudent.Math=85;
//zsStudent.Chinese=68;
//zsStudent.English=96;
Console.WriteLine("下面输出的是默认情况:");
aa.SayHello();
aa.ShowScore();
Console.WriteLine("下面输出的是张三学生的学习成绩:");
zsStudent.SayHello();
zsStudent.ShowScore();
Console.WriteLine("下面输出的是小兰学生的学习成绩:");
xlStudent.SayHello();
xlStudent.ShowScore();
Console.ReadKey();
}
}
}
5、构造方法的重载
构造方法的重载和一般方法是一样的
要实例化一个类必须调用它的构造方法
初始化类的成员时常用到构造方法
对属性方法进行赋值
当对类的成员赋值时,如果一个全部赋值一个只想赋三个怎么办?
通过构造方法的重载来解决
方法的重载:
用到在同一个类中,方法的名称相同,参数个数不同对应位置类型不同
方法是可以重载的,构造方法同样可以重载
6、、认识类图
拿到类:
首先看有什么构造方法及其参数,才能实例化的时候确定调用那些构造方法和传那些参数
****实例化之后需要关心那些属性和方法可以让我们来调用***
其实我们只关心类中的方法就行了,方法的功能方法的使用就行了。具体内部怎么实现的不关心
当代码复杂的时候查找是比较麻烦的,所以引出类图
矩形通用类图
1层 类名student
2层 字段和属性
-age:int
-name:string
+Name:string
-表示私有private +表示公有public
3层 方法 +Sayhi():void
C#专用类图:
右键:“查看类关系图”
7、可变参数params
int sum=Sum(1,2,3,4,5);
Console.Writeline(sum);
static int Sum(paramsint[] arr)//怎么回事一下子能传好几个?上面int的是sum不
是数组?????自动变成了一个数组?!
{
}
static int Sum(paramsint[] arr,int age)正确
static int Sum(int age,paramsint[] arr) 错误
可变参数必须作为最后一个参数
8、命名空间:
命名空间是解决类重名问题,可以看做类的文件夹
相同名字的类产生冲突,最好将类放到命名空间里面
命名空间中放类:
一个命名空间肯定是在一个文件中?不一定可能很多类放到相同命名空间下
访问位置和要访问的类在同一个命名空间namespace下能直接访问到类名,
则不需要using
如果不在同一个命名空间下则不能直接访问
在不同的命名空间下的类在调用有两种方法:
a、写全称命名空间.类名 System.Threading.Thread 调用线程这个类
b、先 using 引用命名空间再调用(即导入命名空间)
(自动引用(ctrl+.)在保证把类名写准了)
所有的命名空间都在system命名空间中
常用命名空间
threading
text
data
collection
命名空间下可以包含命名空间
项目?
不是在一个文件下嵌套几层,而是再建一个文件,在定义时指定为上级命名空间下的命名空间
.net的命名空间表示的是逻辑上的划分
真实文件下的命名空间表示的是物理上的
9、字符串操作处理
类与结构的关系:
string类
string可以看做char的只读数组
string =”abcdefg”;
for(int i;i<s.Length;i++)
{
console.write(s[i]);
}
C#中string的特性:字符串一旦声明赋值就不能改变,是只读的
只能通过索引来读取指定位置的char,不能对指定位置的char进行修改
如果要改变某一元素的值
char[] chars=to.chararray();通过to.chararray得到字符数组
方法s.tochararray的返回值是char数组
chars[2]=’i’ ;修改字符数组的值,char数组的修改不会造成字符串的改变
s=new string(chars);通过调用字符串构造方法new string(char[]),创建chars数组的新字符串
console.write(s);
聚焦:像person类也可以不new可是却不能将对象赋值给他
而string类可以直接用“ ”括起来就是字符串直接赋值
例:
大小写识别: C#与c#
判断全转大写或转小写之后比较
string scoreA=”C#”;
string scoreA=”c#”;
if(scoreA==scoreB)
{
console.writeline(“选择相同课程”)
}
else
{ console.writeline(“选择相同课程”)
}
10、引申:
msdn自学
string类常用方法
查看类msdn静态非静态才知道怎么调用这个类
字符串是不可改变的所以这些函数都不会直接改变字符串的内容,而是把修改后的字符串的值通过函数返回值的形式返回
[访问修饰符] abstract class 类名
Tostring方法
.length属性
ToLower(); 取得字符串的小写形式
ToUpper(); 取得字符串的大写形式
Trim(); 去掉字符串两端的空白
s1.Equals(s2,StringComparison.OrdinallgnoreCase)
两个字符串进行比较不区分大小写返回bool类型
string.Equals()方法
scoreA.Tolower();
string str= scoreB.Tolower();//字符串本身没有改变必须用一个字符串来接收
scoreA = scoreA.Tolower();//可以赋值回去
scoreB = scoreB.Tolower();
console.writeline();
if(scoreA== scoreB) //区分大小写
if(scoreA.Equals(scoreB))//区分大小写
if(scoreA.Equals(scoreB,StringComparison.OrdinallgnoreCase)//忽略大小写
{console.writeline(“选的课相同”);
}
else
{ console.writeline(“选的课不同”);
}
string[] Split(params char[] separator );
string str=” How are you?Fine,thank you!”;
string [] words=str.Split(‘ ’,’?’,’!’,’,’);//char数组
不能一个一个字符放进去,params
char [] removeChar={‘ ’,’?’,’!’,’,’}
string [] words=str.Split(removeChar ,StringSplitOptions. (枚举)RemoveEmptyEntries);
console.writeline(“这句话有{0}个单词。”,words.Length)
console.writeline(“这几个单词分别是:”)
for(i=0;i<words.length;i++)
{
console.writeline(words[i]);
}
console.readline();
console.writeline(“{0}{1}{2}”,words) 传数组
console.writeline(“{0}{1}{2}”,words[1],words[],words[]) 传元素
练习:分析字符串2008-08-08输出2008年08月08日 string.split(‘-’)
分析字符串2008/08/08输出2008年08月08日string.split(‘-’,’/’)
string [] sp=data.Split(new char[] {‘-’,’/’} ,StringSplitOptions.
RemoveEmptyEntries);
console.writeline(“{0}年{1}月{2}日”,sp)
字符串的不可改变性:
变量指向的字符串改变了
不是该字符串的内容改变了
该字符串就一直在那
只不过是变量名字指向了新的字符串
string str=“hello word!”;
str=“abc”;
str=str.replace(“b”,“d”);
s1=“hello word!!”
string s10=s1;
s1=“abcdefg”;
此时s10仍然指向“hello word!!”这个字符串
详情请查看: