MIL2——模拟面试题

问题

C#

  1. 请说说你认为 C# 中 ==​ 和 Equals​ 的区别是什么?

  2. 浅拷贝和深拷贝的区别? 可以举例说明

  3. 下面两种获取10000个数的方式,哪种效率更高?为什么

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    List<int> list = new List<int>();
    for (int i = 0; i < 10000; i++)
    {
    list.Add(i);
    }
    float[] array = new float[10000];
    for (int i = 0; i < 10000; i++)
    {
    array[i] = i;
    }
  4. 现在有如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static void Main(string[] args)
    {
    int i = GetInt();
    Console.WriteLine($"第A处 i = {i}");
    }

    static int GetInt()
    {
    int i = 10;
    try
    {
    return i;
    }
    finally
    {
    i = 11;
    Console.WriteLine($"第B处 i = {i}");
    }
    }
    1. A处和B处谁先打印?
    2. A、B出打印的i值分别是多少?
  5. 请问如下代码中,A、B两处 i 的值为多少?

    1
    2
    3
    4
    class Test
    {
    public int i = 10;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    static void Main(string[] args)
    {
    Test t = GetObj();
    Console.WriteLine($"第A处 i = {t.i}");
    }

    static Test GetObj()
    {
    Test t = new Test();
    try
    {
    return t;
    }
    finally
    {
    t.i = 11;
    Console.WriteLine($"第B处 i = {t.i}");
    }
    }

Unity

  1. Unity中当一个细小高速物体撞击另一个较大物体时 会出现什么情况?如何避免?
  2. 请简述一下Prefab(预制体)的本质是什么?
  3. Unity是否支持写成多线程程序? 如果支持的话需要注意什么?
  4. 请简述一下对象池,在游戏开发中我们什么时候会用到它?
  5. 什么是DrawCall? DrawCall为什么会影响游戏运行效率? 如何减少DrawCall?

答案

C#

  1. 请说说你认为 C# 中 ==​ 和 Equals​ 的区别是什么?

    答案:

    1. ==​ 是运算符,Equals​ 是万物之父 Object​ 中的虚方法,子类可重写
    2. Equals​ 一般在子类中重写后用于比较两个对象中内容是否相同
    3. ==​ 在没有运算符重载的前提下时,引用类型用于比较地址;值类型用于比较值是否相同
    4. 运算效率不同,一般 Equals​ 没有 ==​ 效率高,因为一般 Equals​ 比较的内容比 ==​ 多
  2. 浅拷贝和深拷贝的区别? 可以举例说明

    答案:

    • 浅拷贝: 只复制对象的引用地址 两个对象指向同一内存地址,修改其中一个另一个也会随之变化
    • 深拷贝: 将对象和值赋值过来,两个对象修改其中任意值都不会影响对方

    举例:

    比如 引用对象A 和 引用对象B
    让 A = B,就是浅拷贝,此时A、B的引用地址相同,改A中内容,B也变
    如果想要深拷贝,简单处理就是 new​(包括对象中的成员)

  3. 下面两种获取10000个数的方式,哪种效率更高?为什么

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    List<int> list = new List<int>();
    for (int i = 0; i < 10000; i++)
    {
    list.Add(i);
    }
    float[] array = new float[10000];
    for (int i = 0; i < 10000; i++)
    {
    array[i] = i;
    }

    答案:

    方式2的效率更高,因为 List​ 本质是数组,我们通过 Add​ 往 List​ 中添加元素时,会不断的触发扩容,扩容会带来内存和性能上的消耗

    • 内存方面:每次扩容会产生垃圾,还会造成GC的触发
    • 性能方面:每次扩容会进行“搬家”(老数组中内容存入新数组中)
  4. 现在有如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static void Main(string[] args)
    {
    int i = GetInt();
    Console.WriteLine($"第A处 i = {i}");
    }

    static int GetInt()
    {
    int i = 10;
    try
    {
    return i;
    }
    finally
    {
    i = 11;
    Console.WriteLine($"第B处 i = {i}");
    }
    }
    1. A处和B处谁先打印?
    2. A、B出打印的i值分别是多少?

    答案:

    1. B处先打印,A处后打印
    2. A处 i = 10​,B处 i = 11

    考点:finally的执行顺序(finally内的代码无论如何都会执行,哪怕是 return​ 或者 throw​ ),值类型和引用类型的区别

  5. 请问如下代码中,A、B两处 i 的值为多少?

    1
    2
    3
    4
    class Test
    {
    public int i = 10;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static void Main(string[] args)
    {
    Test t = GetObj();
    Console.WriteLine($"第A处 i = {t.i}");
    }

    static Test GetObj()
    {
    Test t = new Test();
    try
    {
    return t;
    }
    finally
    {
    t.i = 11;
    Console.WriteLine($"第B处 i = {t.i}");
    }
    }

    答案: A、B两处都为11

    考点: finally的执行顺序(finally内的代码无论如何都会执行,哪怕是 return​ 或者 throw​ ),值类型和引用类型的区别

Unity

  1. Unity中当一个细小高速物体撞击另一个较大物体时 会出现什么情况?如何避免?

    答案:

    有可能会直接穿过物体,而不触发碰撞检测

    1. 我们可以尽量用射线检测来替代细小物体的物理系统碰撞
      因为传统的FPS游戏都是通过射线检测加模拟计算来判断伤害的
    2. 修改 Rigidbody​ 刚体中的 Interpolate​(插值)和 CollisionDetection​(碰撞检测)两个参数,来提高碰撞检测的准确性
  2. 请简述一下Prefab(预制体)的本质是什么?

    答案:
    Prefab的本质就是一个YAML配置文件
    其中记录了一个GameObject对象上挂载的脚本信息
    并且记录了脚本信息中的可配置的属性信息

  3. Unity是否支持写成多线程程序? 如果支持的话需要注意什么?

    答案:支持
    注意:

    1. 只能从主线程访问Unity相关组件、对象以及 UnityEngine​ 命名空间中的绝大部分内容
    2. 如果多线程中要和Unity主线程同时修改一些数据
      可以通过 lock​ 关键词加锁
  4. 请简述一下对象池,在游戏开发中我们什么时候会用到它?

    答案:

    1. 对象池的主要作用是 避免大量创建对象再释放对象时造成的内存消耗,可以有效降低GC发生的频率。
      我们把不用的对象放入对象池中而不是让它直接变为垃圾,下次需要用到对象时再从对象池中获取,
      我们通过占用内存来避免更多的内存消耗和GC的发生
    2. 在游戏中频繁创建对象、实例化对象的地方,都可以用到对象池。
      比如前端开发中,游戏中的子弹、伤害字体、特效等等
      比如后端开发中线程池等等
  5. 什么是DrawCall? DrawCall为什么会影响游戏运行效率? 如何减少DrawCall?

    答案:

    1. 什么是DrawCall?

      每次CPU准备渲染相关数据并通知GPU的过程称为一次DrawCall

    2. DrawCall为什么会影响游戏运行效率?

      如果DrawCall次数较高,意味着CPU会花费更多的时间准备渲染数据,这会进行更多的计算,进而影响游戏的运行效率

    3. 如何减少DrawCall?

      • 2D和UI层面:打图集,并且注意面板中不同图集图片的层级不要穿插
      • 3D模型层面:利用动态批处理和静态批处理,尽量不使用实时光照和实时阴影

      等等