MonoBehavior子类返回null仍然可以使用

这篇文章其实是 记MonoBehavior与单例模式碰撞的火花的后续篇。可以读一下,可以更好的理解本文。

众所周知,继承MonoBehavior的子类是不能使用new来实例化的。但是如果我们强行new一下呢?

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using System;

public class henfan : MonoBehaviour {
    void Start () {
        MonoChild mono = new MonoChild();
        if (mono == null)
        {
            Debug.Log("mono == null");
        }

        mono.words = "hahaha";
        mono.Foo();
    }

}

class MonoChild : MonoBehaviour
{
    public string words = "hello Mono";
    public int count;
    public void Foo()
    {
        Debug.Log(words);
    }
}

输出:
mono

首先是warning警告我们不能用new实例化继承了MonoBehaviour的子类。然后mono==null确实成立。但是,如果设置mono.words以及调用mono.Foo()都没有问题。

嘴上说没有,实际上已经实例化、分配内存了??

在判断mono==null后添加以下代码:

unsafe
{
    fixed (int* p = &mono.count)
    {
        Debug.Log("mono count address: " + (int)p);
    }
}

确确实实在为mono分配了内存~

结论:

强行用new实例化MonoBehavior子类:

MonoChild mono = new MonoChild();

1. mono==null 为true

2. 进行了内存分配,可以“不合法”地正常使用mono

后续

学习了一下反汇编及IL代码的阅读,用ILSpy反汇编后:

.method private hidebysig 
    instance void Start () cil managed 
{
    // Method begins at RVA 0x213c
    // Code size 32 (0x20)
    .maxstack 2
    .locals init (
        [0] class MonoChild
    )

    IL_0000: nop
    IL_0001: newobj instance void MonoChild::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldnull
    IL_0009: call bool [UnityEngine.CoreModule]UnityEngine.Object::op_Equality(class [UnityEngine.CoreModule]UnityEngine.Object, class [UnityEngine.CoreModule]UnityEngine.Object)
    IL_000e: brfalse IL_001f

    IL_0013: nop
    IL_0014: ldstr "mono == null"
    IL_0019: call void [UnityEngine.CoreModule]UnityEngine.Debug::Log(object)
    IL_001e: nop

    IL_001f: ret
} // end of method henfan::Start

可以看到IL_0001确实进行了实例化,再次证实了我们的之前的结论。

ps:
反汇编是指从机器语言到汇编语言
反编译是指从机器语言到高级语言

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Java 中,如果一个父类中的方法返回类型是某个类或接口类型,那么子类可以重写该方法并返回子类类型的对象。因此,如果父类中定义了一个 getArea 方法返回某种形状的面积,而子类继承了该方法并计算了自己形状的面积,那么子类可以重写该方法并返回自己的面积。 以下是一个示例代码: ```java class Shape { public double getArea() { return 0.0; } } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double getArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private double width; private double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public double getArea() { return width * height; } } class Main { public static void main(String[] args) { Shape shape1 = new Circle(2.0); Shape shape2 = new Rectangle(3.0, 4.0); System.out.println(shape1.getArea()); // 输出 12.566370614359172 System.out.println(shape2.getArea()); // 输出 12.0 } } ``` 在上面的示例代码中,定义了一个 Shape 父类和两个子类 Circle 和 Rectangle。Shape 类中定义了一个 getArea 方法,返回 0.0,表示默认情况下形状的面积为 0。Circle 类和 Rectangle 类都继承了 Shape 类,并重写了 getArea 方法,分别计算了自己的面积。在主函数中,创建了一个 Circle 对象和一个 Rectangle 对象,并将其分别赋给 Shape 类型的变量 shape1 和 shape2。然后调用了 shape1 和 shape2 的 getArea 方法,由于 shape1 和 shape2 分别是 Circle 和 Rectangle 类型的对象,因此调用的是各自的 getArea 方法,分别输出 12.566370614359172 和 12.0,表示圆的面积和矩形的面积。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值