Object基类

知识点

  1. 值类型。

    1. 值类型是在栈中分配内存,在声明时初始化才能使用,不能为null。
    2. 值类型超出作用范围系统自动释放内存。
    3. 主要由两类组成:结构,枚举(enum),结构分为以下几类:
      1. 整型(Sbyte、Byte、Char、Short、Ushort、Int、Uint、Long、Ulong)
      2. 浮点型(Float、Double)
      3. decimal
      4. bool
      5. 用户定义的结构(struct)
  2. 引用类型。
    1. 引用类型在堆中分配内存,初始化时默认为null。
    2. 引用类型是通过垃圾回收机制进行回收。
    3. 包括类、接口、委托、数组以及内置引用类型object与string。

概念

由于C#中所有的数据类型都是由基类System.Object继承而来的,所以值类型和引用类型的值可以通过显式(或隐式)操作相互转换,而这转换过程也就是装箱(boxing)和拆箱(unboxing)过程。

  1. 装箱 是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。

  2. 拆箱 (取消装箱)是从 object 类型到值类型或从接口类型到实现该接口的值类型的 显式 转换。取消装箱操作包括:
    1. 检查对象实例,确保它是给定值类型的一个装箱值。(拆箱后没有转成原类型,编译时不会出错,但运行会出错,所以一定要确保这一点。用GetType().ToString()判断时一定要使用类型全称,如:System.String 而不要用String。)
    2. 将该值从实例复制到值类型变量中。

示例

首先写个简单的控制台程序:

// Tutorial_boxing_unboxing.cs
// 装箱与拆箱
using System;

class App
{
    static void Main()
    {
        int i = 32;
        object o = i; //隐式装箱

Console.WriteLine("o = {0}", o);

Console.Read();
    }
}

其中object o = i这里我们进行了装箱操作,然后我们用MSIL 反汇编程序查看下生成的.exe程序的内部机理。

1 .method private hidebysig static void  Main() cil managed
 2 {
 3   .entrypoint
 4   // 代码大小       30 (0x1e)
 5   .maxstack  2
 6   .locals init ([0] int32 i,
 7            [1] object o)
 8   IL_0000:  nop
 9   IL_0001:  ldc.i4.s   32
10   IL_0003:  stloc.0
11   IL_0004:  ldloc.0
12   IL_0005:  box        [mscorlib]System.Int32
13   IL_000a:  stloc.1
14   IL_000b:  ldstr      "o = {0}"
15   IL_0010:  ldloc.1
16   IL_0011:  call       void [mscorlib]System.Console::WriteLine(string,
17                                                                 object)
18   IL_0016:  nop
19   IL_0017:  call       int32 [mscorlib]System.Console::Read()
20   IL_001c:  pop
21   IL_001d:  ret
22 } // end of method App::Main

其中第12行是我们的装箱操作。(关于IL中出现的操作符代表的操作请查阅MSDN Library中的.NET开发/.NET Framework SDK/类库参考/System.Reflection.Emit/OpCodes 类/OpCodes 字段)

然后我们取消装箱操作:

static void Main()
    {
        int i = 32;

Console.WriteLine("i = {0}", i);

Console.Read();
    }

再用MSIL工具查看生成的.exe,如下结果:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // 代码大小       28 (0x1c)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   32
  IL_0003:  stloc.0
  IL_0004:  ldstr      "i = {0}"
  IL_0009:  ldloc.0
  IL_000a:  box        [mscorlib]System.Int32
  IL_000f:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_0014:  nop
  IL_0015:  call       int32 [mscorlib]System.Console::Read()
  IL_001a:  pop
  IL_001b:  ret
} // end of method App::Main

在IL_000a行,我们发现这里却也出现了一个box!不过这步是在call System.Console::WriteLine(string, object)时发生的。我们对比前面我们手动boxing的IL代码,发现在我们手动boxing后就没有这步box了。为什么呢?

当我们在调用一些方法的重载版本时,由于编译器找不到符合给定参数类型的重载方法,此时编译器便去寻找到的最接近的版本,然后使用找到的方法,而其参数却是我们传入的值类型的基类如System.Object或者其实现的接口类型,接着编译器为了求得与这个方法的原型一致,就必须对该值类型进行装箱操作(转换成引用类型)。

照这个说法当我们不手动boxing时,在调用了Console.WriteLine()方法输出一个Int32类型值时,系统就要自动进行boxing。也就是说如果我们要对该输出操作作5000次的循环,系统就要做5000次的boxing。这样对性能便会有一定的影响,而且要使循环次数是100,000,000次呢,或者跟多!

此时我们便要想如何消除这不应该的性能损失!正如第一个程序是展示的,我们可以在需要的地方先进行boxing,这个原理很简单,我们可以联想到类似的做法:

//当我们如下时:
for (int i = 0; i < arr.Length; i++)
{
   // 
}

//我们更因该这样:
int L = arr.Length;
for (int i = 0; i < L; i++)
{
   // 
}

这样,我们只要一次boxing,就可以避免让系统重复的做这个操作。

用途

像在调用Console.WriteLine()的过程中系统自动进行boxing一样,当我们在调用其它的一些方法的重载版本进行操所时,为了避免由于无谓的隐式装箱所造成的性能损失,在执行这些多类型重载方法之前,最好先对值进行装箱。一般是在处理大量数据需要对类型进行装箱操作。

原文地址:http://blog.csdn.net/gsky/article/details/2222423

时间: 2024-10-17 20:55:31

Object基类的相关文章

System.Object 基类

System.Object 基类 System.Object在.Net中是所有类型的基类,任何类型都直接或间接地继承自System.Object.没有指定基类的类型都默认继承于System.Object. 基类特性 正由于所有的类型都继承于System.Object.因此,所有的类型都具有下面这些特性: GetType()方法,获取对象的类型. Equals.ReferenceEquals和==,判断对象是否相等. ToString()方法,获取对象的字符串信息,默认返回对象带命名空间的全名.

浅析Object基类提供的Virtual Object.Equals, Static Object.Equals and Reference.Equals等三个方法

当我们去查看object.cs源代码文件的时候,会发现object基类提供了三种判断相等性的方法.弄清楚每种方法存在的原因,也就是具体解决了什么问题,对我们理解.net判断对象相等性的逻辑很有帮助,下面让我们分别来看看吧! 1.Virtual Object.Equals()方法 实际上.net中提供了几种比较相等性(equality)的方法,但是最基础的方法就数object类中定义的virtual Object.Equals()了.下面让我们以一个customer类来看看该方法的实际运作. st

.NET Framework中Object基类有哪些方法?

ToString(),虚方法,任何子类可重写自定义 GetType(),非虚,返回类型名 Equals(),虚方法,默认情况下判定两个引用是否指向同一实例.(ReferenceEquals()功能相同,静态方法Equals()面对值类型判定值是否相等,面对引用类型,判定是否指向同一实例.) GetHashCode() 返回对象的哈希值.在重写equals方法时需要重写GetHashCode以保持统一.可以通过new Random().GetHashCode()得到真随机数. Memberwise

关于python中的 object基类

参考:[1] stackoverflow: what is the difference between old style and new style classes in Python? [2] The Inside Story on New-style Classes

Java Object根类

Object类是Java中其他所有类的祖先,没有Object类Java面向对象无从谈起.作为其他所有类的基类,Object具有哪些属性和行为,是Java语言设计背后的思维体现. Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入.Object类没有定义属性,一共有13个方法,具体的类定义结构如下图: 1.类构造器public Object(); 大部分情况下,Java中通过形如 new A(args..)形式创建一个属于该类型的对象.

python(七):元类与抽象基类

一.实例创建 在创建实例时,调用__new__方法和__init__方法,这两个方法在没有定义时,是自动调用了object来实现的.python3默认创建的类是继承了object. class A(object): def __init__(self, *args, **kwargs): self.name, self.age, self.gender = args[:3] def __new__(cls, *args, **kwargs): print("__new__ has called.

Java记录 -22- Java的基类Object详解

Java的基类Object详解 Java的JDK文档要经常查阅使用,最好查看英文的文档. java.lang.Object 类,java.lang包在使用的时候无需显示导入,编译时由编译器自动帮助我们导入. API(Application Programinga Interface),应用编程接口. Object obj = new Object(); System.out.println(obj); System.out.println(obj.toString()); 上面打印的两个内容一样

.NET基础 (11)类型的基类System.Object

类型的基类System.Object1 是否存在不继承自System.Object类型的类2 在System.Object中定义的三个比较方法有何异同3 如何重写GetHashCode方法 类型的基类System.Object1 是否存在不继承自System.Object类型的类 通过运行ILasm.exe的noautoinherit开关,可以生产不从System.Object继承的类型,这种类型是不安全的类型,也不建议使用. 2 在System.Object中定义的三个比较方法有何异同 静态方

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

在上一篇随笔中,我对Web开发框架的总体界面进行了介绍,其中并提到了我的<Web开发框架>的控制器的设计关系,Web开发框架沿用了我的<Winform开发框架>的很多架构设计思路和特点,对Controller进行了封装.使得控制器能够获得很好的继承关系,并能以更少的代码,更高效的开发效率,实现Web项目的开发工作,整个控制器的设计思路如下所示. 从上图的设计里面可以看到,我把主要能通过抽象封装的CRUD方法都放到了BusinessController<B, T>类里面,