-
1、泛型类就是一个模子,放入类型的材料(字段属性方法),可以塑造出想要的产品。
2、语法
class Cage<T>//这是一个笼子类和泛型类,类名后加上一对<>,加上一个泛型参数
{
T[] petArray;//定义T类型的数组
public void PutIn(T pet){···}//放入T类型的宠物
public T TakeOut(int index){···}//占位符T,cage类变为具体类时,T相应的变成具体数
}
//实例化
var dogCage=new Cage<Dog>();//得到狗狗笼子
var catCage=new Cage<Cat>();//得到猫咪笼子
3、为什么需要泛型,用基类(包括所有类的基类object)或者公共的接口也可以实现一个Cage类,但是类型太宽泛,需要显示转换类型并判断真是类型是什么。
4、泛型使用:声明一个泛型类->引用泛型->构造实例
class Cage<t>{···}
class Cage<Dog>{···}
dogCage=new Cage<Dog>;
比如不写Petcage<Dog> dog=new Petcage<Dog> ("名字");而用一个从来没见过的 var代替。还有 return default<T>也没解释啥意思
理解:泛型就是在不确定类的参数类型和返回类型时,设置一个变量来代替这个固定的类型。当创建类实例时,在给这个变量赋对应类类型值,这样就可以实现一个类,输出不同类型的值和方法。
不用老师的例子,用一个给数组赋值输出数组的例子更好理解;如设置一个类,构造函数初始化一个数组数组类型为int,有给数组赋值方法和获取数组值的方法,在此注意:数组的类型int和获取数组值的方法的返回值类型都为int,如果实例此类调用方法,实参和返回值类型也必须是int;就此限定死了此类的实例; 如果想要一个设置char类型的实例,还得必须创建一个新的char的类和方法才能实现;这样代码工作量很大;若使用泛型,用变量<T>代替固定类型int或char,这样在实例化的时候,将T赋不同类型(int、double、char)就可以获得想要的返回值类型,从而实现了一个模板,只变一个参数T就能实现相同的功能
上面给出的例子。只需要把所有<T>去掉,后面的T全改为int或char 就能变为普通类了。对比理解非常简单了查看全部 -
1、什么是重载运算符
不能创造新的运算符,所以利用现有的某种运算符,针对自定义类或者结构(预定义类型和现有运算符的运算含义是确定的所有不能更改),定义某种运算符(该运算符和该操作具有一定相关性,如公狗狗+母狗狗=新生狗狗),从而简化自定义类型的操作。
为什么需要重载运算符:利用现有运算符,简化自定义类型的操作。最好是,该运算符和该操作,具有一定亿相关性。
2、语法细节
public static Dog operator +(Dog male,Dog female)//如公狗狗+母狗狗=新生狗狗
{
···
}
3、哪些运算符可以重载
一元运算符:+、-、!、~、++、- -、true、false(操作数必须是类和结构)
二元运算符:+、-、*、%、&、|!、^、<<、>>、= =、!=、>、<、>=、<=(两个操作数至少有一个表示类或者结构)
不能重载:=、&&、||、[](索引操作)、()等
4、重载运算符不能做什么
创造新运算符
改变运算符语法
重定义运算符如何处理预定义类型
改变运算符的优先级和结合性
5、重在运算符举例
···
public void ShowAge()
{
Console.WriteLine("Age="+_age);
}
···
//重载自增操作,针对宠物的年龄
public static Pet opertor ++(Pet pet)//返回值为Pet类型,参数为宠物自身。所有的重载方法都需要public static修饰
{
++pet._age;
return pet;
}
···
Dog dog=new Dog("Jack");
dog._age=2;
dog++;
dog.ShowAge();查看全部 -
隐式转换语法public static implicit opertor Dog()(Cat cat){retuen new Cat(Dog dog);}
显示转换语法public static explicit operator Dog(Cat cat){...}
查看全部 -
1、装箱:根据值类型的值,在堆上创建一个完整的引用类型对象,并返回对象的引用,是一种隐式转换(语言自动完成)。
2、为什么要装箱
有时候需要将值类型转化为引用类型(比如object)来进行统一的操作(比如作为函数的参数)和统一的存储(比如object[])。
3、装箱简单实例
int i=3;
object oi=null;
oi=i;//发生装箱,原来的int保持不变,创建了一个新的对象,该对象在堆当中。需要性能消耗的。
4、装箱的本质
就是在对上创建了一个引用类型的副本,新创建的引用类型和原来的值类型相互独立。
相互独立代码验证:
int i=3;
object oi=i;//发生装箱
Console.WriteLine("i="+i+",oi="+oi.ToString);//输出为i=3,oi=3
oi=10;
i=7;
Console.WriteLine("i="+i+",oi="+oi.ToString);//输出为i=7,oi=10, oi存储在堆中, i存储在栈中
说明两者相互独立
5、拆箱
将装箱后的对象转化回值类型的过程,是一种显示转换(需要手动干预)。
6、拆箱实例
in i=3;
object oi=i;//装箱
int j=(int)oi;//拆箱 通过强制转换Console.WriteLine("j="+j);//输出10
查看全部 -
1、静态类
包含静态属性和方法,被标记为static
静态类不能创建实例,不能被继承。
可以为静态类定义静态构造函数。
2、作用
主要用于基础类库(math类)和扩展方法。
3、如何扩展方法
若有源代码,直接添加一个新方法
如果不能修改单也不是密闭类,可以派生子类扩展
如果以上条件不满足,可以使用静态类扩展方法
3、在静态类中的静态方法中参数中加入this关键,则可以直接利用对象调用方法就可以。static class PetGuide//扩展Dog类的方法
{public static double HowToFreedDog(this Dog dog){...}
{
Console.WriteLine("播放如何喂养一直狗狗的视频");
}
}Dog dog=new Dog("Tommy");
dog.HowToFreedDog();
4、总结扩展要求
扩展方法所属的类,必须是static类
扩展方法本身就是static方法
扩展方法的第一个参数类型,必须是this+类名。
例如:
Dog类没办法修改,修改Dog类就需要扩展方法,需要一个喂养宠物的方法
static class PetGuide//扩展Dog类的方法
{static public void HowToFreedDog(this Dog dog)
{
Console.WriteLine("播放如何喂养一直狗狗的视频");
}
}
···
Dog dog=new Dog();//Dog类中没有HowToFreedDog();方法
dog.HowToFreedDog();//扩展之后好像Dog类中有这样的方法一样。查看全部 -
静态类和静态成员
1、类的静态成员
成员被标记为static时,就是静态成员。静态成员将会被类的所有实例共享,所有实例都访问统一内存位置。
静态成员跟实例成员分开存放。静态成员存放在堆中。class Dog{static int Num;}2、静态成员访问
直接通过类名访问,普通成员需要通过实例访问。3、静态成员声明周期
独立任何实例,没有实例也可以访问。静态成员使用之前编译器已经帮忙完成初始化。
4、静态函数不能访问实例成员,仅能访问其他静态成员,普通方法可以访问静态成员
5、静态构造函数class Dog{static public void PrintNum(){Console.WriteLine(“Num=”+Num);}}用于初始化静态字段
在引用任何静态成员之前,和创建任何实例之前调用。
与类同名,使用static,无参数,没有访问修饰符,普通构造函数可以重载的.
静态函数只能访问静态成员,非静态函数可以访问静态/非静态成员class Dog//类名
{static Dog()//静态构造函数,与类同名,无参数,无访问修饰符
{num=0;//只能访问静态成员
}
}
查看全部 -
结构和类
1、不同点
结构是值类型(在栈中),类是引用类型(在堆中)
结构不支持继承,类支持继承
结构不定义默认构造函数,编译器会定义
2、适用场合
结构由于分配内存快,作用域结束即被删除。不需要垃圾回收,用于小型数据结构,传递过程会复制,应该用ref类参数传递提高效率。
类用于其他需要继承体系的场合。
例如:定义食物是一个不需要长期存储的数据类型,吃完就没有了,所以可以定义一个食物struct关于堆和栈内存: 栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。 堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
查看全部 -
接口
1、接口就是制定一组函数成员,而不实现他们的引用类型,用interface声明。接口函数不能用其他访问修饰符修饰,默认为public。interface ICatchMice{void CatchMice();}
2、接口只能用来被实现
例如 Cat:ICatchMice{ public void CatchMice(){...}
//实现接口函数
}Cat c=new Cat();
ICatchMice ic=(ICatchMice)c;
c.CatchMice(); //通过对象调用
ic.CatchMice(); //通过接口调用
3、一个类可以实现多个接口,当一个类同时继承基类和实现接口时,应该将基类写在最前面,用逗号隔开
可实现多个接口
Cat:Pet ,ICatchMice,IClimbTree //基类 接口1 接口2
{
public void CatchRat(){}.
public void ClimbTree()}
...
}
4、一个类实现接口时,必须实现接口声明的函数。
5、可以通过接口引用调用接口中的方法,也可通过实例调用接口方法。例子
爬树为一个接口,抓老鼠为一个接口,当猫这个类实现这两个接口时,
Cat c=new Cat("tom");
爬树 ci=(爬树)c;
c.pashu();//通过实例调用接口方法
ci.pashu();//通过接口引用调用接口方法查看全部 -
密闭类 密闭方法
sealed override public void Speak(){}
查看全部 -
派生类调用基类的构造函数
查看全部 -
扩展想扩展类的方法
查看全部 -
抽象
查看全部 -
依赖倒置原则,程序尽量依赖于抽象类
查看全部 -
隐藏方法
查看全部 -
优点
查看全部
举报