.Net 基础new关键字的用法

一、new的基本功能

一般说来,new关键字在.net中用于以下四个场合。

  1. 作为运算符,用于创建对象和调用构造函数,范围用得最多吧。
  2. 实现多态。
  3. 作为修饰符,用于向基类成员隐藏继承类成员,一般继承情况下,扩展基类方法用得多。
  4. 作为泛型参数约束,用于在泛型声明中约束用作类型参数的参数类型,这个也好像用得多吧。

二、new的基本用法

  1. 先来说说作为泛型参数约束的用法。

MSDN 中的定义是:new约束指定泛型类声明中的任何类型参数都必须有公共的无参构造函数。当泛型类型创建类型的新实例时,将此约束应用于类型参数。

有个注意的地方就是有其他约束时,new约束比须最后指定。

下面实现一个例子:

1     class Person<T> where T : new()
2     {
3         public T GetName()
4         {
5             return new T();
6         }
7     }

9     class Boy
10     {
11         private string _name;
12 
13         public string Name
14         {
15             get{return _name;}
16             set { _name = value; }
17         }
18 
19         public Boy()
20         {
21             _name = "feng";
22         }
23     }
24 
25     class Program
26     {
27         static void Main(string[] args)
28         {
29             Person<Boy> MBoy = new Person<Boy>();
30 
31             Boy a = new Boy();
32             Console.WriteLine(a.Name);
33 
34             Console.WriteLine(MBoy.GetName().Name);
35             Console.ReadKey();
36         }
37     }

结果 打印出2个"feng"

2.  再来说说作为修饰符和多态的用法。

作为修饰符,主要用在向基类成员隐藏继承成员。如果要实现派生类隐藏方法,则基类的方法必须定义为virtual,将基类方法实现为virtual可以保证向前扩展和向后兼容。分别在派生类通过override或new进行灵活控制。new和overdide不可同时共存,因为new用于创建一个新成员,同时隐藏基类的同名成员,注意不是覆盖,要想访问基类的成员可以通过base修饰符来访问。而override则不行。

通过new实现多态。

  1. 比如通过基类扩展来实现继承式多态:

    Animal a =new dog();

    //其中cry()方法实现为虚方法,子类dog继承至Animal 并覆写了该方法,虽然a是父类Animal的一个变量,但是实现的是子类dog的方法,这正是new实现多态的体现吧。

a.cry();

2.也可以通过继承接口来实现多态:

IAnimalRun r=new dog();//dog实现了接口IAnimalRun 的 run()方法

r.run();

看下面一个例子来加深理解:

1     class Num
 2     {
 3         public static int i = 111;
 4 
 5         public virtual void ShowClassInfo()
 6         {
 7             Console.WriteLine("我是基类呵呵");
 8         }
 9         public virtual void ShowNum()
10         {
11             Console.WriteLine("基类的数字是{0}", i.ToString());
12         }
13     }
14 
15     class SubNum : Num
16     {
17         new public static int i = 222;
18 
19         //new 作为修饰符:只是隐藏基类同名方法
20         public new virtual void ShowClassInfo()
21         {
22             Console.WriteLine("我是子类哈哈");
23         }
24 
25         //override则是覆写了基类的方法
26         public override void ShowNum()
27         {
28             Console.WriteLine("子类的数字是{0}", i.ToString());
29         }
30     }
31 
32     class Program
33     {
34         static void Main(string[] args)
35         {
36             Num num1 = new Num();//new 运算符用法
37             num1.ShowNum();
38             SubNum sbnum = new SubNum();
39             //下面2个调用的都是子类的方法 但是实现机制不一样
40             sbnum.ShowNum();//结果:111
41 
42             sbnum.ShowClassInfo();//结果:我是子类
43             
44             //new作为多态的用法:下面是典型的基类继承似多态
45             Num num2 = new SubNum();//num2虽然是基类的变量,但是指向了之类SubNum实例的引用
46 
47             //调用方法时会在运行期检查虚拟方法表,来确定要调用的方法
48             num2.ShowClassInfo();//由于方法只是被隐藏了,没有被重写 所有还是调用的基类的方法
49 
50             num2.ShowNum();//方法被覆盖了 所有调用的是子类的方法
51             Console.ReadKey();
52         }
53     }

个人觉得new实现多态可以放到作为运算符里面不去,不知道你们是不是这样认为的。

3.作为运算符的用法。

作为修饰符和约束的情况也许要多加理解,作为运算符一定是一个不难理解的话题,因为大多数时候我们就是用new作为运算符来创建对象或结构体或枚举等等。new运算符用于返回一个引用,指向系统分配的托管堆的内存地址,那new实例化值类型和引用类型有啥区别呢,来看一段简单的代码。

class MyClass
 2     {
 3         private int _id;
 4         public MyClass(int id)
 5         {
 6             _id = id;
 7         }
 8     }
 9 
10     struct MyStruct
11     {
12         private string _name;
13         public MyStruct(string name)
14         {
15             _name = name;
16         }
17     }
18 
19     class Program
20     {
21         public static void Main()
22         {
23             int i=0;
24             int j = new int();
25             string str = new string(‘#‘, 10);
26 
27             MyClass myClass = new MyClass(123);
28 
29             MyStruct myStruct = new MyStruct("hehe");
30             
31             Console.WriteLine(j);
32             Console.ReadKey();
33         }
34     }

我们来用reflector工具来查看它的IL代码如下:

.method public hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 3
    .locals init (
        [0] int32 num,//这里我创建的明明是i反编译确是num 不理解,求大家指出
        [1] int32 j,//这里我自己修改成了j
        [2] string str,
        [3] class TestNewFunction.MyClass myClass,
        [4] valuetype TestNewFunction.MyStruct myStruct)
    L_0000: nop

//手动初始化i为0

L_0001: ldc.i4.0 
    L_0002: stloc.0

//通过new来初始化j为0

L_0003: ldc.i4.0 //j的值为0
    L_0004: stloc.1

//调用newobj初始化字符串str

L_0005: ldc.i4.s 0x23//‘#‘的16进制
    L_0007: ldc.i4.s 10//这个10应该是count
    L_0009: newobj instance void [mscorlib]System.String::.ctor(char, int32)

L_000e: stloc.2

//调用newobj创建对象,并调用构造函数初始化 ,内存分配在托管堆上

L_000f: ldc.i4.s 0x7b//111的十六进制
    L_0011: newobj instance void TestNewFunction.MyClass::.ctor(int32)
    L_0016: stloc.3

//加载结构体

L_0017: ldloca.s struct2
    L_0019: ldstr "hehe"

//调用构造函数初始化,内存分配在线程的栈上面

L_001e: call instance void TestNewFunction.MyStruct::.ctor(string)
    L_0023: nop 
    L_0024: ldloc.1 
    L_0025: call void [mscorlib]System.Console::WriteLine(int32)
    L_002a: nop 
    L_002b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    L_0030: pop 
    L_0031: ret 
}

本人对IL知道的不是很多,有错误希望大家能够提出来。通过以上分析,可以得出一点结论:

  1. new一个class时,先调用newobj命令 来为实例在托管堆中分配内存,然后调用构造函数来进行对象初始化。
  2. new 一个struct 时,直接调用其构造函数完成初始化。
  3. new 一个int时,用于初始化其值为0。

差点忘了 new运算符不可重载,分配内存失败时,会引发OutOfMemoryException异常。

以上是本人对new这个关键字的用法。如有错误欢迎指出。

原文出处:章出处:http://www.cnblogs.com/xingbinggong/archive/2011/07/05/2098454.html

时间: 2024-12-29 00:53:06

.Net 基础new关键字的用法的相关文章

Java基础-synchronized关键字的用法(转载)

原文地址:http://blog.csdn.net/cq361106306/article/details/38736551 synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰?this或者非静态方法或者是一个实例的时候,所同步的锁是加在this或者实例对象引用上面的.比如a,b同为Main类的实例化对象,a调用被同步的方法,和b调用被同步的方法,没有形成互斥.但是不同线程的a对象调用被同步的方法就被互斥了.

Java基础-synchronized关键字的用法

顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 1. 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在this或者实例对象引用上面的.比如a,b同为Main类的实例化对象,a调用被同步的方法,和b调用被同步的方法,没有形成互斥.但是不同线程的a对象调用被同步的方法就被互斥了. public synchronized void method(){   //-.   }   public void method()   {   s

JAVA 基础--final 关键字的用法

在java中,final的含义在不同的场景下有细微的差别,in a word,它指的是“不可变的” 1.修饰数据.这里的可以看到被final修饰的变量,值不能被改变,但是 package FinalTest; public class FinalPerson { public String _name; public final int _age; public FinalPerson(String name, int age) { this._name = name; this._age =

转 C/C++基础知识:typedef用法小结

第一.四个用途 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, // 和一个字符变量: 以下则可行: typedef char* PCHAR; // 一般用大写 PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针 虽然: char *pa, *pb; 也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typed

Python实用技巧:global关键字的用法详解

这篇文章主要介绍了python global关键字的用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下: 想要更好的了解global关键字,首先要熟悉python的全局变量与局部变量的概念.global关键字的作用是可以申明一个局部变量为全局变量,下面看一下实例 一.变量作用域的说明 1.局部变量 1 def a(): 2 ## 菊部变量 - ,- 3 local = 1 4 print(local) 5 ## 全局无法使用,只有自己可用

super关键字的用法

package com.frank;//定义包名,必须是第一行.如果没有包名,那么就会被放在一个没有名字的默认包中. import java.util.*; /** 继承 */ public class Sample {     public static void main(String[] args)     {         OldMan o = new OldMan("张三",80);         System.out.println("名字:"+o.

yield关键字的用法

在上一篇文章中,说了下foreach的用法,但是还是比较复杂的,要实现接口才能进行遍历,有没有简单些的方法呢?答案是肯定的.且看下面. yield关键字的用法: 1.为当前类型添加一个任意方法,但是要求该方法的返回值类型必须是IEnumerable:<代码1-1> 1 class Person 2 { 3 public string Name { get; set; } 4 public int Age { get; set; } 5 6 public string[] _Name = new

c#多线程中Lock()关键字的用法小结

本篇文章主要是对c#多线程中Lock()关键字的用法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助 本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待. 每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数.这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生.

mysql 去除重复 Select中DISTINCT关键字的用法

在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供 有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值.其原因是 distinct只能返回它的目标字段,而无法返回其它字段,这个问题让我困扰了很久,用distinct不能解决的话,我只有用二重循环查询来解决,而 这样对于一个数据量非常大的站来说,无疑是会直接影响到效率的.所以我花了很多时间来研究这个问题,网上也查不到解决方案,期间把容容拉来帮忙,