C#面向对象(四)

C#面向对象

面向对象思想:面向过程的编程常常会导致所谓的单一应用程序,即所有的功能包含在几个模块(常常是包含在一个代码模块中)。而使用oop(面向对象)技术,常常要使用许多代码模块,每个模块都提供特定的功能,每个模块都是孤立的,甚至与其他模块完全独立。这种模块化编程方法提供了非常大的多样性,大大增加了代码的重用机会。

在传统的应用程序中,执行流常常是简单的、线性的。把应用程序加载到内存中,从A点开始执行到B点结束,然后从内存中卸载,这个过程可能用到其他各种实体,例如存储介质的文件或视频卡的功能,但处理的主体总是位于一个地方。而使用oop,事情就不是这么直接了,尽管可以获得相同的效果,但其实现方式是完全不同的。Oop技术以结构、数据的含义以及数据和数据之间的交互操作为基础,这通常意味着要把更多的精力放在项目的设计阶段,但项目的可扩展性比较高。一旦对某种类型的数据的表达方式达成一致,这种表达方式就会应用到应用程序以后的版本中,甚至是全新的应用程序中。这样将大大减少开发时间。

(一)类:

类描述一组相似对象的共同特性。类和结构实际上都是创建对象的模板,并提供了处理和访问数据的对象。

类定义以下要素:

1.  定义该类的对象所操作的数据结构(attribute的名称和类型);

2.  这些对象要执行的操作,尤其是哪些操作,类的对象如何被调用执行这些操作,以及对象执行这些操作是的“后台运作”。

注:在类里面声明变量必须说明变量是共有的还是私有的或着是保护的。

public int i;//声明了一个int变量,而这个变量是共有的,就是说,在客户端只要实力化对象后就能在客户端使用他了。如果定义成私有的provate,那么在客户端就算实力化对象后也不能使用他。

类的定义:

(二)什么是对象

对象就是oop应用程序的一个组成部件。这个组成部件封装了部分应用程序,这部分程序可以是一个过程、一些数据或一些更抽象的实体。

C#中的对象是从类型中创建的,就像前面的变量一样,对象的类型在oop中有一个特殊的名称:类。可以使用类的定义实例化对象,这表示创建该类的一个实例。

“类的实例”和对象表示相同得的含义,注意“类”和“对象”是完全不同的概念。

注:类是一系列实物的共体的抽象,而对象才是真正的实体。类是将相同实体抽象的描述为某一类别的事物。

如:将所有学生抽象为一个类,所有老师为一个类,而每个学生是学生类的一个类的实例(类是抽象的,具体的学生才是真实存在的),或说学生类的一个对象,所以说对象是类的一个实例。(实例:一个真实存在的例子)。

所有学生都有课程,假期,书本,上课,下课,选课等相同特性,先将他们抽象为一个Student类在Student类里面有上面这些属性。但是类本身不能实现自己啊,他是不真实存在的,所以要实例化一个对象创建了一个对象后就好像创建了某一个学生,假如我是这个学生,那么我就可以真正的去上课,去选课,但是Student类本身不能去上课,去选课。只有实例化化后(如同我实例化后,就相当于该类的一个实例)我是该类的实例(真实存在的一个例子)那么我就可以去上课,选课了。

对象是真实存在的,而类是对某一类具有相同特性的对象的一个抽象模型。

注:对象只能做所属类已定义的方法所规定的操作。

如:现在本田公司定义一个汽车类,这个汽车类里面定义了轮子、螺丝、底板、方向盘、玻璃、座椅、刹车、油箱等。而你是设计师,在公司汽车这个类里面你要创造出一辆汽车来。轮子、螺丝、底板等那些都是公司里面现有的,你现在要创造一辆汽车,你不能用公司里面没有的东西,而你创建出一辆汽车的时候,这辆汽车就是汽车类的一个真实存在的例子,他是真实存在的。

对象和类的关系进一步说明:类就好像是一个byte类型,byte类型规定被定义为byte型的变量只能在0——256之间。超出这个范围就溢出,程序就会出错。

类也是一样,规定一些范围,然后用类名来定义一个变量(准确点说应该是引用变量,因为类定义的变量是引用行的)时,这个变量也只能在类的范围里,而用new关键字来真正的在内存中创建一个全新的对象,这个全新的对象里面放着类里面的字段、属性、方法,每新建一个对象。

就如:我是房地产商,在我卖房这前,我先建立一个房子模型告诉顾客这片地将建成什么样的房子(就像定义一个类,类里面有些什么方法,属性,字段),他听后就赋钱给我了,我就用这些钱在这块地盖一栋真实的房子就好像用new在内存中创建了一个对象)。我只有一个模型,所有给我买房的人他们的房子都是照着这个模型来做的,建出来的房子和这个模型一模一样,他不会多什么,也不会少什么,只不过模型不能用,而照着模型新建的房子才能用,所以所有买房的人都会得到一栋相同的相互独立的房子。付了钱的顾客可以根据房子的物理地址来找到他的房子(因为每新建一栋房子,房子物理的地址都会不同),当付了钱的顾客通过物理地址找到房子后,他可以可以随便用房子里面的东西,他也可以可以将房子装修成自己喜欢的样式。

解说:public class Home

     

         private string 沙发;

         private string 们;

         private string 电视;

         ……

      

 Public class 售楼部

{

Public static void main(String arge[])

{

Home 顾客1//没有房子,因为他们是来看的,还没有买房;

Home 顾客2

Home 顾客3

new  Home();//在地上照着Home类这个模型建了一栋真实的房子

Home 付了钱的顾客=new Home();//付了钱的顾客我就给他一懂真实的房子。

//当“顾客1付钱后

顾客1=new Home();//我也给他一栋新房子;

}

}

注:每new Home()一次,都会在没有被占用的内存中新建一个对象(在空余的地皮上新建一栋房子),而不是替换原来的对象,所以每个对象都是互相独立在内存中的,他们互不干涉。

Home 顾客1//这里并没有创建一个对象,只是定义了一个引用变量。

New Home();//这里在内存中创建了一个对象。(在内存中创建那么说明他是占内存的)。

顾客1=new Home(),将“顾客1”的引用指针指向new Home()创建的对象的内存地址。

对于new Home()没有引用变量指针的指向。那么c#会自动将从内存中销毁,防止占用内存。因为他没有引用变量指针的指向,他虽然占用内存,真实存在,但他没有被用到。那就是无用的对象,所以要将他销毁。

(三)成员定义

在类定义中,也提供了该类中所有成员的定义,包括字段、方法和属性,所有的成员都有自己的访问级别,下面的关键字之一来定义:

最后两个关键字可以合并使用,所以也有protected internal成员。它们只能由项目中派生的代码来访问。

字段、方法和属性都可以使用关键字static来声明,这表示它们是类的静态成员,而不是对象实例的成员。

 

(三)属性和字段

属性字段可以访问对象中包含的数据,这个对象数据可以用于区分不同的对象,因为同一个类的不同对象在属性和字段中存储了不同的值。

1.字段

asp.net中,公共字段以PascalCasing形式来命名,而不是camelCasing。这里使用这种命名方法,。

字段用来存储与类有关的数据,字段是与类相关的变量。

字段和变量的区别:直接在类中的数据成员为字段,他用访问修饰符和数据类型类定义

public string name;),字段就像类的一个小数据库,用来存放与类相关的数据;而单纯的变量是没有修饰符的(int age;),他不能直接在类里面定义,只能在函数里面定义,他用来作为方法的一个临时变量。

字段也可以使用关键字readonly,表示这个只读字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值。

Class MyClass

{

   Public readonly int MyInt=12;

}

2.属性的定义

属性用来隐藏字段,提高字段的安全性。

属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块由于设置属性的值,

这两个块也称为访问器,分别用getset关键字来定义,可以用于控制对属性的访问级别。可以忽略其中的一个块来创建只读或只写属性(忽略get块创建只写属性,忽略set块创建只读属性)。还可以将set设置为受保护的,get设置成公共的。属性至少要包含一个块,才是有效的。

Get块必须有一个属性类型的返回值。简单的属性一般与一个私有字段相关联,以控制对这个字段的访问,此时get块可以直接返回该字段的值。

Private int myInt;//一个字段

Public int MyIntProp//一个属性

{

  get { return myInt;}

  set {myint=value;}

//value等于类型于属性相同的一个值,所以如果属性和字段使用相同的类型,就不必担心数据类型转换了。

}

注:属性可以使用virtualoverrideabstract关键字,就像方法一样,但这几个关键字不能用于字段。

public class person       //定义基类

    {

        private string name;

        private string adress;

        public string Name

        {

            get { return name; }

            set {name = value; }

        }

        public string Adress

        {

            get{return adress; }

            set{adress = value; }

        }

public  void print()

        {

       Console.WriteLine("姓名: " + Name + "\n" + "地址" + Adress);

        }

}

public  class Student:person        //继承person

    {

        private string studentId; //定义一个字段

        public string StudenId//定义一个属性

        {

            get{return studentId; }

            set{ studentId = value; }

        }

        public void print1()//定义一个方法,但是不能和基类的方法重名哦!如果和基类的重名了,那么会把基类的方法给隐藏掉。如果真的想隐藏掉基类的方法,那么可以在前面加一个new关键字。

        {

            Console.WriteLine("学号" + StudenId+"\n");

        }

}

public  class Professor:person

    {

        private string title;

        public string Title

        {

            get{ return title; }

            set{title = value; }

        }

        public void print1()

        {

            Console.WriteLine("官位 " + Title);

        }

    }

class Program

    {

        static void Main(string[] args)

        {

            Student s = new Student();

            s.Name = "报文";

            s.Adress = "云南农业大学";         

            s.print();//调用基类中的方法;

            s.print1();//调用自己类中的方法;

          

            Professor p = new Professor();

            p.Title = "教授";

            p.Adress = "云南农业大学";          

            p.print();

            p.print1();

            Console.Read();

        }

    }

(四)方法的定义

 

(五)对象的生命周期

每个对象都有一个明确定义的生命周期,除了“正在使用”的正常状态之外,还有两个重要的阶段:

构造阶段:对象最初进行实例化的时期,这个初始化过程称为构造阶段,由构造函数完成。

析构阶段:在删除一个对象时,常常需要执行一些清理工作,例如释放内存,这由析构函数完成。

(六)访问器

1.访问器

访问器包括:get取值器(外面从get取值)、set赋值器(外面赋的值先赋给set,然后通过set赋值给私有变量)

  class Program

    {

        static void Main(string[] args)

        {          

            Person1 p1 = new Person1();

   19   p1.Age = 39;//赋值

   20   p1.Age = p1.Age + 1;// 右边的p1.Age要从Person1中取值,但是person1只返回了一个3给我,那么我就用3139怎么也用不到了),然后再对左边的p1.Age赋值,因为给person1Age赋值要通过Ageset赋值器来赋值,但set不接受外界传过来的值,无论外界怎么赋值都相当于没有赋值;

            Console.WriteLine(p1.Age);// 这里输出的结果是3p1.Age现在要输出了,那么他要先将值取出来才能打印啊。所以又要到person1中去拿,结果person1中的取值器get返回给我个3;所以打印出一个3来;

           Console.ReadKey();

        }

    }

class Person1

    {

  31行:      private int age;//set接受进来的值存在age里面;而这里不用age来存值,因为set什么也不接收所以也用不着存值。

33行:  public int Age

        {

            get  //set大哥给我个值我想用就用,不想用我就自己给自己个值;当用户来想我拿值的时候我可以从set大哥那里拿来的,也可以用我自己的;

            {//不管谁向我要值(20行,21行向我要值)我都给他个3,这里我不返回age中存储的值;  

             return 3;

            //return age;返回存储里面的,也可以返回其他值

            }

37行:    set//用户给的东西要不要由我说了算;如果我要的话,get就可以从我这里拿,get也可以不拿自己给自己一个值;         

  {//对用户端的值(第19行,第20行对我赋值)我不踩取,我什么都不要;

// age = 10;age可以等于自己定义的一个数值,也可以等于用户传过来的值

//age=valuevalue是用户赋过来的值(age=Age=value=P1.Age=10)。

注:P1.Age=10用户对Age赋值;Age没有内存空间,他只是一个访问器,所以将传进来的值放到了age31行定义了age,就为他分配了内存空间);

            }

        }

    }

步骤分析:person1的执行过程为:19(我给37赋值),3719给我个值但是我不要),20(33行取个值)33(返回个3给他)20(3+1等于4赋值给37)37(我还是不要)21(我想输出p1.Age请给我个值,去33行拿)33(我这里只有3,给你)

总结:1.从上面这个例子说明;set是用户给他赋值,在外面拿来的值,最终要交给set

2.get是用户来向他取值的。当外面要用值的时候,就来get这里拿。而get所给用户的值可以是自己给的也可以是从set大哥那里拿来的;

3. 当定义为私有的时候通过公有方法可以将值从外面传进来,而这个公有方法可以对外面的值做一个过滤,可以接受、不接受、还可以接受后随意改变。

4.私有变量外面需要通过公有方法才能传进来。像上面的set是不接受外面的值的,但是里面他自己可以更改;里面更改后可以随意的用而不用问get去拿。外面要用类里面的私有值的时候必须经过get来拿,get给什么他就拿什么,但是在类本身里面他可以不用从get哪里拿,他可以自己随意改变,而不用管set是否接收;

对第4点总结一句话:getset是外面对私有变量赋值与取值的转换器,而对类自己里面不用通过他们,直接赋值,直接取值;外界赋通过set赋进来的值被放在了私有变量中了。当类自己为变量赋值或取值时,类里面说了算,外面赋值相当于给了私有变量一个初始值,如果类里面自己对他从新赋值了,然后再取值,当然取到的是新值了。

注意:c#里面如果类中的变量如果没有赋初值也可以用,他的默认值为0

2.访问器的过滤作用

setget里面这个一些条件来达到过滤的作用,如果变量定义为公有的,那么这个变量的getset就不用写了,用户可以直接给公有变量赋值,而不用通过访问器来赋值,所以getset也就起不了作用了。

class Program

    {

        static void Main(string[] args)

        {

            Person p = new Person();

            p.Age = 10;

            p.Sex = "";

            p.Name = "小王";

            p.Point();

}

     }

class Person

    {

        private int age;

        private string name;

        private string sex;      

 

        public int Age //Age不保存值,通过set将值保存在age里面;

        {

            get //取值

            {

                return age;

            }

            set //赋值

            {

                if (value < 0)// 如果是公有的,那么在这里设置就不起作用了。因为公有的可以直接在用户端赋值,而私有的必须通过公有方法才能将值传递进来;

              {//这里相当与设置了一个私人的过滤器,自己可以选择自己想要的,如果是公有的就不可以了。

                    Console.WriteLine("你输入的值不符合要求");

                    return;

               }

                age = value;// value是用户赋值过来的值;

            }

        }

        public string Name

        {

          get//因为是name是私有的,在这里可以将拿来的值进行添、删、改或直接不要,一切有我get说了算。

            {

                if (name == "大王")//假如我拿到的name==大王,当用户向我要值的时候我就在name上添加一个总经理;

                { return name + "总经理"; }

                else

                {  return name; }

            }

            set

            { name = value; }

        }

        public string Sex

        {

            get

            {  return sex;  }

            set

            {

                if (value == "")

                {

                    Console.WriteLine("对不起,小姐,这里是男人俱乐部");

    return行:            return;// 这里的返回只是返回Sex外面去,不执行Sex里面在return之下的语句;

                }

                sex = value;// 如果是女的就不可能将值赋给sex,前一步就直接被返回去了。

            }

        }

        public void Point()

        {

            Console.WriteLine("你好{0},欢迎来到儿童俱乐部,你有{1}岁,你{2}",Name,Age,Sex);

        }

    }  

注:如果私有变量时字符串型,我们没有给他赋值,则默认为null;而整型的话,没有赋值,则默认为0。这个的sex=女,当执行到“return行”是就被返回去了,那么就没有对set赋值了。所以set为空。

 

3.引用型与值传递

值类型的值是放在线程堆栈上的,在堆栈上没有“同步快”和“方法表”只有值;

引用类型的值是放在托管推上的,在托管堆上有“同步快”和“方法表”加上引用类型的值。

值传递是将一个值赋值过去。

//------------------------------值传递

            int i = 10;

            int j = i;// j复制了i的值;当ij=i值后改变时j并不会改变;

            i++;

            Console.WriteLine(j);//j当然是10啦。

//-------------------------------引用型

class Program

    {

        static void Main(string[] args)

        {          

            Person p1 = new Person(5);

            Person p;

            p = p1;// p,p1指向了同一个对象;这就是引用;

            p1.Age++;//p1.Age++他令pp1他们同指的对象改变了; 所以p.Age也跟着改变(因为他们指向同一个对象);               

            Console.WriteLine(p.Age);

 

            Person p2 = new Person(10);

            p = p1;

            p1 = p2; //p1指向了p2所值的对象,他并没有改变原先的对象;而p现在还是指着原来的对象;所以p.Age并没有改变;       

            Console.WriteLine(p.Age);

            Console.ReadKey();

        }

    }

class Person

    {

        //public int age1;//一个变量

        public int Age { get; set; }//Ageperson的一个属性;而不是一个变量;

        public Person(int age)

        {

            this.Age = age;

        }

    }

posted @ 2011-10-14 17:23  放眼世界  阅读(1067)  评论(0编辑  收藏  举报