Unity 面试题汇总(一)
C#语言基础
1. 重载和重写的区别
1) 封装、继承、多态所处位置不同,重载在同类中,重写在父子类中。
2) 定义方式不同,重载方法名相同参数列表不同,重写方法名和参数列表都相同。
3) 调用方式不同,重载使用相同对象以不同参数调用,重写用不同对象以相同参数调用。
4) 多态时机不同,重载时编译时多态,重写是运行时多态。
2. 面向对象的三大特点
1.继承: 提高代码重用度,增强软件可维护性的重要手段,符合开闭原则。继承最主要的作用就是把子类的公共属性集合起来,便与共同管理,使用起来也更加方便。你既然使用了继承,那代表着你认同子类都有一些共同的特性,所以你把这些共同的特性提取出来设置为父类。继承的传递性:传递机制 a▶b; b▶c; c具有a的特性 。继承的单根性:在C#中一个类只能继承一个类,不能有多个父类。
2.封装: 封装是将数据和行为相结合,通过行为约束代码修改数据的程度,增强数据的安全性,属性是C#封装实现的最好体现。就是将一些复杂的逻辑经过包装之后给别人使用就很方便,别人不需要了解里面是如何实现的,只要传入所需要的参数就可以得到想要的结果。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。
3.多态性: 多态性是指同名的方法在不同环境下,自适应的反应出不同得表现,是方法动态展示的重要手段。多态就是一个对象多种状态,子类对象可以赋值给父类型的变量。
3.简述值类型和引用类型有什么区别
1.值类型存储在内存栈中,引用类型数据存储在内存堆中,而内存单元中存放的是堆中存放的地址。
2.值类型存取快,引用类型存取慢。
3.值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针和引用。
4.栈的内存是自动释放的,堆内存是.NET 中会由 GC 来自动释放。
5.值类型继承自 System.ValueType,引用类型继承自 System.Object。
4.请简述private,public,protected,internal的区别
public:对任何类和成员都公开,无限制访问
private:仅对该类公开
protected:对该类和其派生类公开
internal:只能在包含该类的程序集中访问该类
protected internal:protected + internal
5.C#中所有引用类型的基类是什么
引用类型的基类是System.Object值类型的基类是 System.ValueType 同时,值类型也隐式继承自System.Object
6.请简述ArrayList和 List的主要区别
ArrayList不带泛型 数据类型丢失
List带泛型 数据类型不丢失
ArrayList需要装箱拆箱 List不需要
7.请简述GC(垃圾回收)产生的原因,并描述如何避免?
GC为了避免内存溢出而产生的回收机制
避免:1)减少 new 产生对象的次数
2)使用公用的对象(静态成员)
3)将 String 换为 StringBuilder
8.请描述Interface与抽象类之间的不同
1.接口不是类 不能实例化 抽象类可以间接实例化
2.接口是完全抽象 抽象类为部分抽象
3.接口可以多继承 抽象类是单继承
9.请简述关键字Sealed用在类声明和函数声明时的作用
类声明时可防止其他类继承此类,在方法中声明则可防止派生类重写此方法。
10.反射的实现原理?
可以在加载程序运行时,动态获取和加载程序集,并且可以获取到程序集的信息反射即在运行期动态获取类、对象、方法、对象数据等的一种重要手段
主要使用的类库:System.Reflection
核心类:
1.Assembly描述了程序集
2.Type描述了类这种类型
3.ConstructorInfo描述了构造函数
4.MethodInfo描述了所有的方法
5.FieldInfo描述了类的字段
6.PropertyInfo描述类的属性
通过以上核心类可在运行时动态获取程序集中的类,并执行类构造产生类对象,动态获取对象的字段或属性值,更可以动态执行类方法和实例方法等。
11..Net与 Mono 的关系?
.Net是一个语言平台,Mono为.Net提供集成开发环境,集成并实现了.NET的编译器、CLR 和基础类库,使得.Net既可以运行在windows也可以运行于 linux,Unix,Mac OS 等。
12.在类的构造函数前加上static会报什么错?为什么?
构造函数格式为public+类名如果加上 static 会报错(静态构造函数不能有访问、型的对象,静态构造函数只执行一次;运行库创建类实例或者首次访问静态成员之前,运行库调用静态构造函数;静态构造函数执行先于任何实例级别的构造函数;显然也就无法使用this和 base 来调用构造函数。
13.C# String类型比 stringBuilder 类型的优势是什么?
如果是处理字符串的话,用string中的方法每次都需要创建一个新的字符串对象并且分配新的内存地址,而 stringBuilder 是在原来的内存里对字符串进行修改,所以在字符串处理
方面还是建议用stringBuilder这样比较节约内存。但是 string 类的方法和功能仍然还是比 stringBuilder 类要强。
string类由于具有不可变性(即对一个 string 对象进行任何更改时,其实都是创建另外一个 string 类的对象),所以当需要频繁的对一个 string 类对象进行更改的时候,建议使用StringBuilder 类,StringBuilder 类的原理是首先在内存中开辟一定大小的内存空间,当对此 StringBuilder 类对象进行更改时, 如果内存空间大小不够, 会对此内存空间进行扩充,而不是重新创建一个对象,这样如果对一个字符串对象进行频繁操作的时候,不会造成过多的内存浪费,其实本质上并没有很大区别,都是用来存储和操作字符串的,唯一的区别就在于性能上。
String主要用于公共 API,通用性好、用途广泛、读取性能高、占用内存小。
StringBuilder主要用于拼接 String,修改性能好。
不过现在的编译器已经把String的 + 操作优化成 StringBuilder 了, 所以一般用String 就可以了
String是不可变的,所以天然线程同步。
StringBuilder可变,非线程同步。
14.C#函数 Func(string a, string b)用 Lambda 表达式怎么写?
(a,b) => {};
15.数列1,1,2,3,5,8,13...第 n 位数是多少?用 C#递归算法实现
public int CountNumber(int num) {
if (num == 1 || num == 2) {
return 1;
} else {
return CountNumber(num -1) + CountNumber(num-2);
}
}
16.冒泡排序(手写代码)
public static void BubblingSort(int[]array) {
for (int i = 0; i < array.Length; i++){
for (int j = array.Length - 1; j > 0; j--){
if (array[j] < array[i]) {
int temp = array[j];
array[j] = array[j-1];
array[j - 1] = temp;
}
}
}
}
17.C#中有哪些常用的容器类,各有什么特点。
List,HashTable,Dictionary,Stack,Queue
List:索引泛型容器 访问速度快 修改速度慢
HashTable/Dictionary:散列表格式 查询效率高 空间占用较大
Stack:后进先出
Queue:先进先出
18.C#中常规容器和泛型容器有什么区别,哪种效率高?
不带泛型的容器需要装箱和拆箱操作速度慢所以泛型容器效率更高数据类型更安全
19.有哪些常见的数值类?
简单值类型--包括 整数类型、实数类型、字符类型、布尔类型
复合值类型--包括 结构类型、枚举类型
20.C#中委托和接口有什么区别?各用在什么场合?
接口(interface)是约束类应该具备的功能集合,约束了类应该具备的功能,使类从千变万化的具体逻辑中解脱出来,便于类的管理和扩展,同时又合理解决了类的单继承问题。
C#中的委托是约束方法集合的一个类,可以便捷的使用委托对这个方法集合进行操作。
在以下情况中使用接口:
1.无法使用继承的场合
2.完全抽象的场合
3.多人协作的场合
以上等等
在以下情况中使用委托:多用于事件处理中
21.C#中unsafe关键字是用来做什么的?什么场合下使用?
非托管代码才需要这个关键字一般用在带指针操作的场合
22.C#中ref和out关键字有什么区别?
ref修饰参数,表示进行引用传递,out修饰参数也表示进行引用传递,但传递的引用只为带回返回值 ref又进又出 out不进只出
23.For,foreach,Enumerator.MoveNext的使用,与内存消耗情况
for循环可以通过索引依次进行遍历,foreach和Enumerator.MoveNext通过迭代的方式进行遍历。内存消耗上本质上并没有太大的区别。但是在Unity中的Update中,一般不推荐使用foreach 因为会遗留内存垃圾。
24.函数中多次使用string的+=处理,会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决。
通过StringBuilder那进行append,这样可以减少内存垃圾
25.当需要频繁创建使用某个对象时,有什么好的程序设计方案来节省内存?
设计单例模式进行创建对象或者使用对象池
26.JIT和AOT区别
Just-In-Time -实时编译
执行慢安装快占空间小一点
Ahead-Of-Time -预先编译
执行快安装慢占内存占外存大
27.给定一个存放参数的数组,重新排列数组
void SortArray(Array arr){Array.Sort(arr);}
28.Foreach循环迭代时,若把其中的某个元素删除,程序报错,怎么找到那个元素?以及具体怎么处理这种情况?(注:Try.....Catch捕捉异常,发送信息不可行)
foreach不能进行元素的删除,因为迭代器会锁定迭代的集合,解决方法:记录找到索引或者key值,迭代结束后再进行删除。
29.GameObject a=new GameObject() GameObject b=a 实例化出来了A,将A赋给B,现在将B删除,问A还存在吗?
存在,b删除只是将它在栈中的内存删除,而A对象本身是在堆中,所以A还存在
30.你拥有A块钱,一瓶水B块钱,每瓶水可以得到一个瓶盖,每C个瓶盖可以换一瓶水请写出函数求解上面题目,上面题目ABC为参数
public static int Buy(int a,int b,int c) {
return a/b + ForCap(c,a/b);
}
public static int ForCap(int c,int d) {
if (d
return 0;
} else {
return d/c + ForCap(c,d/c + d%c);
}
}
31.有一排开关,第一个人把所有的开关打开,第二个人按2的倍数的开关,第三个人按3的倍数的开关,以此类推,现在又n个开关,k个人,写函数求最后等两者的开关,输入参数n和k
static void Main(string[] args) {
int n = int.Parse(Console.ReadLine());
int k = int.Parse(Console.ReadLine());
Function(100,100);
}
static void Function(int n, int k) {
int i, j = 0;
bool[] a = new bool[1000]; //初始false:关灯,true:开灯
for (i = 1; i <= k; i++) //k个人
for (j = 1; j <= n; j++) //n个灯
if (j % i == 0)
a[j] = !a[j]; //取反,false变true,原来开变关,关变开
for (i = 1; i <= n; i++) //最后输出a[i]的值就可以了
if (a[i]) //灯亮着
Console.WriteLine(i);
}
32.数制转换,将任意整数转换成8进制形式
static void Main(string[] args) {
int n;
n =int.Parse(Console.ReadLine());
Console.WriteLine("输入的10进制为:{0}",n);
Console.Write("转换为8进制数为: ");
d2o(n);
}
static void d2o(int n) {
if (n > 7) {
d2o(n / 8);
}
Console.Write(n%8);
}
33.找出200以内的素数。
static void Main(string[] args) {
int count = 0;
for (int i = 1; i < 200; i++) {//外层循环:要判断的数
for (int j = 2; j <=i; j++){
if (i % j == 0&& i!=j) {
break;
}
if (j == i ) {//结束的条件:最后一个数还没有被整除
count++;
Console.WriteLine(i);
}
}
}
Console.WriteLine(count);
}
34.打印杨辉三角形
public static void YHSJ(){
int [][]a= new int[7][] ;
a[0] = new int[1]; //a[0][0]=1;
a[1] = new int[2] ;
for (int i = 0; i < 7; i++) {
a[i] = new int[i+1] ;
a[i][0] =1;
a[i][i]=1;
if(i>1) {//求出中间的数据
for(int j=1;j
a[i][j]= a[i-1][j-1]+a[i-1][j];
}
}
}
for (int i=0; i
for (int k = 0; k < a.Length-1-i; k++) {
Console.Write("");
}
for(int j=0;j
Console.Write(a[i][j] + "");
}
Console.WriteLine();
}
}
35.中国有句俗话“三天打鱼两天晒网”,某人从2000年1月1日起开始“三天打鱼两天晒网”,问这个人在今后的某天中“打鱼”还是”晒网”
public static void Compute(){
Console.WriteLine ((DateTime.Now - DateTime.Parse("2000-01-01")).Days%5<3?"打鱼":"晒网");
}
36.假设当前市场价一只鸡10元,一只鸭12元5角。请写一个函数ShowPrice,输入参数分别为鸡和鸭的个数(非负整型),功能为显示出总价钱,精确到分。例如调用ShowPrice(5,10)后输出175.00。请注意程序的可读性和易于维护性。
static void ShowPrice(int num_chicken, int num_duck) {
float totalPrice = 0.00f;
float price_chicken = 10f;
float price_duck = 12.5f;
totalPrice = num_chicken * price_chicken + num_duck * price_duck;
Console.WriteLine("总价钱为:{0:0.00}", totalPrice);
}
37.请写一个函数,用于返回n!(阶乘)结果末尾连续0的个数,如GetZeroCount(5)返回1,因为5! = 120,末尾连续1个0
static void Main(string[] args) {
int fac = Factorial(5);
Console.WriteLine(CountZero(fac));
}
public static int Factorial(int n) {
if (n == 1) {
return 1;
} else {
return n * jiecheng(n - 1);
}
}
//求连续的0的个数
public static int CountZero(int num) {
int result = 0; //最后的结果
String numStr = num.ToString();
for (int i = numStr.Length - 1; i >= 0; i--) {
if (numStr[i] == '0') {
result ++;
} else {
break;
}
}
return result;
}