可空类型为什么可以为空?也许会被面试到哦。。。

简介:
  也许某天你来某一家公司面试,或许就会被问到这个问题,当你看到这个问题,也许会立即反编译下源代码看个究竟。
[Serializable, StructLayout(LayoutKind.Sequential), __DynamicallyInvokable]
public struct Nullable<T> where T: struct
{
    private bool hasValue;
    internal T value;
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
    public Nullable(T value)
    {
        this.value = value;
        this.hasValue = true;
    }

    [__DynamicallyInvokable]
    public bool HasValue
    {
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        get
        {
            return this.hasValue;
        }
    }
    [__DynamicallyInvokable]
    public T Value
    {
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
        get
        {
            if (!this.HasValue)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);
            }
            return this.value;
        }
    }
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
    public T GetValueOrDefault()
    {
        return this.value;
    }

    [__DynamicallyInvokable]
    public T GetValueOrDefault(T defaultValue)
    {
        if (!this.HasValue)
        {
            return defaultValue;
        }
        return this.value;
    }

    [__DynamicallyInvokable]
    public override bool Equals(object other)
    {
        if (!this.HasValue)
        {
            return (other == null);
        }
        if (other == null)
        {
            return false;
        }
        return this.value.Equals(other);
    }

    [__DynamicallyInvokable]
    public override int GetHashCode()
    {
        if (!this.HasValue)
        {
            return 0;
        }
        return this.value.GetHashCode();
    }

    [__DynamicallyInvokable]
    public override string ToString()
    {
        if (!this.HasValue)
        {
            return "";
        }
        return this.value.ToString();
    }

    [__DynamicallyInvokable]
    public static implicit operator T?(T value)
    {
        return new T?(value);
    }

    [__DynamicallyInvokable]
    public static explicit operator T(T? value)
    {
        return value.Value;
    }
}

 
Collapse Methods

当你reflector之后,你可能会快速的认为这个就是答案,但是你真的把这个代码拷贝到编辑器中,你会发现如下的错误。

 

从图中可以看到,原来事情没有这么简单,最后还是回到了原来的问题上,null不能给值类型赋值,这个时候,你可能就比较好奇。

我们的FCL中定义的类怎么就能逃过编译器呢?

 

①:我们用ILdasm看下il代码。

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = null;
        }
    }

 

②:下面我们再将Nullable<Int32> i = null 改成 Nullable<Int32> i = 0,看看il代码是怎么样的。

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = 0;
        }
    }

 

下面我们比较比较这两张图不一样的地方。

《1》 当 Nullable<Int32> i = 0 的时候,发现Nullable被实例化了(instance),并且还调用了其构造函数(ctor(!0)),

这种情况我们看Nullable的结构体定义,发现是非常合乎情理的。

 

《2》当 Nullable<Int32> i = null 的时候,从IL代码上看,只是调用了initobj指令,并没有实例化,也没有调用构造函数,

再看看这个指令的意思:将位于指定地址的对象的所有字段初始化为空引用或适当的基元类型的 0。

①:既然是”初始化“操作,那我应该也可以写成这样:

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = new Nullable<Int32>();
        }
    }

 

②:既然是“初始化”,那么作为null的Nullable应该可以调用实例方法并不报错,这就如指令说的一样,如果成功,那就

说明null只是Nullable的一种状态,不能跟“类”中的空引用混淆。

     从上面的三张图上可以看出,也许答案就在这个里面,编译器和CLR作为“特等公民”在底层做了很多我们看不到的东西,

这其中就像上图一样给我们多加了一种”可空状态“,只是如何做的,我们看不到而已。

 

《3》既然说到null,我也很好奇的看看到底“类”下面的null是什么情况。

class Program
    {
        static void Main(string[] args)
        {
            Program p = null;
        }
    }

 

ldnull的意思是:将空引用推送到计算堆栈上。

可以看到,既然没有new,也就不会在堆中分配内存,而这里是将null放入到线程栈中,不知道编译器在initobj中

是否也有类似的操作。。。

 

最后要说的是:希望大家讨论讨论,毕竟我也是猜测而已,并没有实实在在的看到那些给我们隐藏的东西。

相关文章
|
1月前
|
Java 程序员
java线程池讲解面试
java线程池讲解面试
62 1
|
2月前
|
存储 关系型数据库 MySQL
2024年Java秋招面试必看的 | MySQL调优面试题
随着系统用户量的不断增加,MySQL 索引的重要性不言而喻,对于后端工程师,只有在了解索引及其优化的规则,并应用于实际工作中后,才能不断的提升系统性能,开发出高性能、高并发和高可用的系统。 今天小编首先会跟大家分享一下MySQL 索引中的各种概念,然后介绍优化索引的若干条规则,最后利用这些规则,针对面试中常考的知识点,做详细的实例分析。
253 0
2024年Java秋招面试必看的 | MySQL调优面试题
|
2月前
|
存储 算法 Java
铁子,你还记得这些吗----Java基础【拓展面试常问题型】
铁子,你还记得这些吗----Java基础【拓展面试常问题型】
47 1
|
2月前
|
NoSQL Java 关系型数据库
凭借Java开发进阶面试秘籍(核心版)逆流而上
最近参加了面试或者身边有朋友在面试的兄弟有没有发现,现在的面试不仅会问八股文,还会考察框架、项目实战、算法数据结构等等,需要准备的越来越多。 其实面试的时候,并不是要求你所有的知识点都会,而是关键的问题答到点子上!这份《Java 开发进阶面试秘籍(核心版)》由 P8 面试官整体把控,目前已经更新了 30 万字! 资料中涵盖了一线大厂、中小厂面试真题,毕竟真题都是技术领域最经典的基础知识和经验沉淀的汇总,非常有必要学习掌握!双重 buff 叠加,offer 接到手软~ 点击此处取,这可能是你到目前为止领取的最具含金量的一份资料! 整套资料涵盖:Spring、Spring
|
2月前
|
存储 缓存 Java
面试官:什么是Java内存模型?
面试官:什么是Java内存模型?
113 0
面试官:什么是Java内存模型?