抽象类是一种特殊的类,它不能被实例化,只能用作其他类的基类。抽象类用于定义一组相关的类的共同行为和属性。
定义一个抽象类
//区别:定义了一个抽象的方法
//由virtual 换成了 abstract,都是代表虚方法,需要让子类重新来实现的,区别在于abstract不需要展开。
public abstract class Pet {
public String Name;
public String Health;
public String Gender;
public abstract void Eat();
public abstract void ToHospital();
}
//如果只描述抽象类不赋值,代表空指针
Pet pet;
//Pet pet2 = new Pet(); //抽象类是不能直接创建本类实例的
定义一个抽象类的派生类
//注意:凡是继承抽象类的当前类,都需要把基类中描述的方法实现了,否则会报错
public class Dog : Pet {
public override void Eat() {
Console.WriteLine("狗子喜欢吃骨头");
}
public override void ToHospital() {
Console.WriteLine("健康也很重要");
}
}
Dog dog;
//使用了基类指向了派生类对象
pet = new Dog();
//as 将一个对象转成另一个对象,如果转换失败则返回null
dog = pet as Dog;
if (dog != null) dog.Eat();
else Console.WriteLine("转换失败了");
注意:凡是继承抽象类的当前类,都需要把基类中描述的方法实现了,否则会报错
接口(interface)是一种定义了一组方法、属性、事件或索引器的合同。接口定义了类或结构体应该实现的成员列表,用于描述对象的行为或能力。
// 接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的
//当需要继承的目标是多个的时候,可以考虑使用接口
public interface A {
//接口的方法只声明不实现,表示需要在派生类中实现
void Method1();
}
public interface B : A {
//只有类继承自接口的时候接口的方法需要实现,如果是接口继承自接口,则不需要实现
void MethodB();
}
//在这里(派生类)中实现接口中的方法
class Man : A, B {
public void Method1() {
Console.WriteLine("这是继承自接口A的方法");
}
public void Method2() {
Console.WriteLine("这是自身的方法");
}
public void MethodB() {
Console.WriteLine("这是继承自接口B的方法");
}
}
接口中的成员
接口中应该只包含方法的声明,不能有方法的实现
接口中不能出现构造函数
接口中不能包含实例字段,也不能包含运算符重载
接口中不允许声明成员修饰符,默认只有一个就是 public
public interface ISpeakLanguge {
//接口中应该只包含方法的声明,不能有方法的实现
void Speak();
//接口中不能出现构造函数
//public ISpeakLanguge(){}
//接口中不能包含实例字段,也不能包含运算符重载
//int a;
//接口中不允许声明成员修饰符,默认只有一个就是 public
//private void aa(string a) { }; //报错
}
public class ChinesePeople : ISpeakLanguge {
//如果一个类继承了接口,那么首先要把接口中声明的方法实现,否则会报错
public void Speak() {
Console.WriteLine("中国人说中国话。");
}
}
两者的区别 | 抽象类 | 接口 |
---|---|---|
实现方式 | 通过继承来实现 | 通过实现来实现的 |
实现限制 | 一个类可以同时继承抽象类并实现接口,但只能继承一个抽象类 | 一个类可以实现多个接口 |
成员类型 | 可以包含具体方法的实现,也可以包含抽象方法和属性 | 只能定义抽象方法、属性、事件和索引器,不能包含具体实现 |
构造函数 | 可以有构造函数 | 不能有构造函数 |
默认实现 | 可以提供成员的默认实现,派生类可以选择性地重写或调用基类的实现 | 没有默认实现,实现接口的类必须提供所有成员的具体实现 |
目的和设计理念 | 用于表示一种通用的基类,它可以包含代码重用和共享状态的能力 | 用于定义一种契约,规定了类应该具有的行为,强调了多态性和代码的松耦合性 |
//在装箱过程中,系统会创建一个新的引用类型对象,并将值类型的数据复制到该对象中。
int value = 10;
object boxedValue = value; // 装箱操作
//在拆箱过程中,系统会检查引用类型对象是否实际上装箱了值类型数据,并将其提取出来。
object boxedValue = 10; // 装箱操作
int value = (int)boxedValue; // 拆箱操作
注意:
拆箱操作需要进行显式的类型转换,以确保拆箱后的数据类型正确。如果拆箱的对象并非装箱时的值类型,或者装箱对象为 null,那么在拆箱时会抛出异常。
拆箱和装箱的过程会涉及数据的复制和类型转换,因此可能会对性能产生一定的影响。在需要频繁操作值类型数据的场景中,尽量避免不必要的装箱和拆箱操作,以提高代码的执行效率。