• C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态


    C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态


     

    类/接口/成员修饰符

    C#修饰符---接口:

    接口默认访问符是internal
    接口的成员默认访问修饰符是public

    C#修饰符--类:

    public、internal、 partial、abstract、sealed、static

    C#修饰符--类成员修饰符:

    public、protected、private、internal、sealed、abstract、virtual、override、readonly、const

    简单介绍:

    Public:最开放,所有的本程序集以及其他的程序集里面的对象都能够访问

    Protected:比较开放,自身成员以及子类成员可访问

    Private:只有自身成员才能够访问

    Internal:本程序集内的成员可以访问

    Partial:部分类,可以将一个类分成几部分写在不同文件中,最终编译时将合并成一个文件,且各个部分不能分散在不同程序集中

    Abstract:修饰类的时候表示该类为抽象类,不能够创建该类的实例。修饰方法的时候表示该方法需要由子类来实现,如果子类没有实现该方法那么子类同样是抽象类;且含有抽象方法的类一定是抽象类

    Sealed:修饰类时表示该类不能够被继承,修饰方法时表示该方法不能被覆写。

    Static:修饰类时表示该类时静态类,不能够实例化该类的对象,既然不能实例化该类,那么这个类也就不能够含有对象成员,即该类所有成员为静态;修饰类成员时,该成员为类成员,只能通过【类.成员名】的方式访问

    当static修饰构造函数时,构造函数不能含有任何参数,不能含有修饰符,构造函数不能对对象成员进行初始化操作。但是能够对静态成员进行初始化或者调用。不能保证他在什么时候执行,却能保证在第一次使用类型前执行。在静态构造函数中初始化的静态成员为最终初始化结果。

    Virtual:修饰方法成员,表示虚方法。父类可以含有该类的实现,子类可以覆写该函数。

    Override:表示该方法为覆写了父类的方法。

    Readonly:修饰字段,表示该字段为只读字段。

    注意:readonly修饰引用类型时由于操作不当可能修改该只读对象状态。例如:

    Readonly List< Person> persons=….;

    我们可能在某些地方对persons 进行了修改:persons.add(new Person());

    Const:修饰字段,表示该字段为只读字段。并且在编译时必须能够明确知道该字段的值,其值是硬编码到程序中去的,修改了该类型成员后需要重新编译才能使修改生效。

    而readonly是运行时只读,内容在运行时确定,所以修改了readonly类型成员后无需重新编译即可生效。

    Readonly不能修饰局部变量,const可以。

    注意:当一个类或方法没有被任何修饰符修饰时,默认为internal:


    多态、重载、重写

    重写:是指重写基类的方法,在基类中的方法必须有修饰符virtual,而在子类的方法中必须指明override。

    格式如下:

    1.在基类中: 

    1 public virtual void myMethod() 
    2 {
    3 }

    2.在子类中: 

    1 public override void myMethod() 
    2 {
    3 }

    重写以后,用基类对象和子类对象访问myMethod()方法,结果都是访问在子类中重新定义的方法,基类的方法相当于被覆盖掉了。

    重载:用于在给定了参数列表和一组候选函数成员的情况下,选择一个最佳函数成员来实施调用。

     
    1 public void test(intx,inty){}
    2  
    3 public void test(intx,refinty){}
    4  
    5 public void test(intx,inty,stringa){}

    重载的特征:

    • 方法名必须相同
    • 参数列表必须不相同,与参数列表的顺序无关
    • 返回值类型可以不相同

    但如果有泛型,就要注意了!

    多态:c#的多态性主要体现在类的继承上

    子类继承父类的时候,可能出现同名但方法定义不同的情况, 所以在子类中会将原方法覆盖,实现自身的要求.

    总结一句话:通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态。

    需要注意的地方有两点:

    1. 可以在子类中被重写的方法一定要被标记成virtual(虚拟), abstract(抽象), override(重写)标记为virtual 和abstract 的函数就是为了重写而创建的,标记为override的函数本身是由前两种函数重写而来的,所以它可以被重写也是顺理成章的了;
    2. 重写的函数必须在子类中出现,而且任何一个父类的函数在其一个子类中只能被重写一次。(这一点很好理解,当你要重写两次时,该子类中将定义两个返回类型,方法名称 和参数列表都相同的函数,这肯定是不可能的)。

    例子1:

    代码
    
    public class Animal
        {
            public virtual void Eat()
            {
                Console.WriteLine("Animal eat");
            }
        }
    
        public class Cat : Animal
        {
            public override void Eat()
            {
                Console.WriteLine("Cat eat");
            }
        }
    
        public class Dog : Animal
        {
            public override void Eat()
            {
                Console.WriteLine("Dog eat");
            }
        }
    
        class Tester
        {
            static void Main(string[] args)
            {
                Animal[] animals = new Animal[3];
    
                animals[0] = new Animal();
                animals[1] = new Cat();
                animals[2] = new Dog();
    
                for (int i = 0; i < 3; i++)
                {
                    animals[i].Eat();
                }
            }
        }

    输出结果:

    Animal eat...

    Cat eat...

    Dog eat...

    在上面的例子中,通过继承,使得Animal对象数组中的不同的对象,在调用Eat()方法时,表现出了不同的行为。

    多态的实现看起来很简单,要完全理解及灵活的运用c#的多态机制,也不是一件容易的事

    例子2:override实现多态

    多层继承中又是怎样实现多态的。比如类A是基类,有一个虚拟方法method()(virtual修饰),类B继承自类A,并对method()进行重写(override修饰),现在类C又继承自类B,是不是可以继续对method()进行重写,并实现多态呢?看下面的例子。

     1 代码
     2 
     3 public class Animal
     4     {
     5         public virtual void Eat()
     6         {
     7             Console.WriteLine("Animal eat");
     8         }
     9     }
    10 
    11     public class Dog : Animal
    12     {
    13         public override void Eat()
    14         {
    15             Console.WriteLine("Dog eat");
    16         }
    17     }
    18 
    19     public class WolfDog : Dog
    20     {
    21         public override void Eat()
    22         {
    23             Console.WriteLine("WolfDog eat");
    24         }
    25     }
    26 
    27     class Tester
    28     {
    29         static void Main(string[] args)
    30         {
    31             Animal[] animals = new Animal[3];
    32 
    33             animals[0] = new Animal();
    34             animals[1] = new Dog();
    35             animals[2] = new WolfDog();
    36 
    37             for (int i = 0; i < 3; i++)
    38             {
    39                 animals[i].Eat();
    40             }
    41         }
    42 }

    运行结果为:

    Animal eat...

    Dog eat...

    WolfDog eat... 

    在上面的例子中类Dog继承自类Animal,对方法Eat()进行了重写,类WolfDog又继承自Dog,再一次对Eat()方法进行了重写,并很好地实现了多态。不管继承了多少层,都可以在子类中对父类中已经重写的方法继续进行重写,即如果父类方法用override修饰,如果子类继承了该方法,也可以用override修饰,多层继承中的多态就是这样实现的。要想终止这种重写,只需重写方法时用sealed关键字进行修饰即可。

    例子3:abstract-override实现多态

    用abstract修饰的抽象方法。抽象方法只是对方法进行了定义,而没有实现,如果一个类包含了抽象方法,那么该类也必须用abstract声明为抽象类,一个抽象类是不能被实例化的。对于类中的抽象方法,可以再其派生类中用override进行重写,如果不重写,其派生类也要被声明为抽象类。看下面的例子。

     1 代码
     2 
     3     public abstract class Animal
     4     {
     5       public abstract void Eat();
     6     }
     7 
     8     public class Cat : Animal
     9     {
    10         public override void Eat()
    11         {
    12             Console.WriteLine("Cat eat");
    13         }
    14     }
    15 
    16     public class Dog : Animal
    17     {
    18         public override void Eat()
    19         {
    20             Console.WriteLine("Dog eat");
    21         }
    22     }
    23 
    24     public class WolfDog : Dog
    25     {
    26         public override void Eat()
    27         {
    28             Console.WriteLine("Wolfdog eat");
    29         }
    30     }
    31 
    32     class Tester
    33     {
    34         static void Main(string[] args)
    35         {
    36             Animal[] animals = new Animal[3];
    37 
    38             animals[0] = new Cat();
    39             animals[1] = new Dog();
    40             animals[2] = new WolfDog();
    41 
    42             for (int i = 0; i < animals.Length; i++)
    43             {
    44                 animals[i].Eat();
    45             }
    46         }
    47     }

    运行结果为:

    Cat eat...

    Dog eat...

    Wolfdog eat...

    从上面可以看出,通过使用abstract-override可以和virtual-override一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。


     

    静态和非静态

    静态类和非静态类

    静态类与非静态类的重要区别在于静态类不能实例化,也就是说,不能使用 new 关键字创建静态类类型的变量。在声明一个类时使用static关键字,具有两个方面的意义:首先,它防止程序员写代码来实例化该静态类;其次,它防止在类的内部声明任何实例字段或方法。

    静态类是自C# 2.0才引入的,C# 1.0不支持静态类声明。程序员必须声明一个私有构造器。私有构造器禁止开发者在类的范围之外实例化类的实例。使用私有构造器的效果与使用静态类的效果非常相似。

    两者的区别:
    私有构造器方式仍然可以从类的内部对类进行实例化,而静态类禁止从任何地方实例化类,其中包括从类自身内部。静态类和使用私有构造器的另一个区别在于,在 使用私有构造器的类中,是允许有实例成员的,而C# 2.0和更高版本的编译器不允许静态类有任何实例成员。使用静态类的优点在于,编译器能够执行检查以确保不致偶然地添加实例成员,编译器将保证不会创建此 类的实例。静态类的另一个特征在于,C#编译器会自动把它标记为sealed。这个关键字将类指定为不可扩展;换言之,不能从它派生出其他类。

    静态类的主要特性:
    1:仅包含静态成员。
    2:无法实例化。
    3:是密封的。
    4:不能包含实例构造函数。

    静态成员

    1:非静态类可以包含静态的方法、字段、属性或事件;
    2:无论对一个类创建多少个实例,它的静态成员都只有一个副本;
    3:静态方法和属性不能访问其包含类型中的非静态字段和事件,并且不能访问任何对象的实例变量;
    4:静态方法只能被重载,而不能被重写,因为静态方法不属于类的实例成员;
    5:虽然字段不能声明为 static const,但 const 字段的行为在本质上是静态的。这样的字段属于类,不属于类的实例。因此,可以同对待静态字段一样使用 ClassName.MemberName 表示法来访问 const 字段;

    6:C# 不支持静态局部变量(在方法内部定义静态变量)。

    静态构造函数

    1:静态类可以有静态构造函数,静态构造函数不可继承;
    2:静态构造函数可以用于静态类,也可用于非静态类;
    3:静态构造函数无访问修饰符、无参数,只有一个 static 标志;
    4:静态构造函数不可被直接调用,当创建类实例或引用任何静态成员之前,静态构造函数被自动执行,并且只执行一次。

    注意:
    1:静态类在内存中是一直有位置的;
    2:非静态类在实例化后是在内存中是独立的,它的变量不会重复,在使用后会及时销毁,所以不会出现未知的错误。在C#中静态成员是比较敏感的东西,在不是十分确认的情况下不要使用;
    3:建议更多地使用一般类(非静态类)。

    使用选择:
    当定义的类不需要进行实例化时,我们使用静态类;如果需要实例化对象,需要继承等特性时,应该使用非静态类,并且将统一使用的变量和方法设为静态的,那么所有实例对象都能访问。

  • 相关阅读:
    高级人力资源管理最喜欢的工具;笔迹分析测试的六大好处
    我与时尚MM的那些事儿
    当幸福来敲门
    perl 模板
    一些R函数【自己使用过,保存】
    关于异步加载、缓存图片、软引用等
    android线程同步
    现半透明的popupwindow
    android中的MotionEvent 及其它事件处理
    android客户端从服务器端获取json数据并解析
  • 原文地址:https://www.cnblogs.com/JiYF/p/6122475.html
Copyright © 2020-2023  润新知