C#(五):接口、泛型、struct、继承、方法的隐藏与重写、密封、抽象、多态
接口、泛型、struct、继承、方法的隐藏与重写、密封、抽象、多态
- 接口
- 用途
- 特点
- 语法
- 代码
- 泛型
- 使用在类中的泛型-特点:
- 使用在方法中的泛型-特点:
- 使用在接口中的泛型-特点:
- struct
- 结构体是 `值类型` `struct`
- 结构体与类的区别
- 继承
- 示例
- 继承之构造方法
- 向上转型(隐式类型转换) - 子类转换成父类
- 向下转型(需要强制类型转换) - 父类转换成子类
- 方法的隐藏与重写
- 方法隐藏
- 方法重写
- 密封
- 密封类
- 密封方法
- 抽象
- `抽象类`
- `抽象方法`
- 多态 `virtual` `abstract` `interface`
接口
用途
- 定义一系列的规范
特点
- 接口中方法不是抽象方法(接口中方法的实现不能使用 override)
- 接口中方法的实现必须是 public 权限的
- 抽象类实现接口方法可以把接口方法实现为抽象方法
- 一个类中实现接口方法可以把方法实现为虚方法
语法
- 一个类可以实现多个接口
- 一个类继承另一个类并且实现接口需要把接口下载继承类的后边,并用逗号分隔
- 区分接口与继承规范:接口命名以大写字母I开头
代码
interface IUSB
{
// 充电
public void Charge();
// 数据传输
void TransportData();
}
class Hardware {
}
// 让Mouse去实现USB这个接口
class Mouse : Hardware, IUSB
{
// 一个类中实现接口方法可以把方法实现为虚方法
public virtual void Charge() {
}
public void TransportData() {
}
}
// 抽象类实现接口方法可以把接口方法实现为抽象方法
abstract class Keyword : IUSB
{
public abstract void Charge();
public void TransportData() {
}
}
泛型
使用在类中的泛型-特点:
class Program
{
static void Main(string[] args)
{
// 使用一个泛型
Person<int> person = new Person<int>();
person.Show(23);
// 使用多个泛型
Animal<string, uint, char> animal = new Animal<string, uint, char>
{
name = "Dog",
age = 23,
sex = '男'
};
Console.WriteLine(animal.name);
Console.WriteLine(animal.age);
Console.WriteLine(animal.sex);
}
}
class Person<T> {
public T Show(T x)
{
Console.WriteLine(x);
return x;
}
}
class Animal<T, M, D>
{
public T name;
public M age;
public D sex;
}
class Animal<T, M>
{
public T name;
public M age;
}
class Animal
{
public string name;
public uint age;
}
class Dog : Animal
{
}
class Lee : Person<string>
{
}
使用在方法中的泛型-特点:
class Program
{
static void Main(string[] args)
{
Person.Show<string>();
Person.Show<string>("Hello World ~");
Person.Show("Hello World ~");
Console.ReadKey();
}
}
class Person {
public static void Show<T>()
{
Console.WriteLine("Hello World");
}
public static void Show<T>(T x)
{
Console.WriteLine(x);
}
}
使用在接口中的泛型-特点:
interface IUSB<T> {
void Show(T x);
}
class Mouse : IUSB<string> {
public void Show(string x)
{
Console.WriteLine(x);
}
}
struct
结构体是 值类型
struct
struct Person
{
// 静态构造
static Person(){
}
// 有参构造
public Person(string name, int age, char sex, double height) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
}
//字段
public string name;
public int age;
public char sex;
public double height;
public static double weight; // 静态字段
//属性
public double Height
{
set {
this.height = value;
}
get {
return height;
}
}
//方法
public void FunA() {
Console.WriteLine("Person Show ~");
}
};
class Program
{
static void Main(string[] args)
{
Person lee = new Person
{
age = 23
};
Change(lee);
Console.WriteLine(lee.age); // 230
Console.ReadKey();
}
public static void Change(Person person) {
person.age = 230;
}
}
结构体与类的区别
相同点
:- 都可以包含字段属性和方法
- 都可以通过new来实例化
- 都可以配置访问权限修饰符
不同点
:结构体是在栈上开辟的空间,是值类型,不是引用类型
class Person
{
public int age;
};
class Program
{
static void Main(string[] args)
{
Person lee = new Person();
lee.age = 23;
Change(lee);
Console.WriteLine(lee.age); // 230
Console.ReadKey();
}
public static void Change(Person person) {
person.age = 230;
}
}
struct Person
{
public int age;
};
class Program
{
static void Main(string[] args)
{
Person lee = new Person();
lee.age = 23;
Change(lee);
Console.WriteLine(lee.age); // 23
Console.ReadKey();
}
public static void Change(Person person) {
person.age = 230;
}
}
* 构造方法
* 结构体中不允许写无参构造
* 结构体的有参构造方法中必须为所有的字段进行赋值操作
struct Person
{
public Person(string name, int age, char sex, double height) {
this.name = name; // 必须赋值
this.age = age; // 必须赋值
this.sex = sex; // 必须赋值
this.height = height; // 必须赋值
}
//字段
public string name;
public int age;
public char sex;
public double height;
}
* 结构体中始终包含一个public无参的构造方法,所以 `Person p = new Person();` 不报错
* 结构体中不允许写析构函数
* 结构体中只有一个父类 `Object` ,不能被继承也不能继承
继承
- 如果多个类中拥有共同的属性和方法,那么可以提取出公共的属性和方法定义为一个新类,此类即为
父类(基类/超类)
- 多个具有相同属性和方法的类被称为
子类(派生类)
- 他们之间的关系是:
子类 继承 父类
- 特点:
a. 子类拥有父类的所有字段、属性和方法。
b. 构造方法不能被继承。
c. 一个类只能有一个父类,可以拥有多个子类。
示例
定义一个硬件类,包括 CPU 硬盘 内存 显卡 主板 电源 类,他们拥有共同属性为 名称 价格 属性
class MainClass
{
public static void Main(string[] args)
{
CPU cpu = new CPU
{
Name = "CPU"
};
cpu.SetPrice(100d);
Console.WriteLine(cpu.Name); // CPU
Console.WriteLine(cpu.GetPrice()); // 100
GPU gpu = new GPU
{
Name = "GPU"
};
gpu.SetPrice(120d);
Console.WriteLine(gpu.Name); // GPU
Console.WriteLine(gpu.GetPrice()); // 120
}
}
/// <summary>
/// 硬件类 - 父类
/// </summary>
class Hardware
{
public string Name;
private double Price;
public void SetPrice(double price)
{
Price = price;
}
public double GetPrice()
{
return Price;
}
}
/// <summary>
/// CPU 继承 硬件
/// </summary>
class CPU : Hardware {
}
/// <summary>
/// 显卡 继承 硬件
/// </summary>
class GPU : Hardware {
}
/// <summary>
/// 硬盘 继承 硬件
/// </summary>
class Disk : Hardware {
}
/// <summary>
/// 内存 继承 硬件
/// </summary>
class Memory : Hardware {
}
/// <summary>
/// 主板 继承 硬件
/// </summary>
class MainBoard : Hardware {
}
/// <summary>
/// 电源 继承 硬件
/// </summary>
class PowerSupply : Hardware {
}
继承之构造方法
报错代码
Dog dog = new Dog(); // Error 子类在实例化的时候会先实例化父类中的无参构造方法
class Animal {
public string name;
public Animal(string name)
{
this.name = name;
}
}
class Dog : Animal {
// Error
public uint age;
}
报错原因:
原因一:
子类在实例化的时候会先实例化父类中的无参构造方法,因为Animal中无无参构造方法
解决(方案一):
父类提供一个无参构造方法
Dog dog = new Dog();
class Animal {
public string name;
public Animal()
{
}
public Animal(string name)
{
this.name = name;
}
}
class Dog : Animal {
public uint age;
}
* 原因二:`子类在实例化的时候会先实例化父类中的构造方法,因为Animal中是有参的构造方法,所以需要在子类构造之前先调用父类中的有参构造方法`
* 解决(方案二):`类构造之前先调用父类中的有参构造方法`
Dog dog = new Dog();
class Animal {
public string name;
public Animal(string name)
{
this.name = name;
}
}
class Dog : Animal {
public uint age;
// base(参数) -> 执行Dog构造方法之前先去执行他的父类构造方法
public Dog() : base("")
{
}
}
* 解决思想:`想办法让父类实例化的时候合理化(让父类实例化的时候不会报错)`
向上转型(隐式类型转换) - 子类转换成父类
向上转型一定成功
Dog dog = new Dog();
Animal animal = dog;
// => Animal animalDog = new Dog();
// => sbyte b = 1; int a = b; => int ab = 1;
class Animal {
}
class Dog : Animal {
}
class Hashiqi : Dog {
}
示例:动物园动物录入
class MainClass
{
public static void Main(string[] args)
{
Animal.RecordAnimal(new Bird()); // 录入动物
// => 详单于
// Animal animal = new Bird(); // 向上转型
// Animal.RecordAnimal(animal);
}
}
class Animal {
public static void RecordAnimal(Animal animal) {
}
}
class Bird : Animal {
}
class Monkey : Animal {
}
class Tiger : Animal {
}
向上转型后的对象将不再能够使用子类中特有的字段属性和方法
class MainClass
{
public static void Main(string[] args)
{
Hashiqi hashiqi = new Hashiqi();
hashiqi.type = ""; // ok
hashiqi.sex = ' '; // ok
hashiqi.name = ""; // ok
hashiqi.age = 1; // ok
Dog dog = new Dog();
//dog.type = ""; // Error “Dog”未包含“type”的定义,并且找不到可接受第一个“Dog”类型参数的可访问扩展方法“type”
dog.sex = ' '; // ok
dog.name = ""; // ok
dog.age = 1; // ok
Animal animal = new Animal();
//animal.type = ""; // Error “Animal”未包含“type”的定义,并且找不到可接受第一个“Animal”类型参数的可访问扩展方法“type”
//animal.sex = ' '; // Error “Animal”未包含“sex”的定义,并且找不到可接受第一个“Animal”类型参数的可访问扩展方法“sex”
animal.name = ""; // ok
animal.age = 1; // ok
Animal d = new Hashiqi();
//d.type = ""; // Error “Animal”未包含“type”的定义,并且找不到可接受第一个“Animal”类型参数的可访问扩展方法“type”
//d.sex = ' '; // Error “Animal”未包含“sex”的定义,并且找不到可接受第一个“Animal”类型参数的可访问扩展方法“sex”
d.name = ""; // ok
d.age = 1; // ok
Dog dd = new Hashiqi();
//dd.type = ""; // Error “Dog”未包含“type”的定义,并且找不到可接受第一个“Dog”类型参数的可访问扩展方法“type”
dd.sex = ' '; // ok
dd.name = ""; // ok
dd.age = 1; // ok
}
}
class Animal {
public string name;
public int age;
}
class Dog : Animal {
public char sex;
}
class Hashiqi : Dog {
public string type;
}
向下转型(需要强制类型转换) - 父类转换成子类
如果向下转型失败,那么得到
null
// Dog dog = (Dog)new Animal(); // 不推荐
Dog dog = new Animal() as Dog;
Console.WriteLine(dog == null); // True
class Animal {
}
class Dog : Animal {
}
class Hashiqi : Dog {
}
转型成功
class MainClass
{
public static void Main(string[] args)
{
Animal animal = new Dog(); // 向上转型
Dog dog = animal as Dog; // 向下转型
Console.WriteLine(dog); // Dog
Console.WriteLine(dog == null); // False
}
}
class Animal {
}
class Dog : Animal {
}
class Hashiqi : Dog {
}
向下转型错误示例
class MainClass
{
public static void Main(string[] args)
{
Hashiqi hashiqi = new Animal() as Hashiqi; // 向下转型
Console.WriteLine(hashiqi == null); // True
Console.WriteLine(hashiqi.type == null); // Error System.NullReferenceException
}
}
class Animal {
public string name;
public int age;
}
class Dog : Animal {
public char sex;
}
class Hashiqi : Dog {
public string type;
}
方法的隐藏与重写
方法隐藏
父类中含有的字段属性和方法,在子类中也需要定义类似的字段属性和方法,那么就需要隐藏继承自父类的字段属性和方法
class MainClass
{
public static void Main(string[] args)
{
Animal a = new Dog();
a.Show(); // Animal.Show() -> Animal Show
Dog d = new Dog();
d.Show(); // Dog.Show() -> Dog Show
}
}
class Animal {
public void Show() {
Console.WriteLine("Animal Show");
}
}
class Dog : Animal {
// public void Show()
// 父类中含有name属性,子类还需要定义name属性,需要隐藏继承父类的属性,需要使用new
public new void Show()
{
Console.WriteLine("Dog Show");
}
}
方法重写
需要使用关键字
override
和虚函数(virtual)
- 虚函数 -> 能被子类隐藏和重写
- 非虚函数 -> 能被子类隐藏,不能被重写
重写函数
class MainClass
{
public static void Main(string[] args)
{
Animal a = new Dog();
a.Show(); // Animal.Show() -> Dog Show 因为被重写了
Dog d = new Dog();
d.Show(); // Dog.Show() -> Dog Show
}
}
class Animal {
// 子类中的方法重写父类中的方法,需要将父类中的方法设置为虚函数 virtual
public virtual void Show() {
Console.WriteLine("Animal Show");
}
}
class Dog : Animal {
// 子类中的方法重写父类中的方法 override
public override void Show()
{
Console.WriteLine("Dog Show");
}
}
* 隐藏函数
class MainClass
{
public static void Main(string[] args)
{
Animal a = new Dog();
a.Show(); // Animal.Show() -> Animal Show
Dog d = new Dog();
d.Show(); // Dog.Show() -> Dog Show
}
}
class Animal {
// 子类中的方法重写父类中的方法,需要将父类中的方法设置为虚函数 virtual
public virtual void Show() {
Console.WriteLine("Animal Show");
}
}
class Dog : Animal {
// 隐藏父类方法
public new void Show()
{
Console.WriteLine("Dog Show");
}
}
密封
密封类
特点:不能被继承
sealed class Person {
}
class Lee : Person {
} // Error “Lee”: 无法从密封类型“Person”派生
密封方法
特点:不能被继续重写,并且只有重写方法才能使用密封
class Animal {
public virtual void Show() {
}
}
class Dog : Animal {
public override sealed void Show() {
}
}
class Hashiqi : Dog{
public override void Show() {
} // Error “Hashiqi.Show()”: 继承成员“Dog.Show()”是密封的,无法进行重写
}
class Animal {
public virtual sealed void Show() {
} // Error 因为“Animal.Show()”不是重写,所以无法将其密封
}
抽象
- 定义一种规范,用于约束子类的行为
抽象类
- 不能实例化对象
- 抽象类中可以写静态和非静态的成员
- 抽象类可以被继承和继承其他类
抽象方法
抽象方法只能存在在抽象类中
一个类继承自抽象类,那么这个类中必须实现父类中的所有抽象方法
// 抽象类
abstract class Animal {
// 抽象方法
public abstract void Eat();
}
class Dog : Animal {
// 通过重写实现父类中的所有抽象方法
public override void Eat() {
}
}
多态 virtual
abstract
interface
实现多态主要有3种方法:
虚方法
,抽象类
,接口
还没有评论,来说两句吧...