8.面向对象-封装-索引器
8.1 知识点
知识回顾
class 类名
{
#region 特征——成员变量
#endregion
#region 行为——成员方法
#endregion
#region 初始化调用——构造方法
#endregion
#region 释放时调用——析构方法
#endregion
#region 保护成员变量用——成员属性
#endregion
}
索引器基本概念
- 让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写。
索引器基本语法
访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名.....]
{
// 内部的写法和规则和索引器相同
get{}
set{}
}
实例
class Person
{
private string name;
private int age;
private Person[] friends;
//声明索引器
public Person this[int index]
{
//索引器get和set的用法可以说和成员属性几乎一样
//区别是索引器要传入参数
get
{
//可以写逻辑的 根据需求来处理这里面的内容
return friends[index];
}
set
{
friends[index] = value;
}
}
}
索引器中可以写逻辑
public Person this[int index]
{
//索引器get和set的用法可以说和成员属性几乎一样
//区别是索引器要传入参数
get
{
//可以写逻辑的 根据需求来处理这里面的内容
//判断朋友数组为不为空或者会不会数组越界
if (friends == null || friends.Length - 1 < index)
{
return null;
}
return friends[index];
}
set
{
//可以写逻辑的 根据需求来处理这里面的内容
//value代表传入的值
//判断朋友数组为不为空
if (friends == null)
{
//如果朋友数组为空
//则开个新房间 把传入的值丢到第一个房间去
friends = new Person[] { value };
}
else if (index > friends.Length - 1)
{
//如果传入的索引越界
//自己定了一个规则 如果索引越界 就默认把最后一个朋友顶掉
friends[friends.Length - 1] = value;
}
else
{
//如果朋友数组不为空 且 传入的索引不越界
//直接赋值即可
friends[index] = value;
}
}
}
索引器可以重载
- 索引器的重载要点
- 重载的概念是——函数名相同,参数类型、数量、顺序不同。
- 可以理解为this就是索引器的函数名。
- 学了
Object
后,索引器的返回值相当于可以返回任意类型。
实例
参数数量不同的索引器重载
public int this[int i, int j] { get { return array[i, j]; } set { array[i, j] = value; } }
参数类型不同的索引器重载
public string this[string str] { get { switch (str) { case "name": return this.name; case "age": return age.ToString(); } return ""; } }
索引器的使用
主函数内:
Person p = new Person();
p[0] = new Person();
// 使用索引器
// 给 p 的 friends 数组中索引 0 的对象 new 一个 Person 房间
Console.WriteLine(p[0]); // Lesson6_封装_索引器.Person
// p[0, 0] = 10; // 会报错,Person 的二维数组没有初始化
总结
索引器对于我们来说的主要作用
- 可以让我们以中括号的形式范围自定义类中的元素,规则自己定,访问时和数组一样。
- 比较适用于在类中有数组变量时使用,可以方便的访问和进行逻辑处理。
固定写法
- 访问修饰符 返回值 this[参数列表]
- get 和 set 语句
注意:结构体里面也是支持索引器
8.2 知识点代码
using System;
namespace Lesson6_封装_索引器
{
#region 知识回顾
class 类名
{
#region 特征——成员变量
#endregion
#region 行为——成员方法
#endregion
#region 初始化调用——构造方法
#endregion
#region 释放时调用——析构方法
#endregion
#region 保护成员变量用——成员属性
#endregion
}
#endregion
#region 知识点一 索引器基本概念
//基本概念
//让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写
#endregion
#region 知识点二 索引器基本语法
//基本语法
//访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名.....]
//{
// 内部的写法和规则和索引器相同
// get{}
// set{}
//}
//实例
// 人 类
class Person
{
private string name;
private int age;
private Person[] friends;
private int[,] array;
//声明索引器
public Person this[int index]
{
//索引器get和set的用法可以说和成员属性几乎一样
//区别是索引器要传入参数
get
{
#region 知识点三 索引器中可以写逻辑
//可以写逻辑的 根据需求来处理这里面的内容
//判断朋友数组为不为空或者会不会数组越界
if (friends == null ||
friends.Length - 1 < index)
{
return null;
}
#endregion
return friends[index];
}
set
{
#region 知识点三 索引器中可以写逻辑
//可以写逻辑的 根据需求来处理这里面的内容
//value代表传入的值
//判断朋友数组为不为空
if (friends == null)
{
//如果朋友数组为空
//则开个新房间 把传入的值丢到第一个房间去
friends = new Person[] { value };
}
else if (index > friends.Length - 1)
{
//如果传入的索引越界
//自己定了一个规则 如果索引越界 就默认把最后一个朋友顶掉
friends[friends.Length - 1] = value;
}
else
{
//如果朋友数组不为空 且 传入的索引不越界
//直接赋值即可
friends[index] = value;
}
#endregion
}
}
#region 知识点五 索引器可以重载
//索引器的重载要点
//重载的概念是——函数名相同 参数类型、数量、顺序不同
//可以理解为this就是索引器的函数名
//学了万物之父Object后 索引器的返回值相当于可以返回任意类型
//实例
//参数数量不同的索引器重载
public int this[int i, int j]
{
get
{
return array[i, j];
}
set
{
array[i, j] = value;
}
}
//参数类型不同的索引器重载
public string this[string str]
{
get
{
switch (str)
{
case "name":
return this.name;
case "age":
return age.ToString();
}
return "";
}
}
#endregion
}
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("索引器");
#region 知识点五 索引器的使用
Person p = new Person();
p[0] = new Person();
//使用索引器
//给p的friends数组中索引0的对象new一个Person房间
Console.WriteLine(p[0]);//Lesson6_封装_索引器.Person
//p[0, 0] = 10;//会报错 Person的二维数组没有初始化
#endregion
}
}
//总结
//索引器对于我们来说的主要作用
//可以让我们以中括号的形式范围自定义类中的元素 规则自己定 访问时和数组一样
//比较适用于 在类中有数组变量时使用 可以方便的访问和进行逻辑处理
//固定写法
//访问修饰符 返回值 this[参数列表]
//get和set语句块
//可以重载
//注意:结构体里面也是支持索引器
}
8.3 练习题
自定义一个整型数组类,该类中有一个整形数组变量,为它封装增删查改的方法
基本思路
- 使用list的底层实现原理
- 初始化时给定一定的房间容量
- 记录当前使用了几个房间
- 当房间容量大于等于当前使用了几个房间的值时,直接放
- 当房间容量小于等于当前使用了几个房间的值时,开更大容量的房间,搬家
- 避免产生很多垃圾,消耗过多的性能,造成卡顿
class语句块外 namespace语句块内
// class语句块外 namespace语句块内
// 整型数组类
class IntArray
{
// 基本思路
// 使用list的底层实现原理
// 初始化时给定一定的房间容量
// 记录当前使用了几个房间
// 当房间容量大于等于当前使用了几个房间的值时 直接放
// 当房间容量小于等于当前使用了几个房间的值时 开更大容量的房间 搬家
// 避免产生很多垃圾 消耗过多的性能 造成卡顿
#region 成员变量
// 整型数组数组
private int[] array;
// 当前房间容量
private int capacity;
// 当前使用了几个房间
private int length;
#endregion
#region 成员属性
public int Length
{
get
{
return length;
}
}
public int Capacity
{
get
{
return capacity;
}
}
#endregion
#region 构造函数
public IntArray()
{
capacity = 4; // 初始化时,只准备有4个空房间
length = 0; // 初始化时,1个房间都没有使用
array = new int[capacity]; // 开对应数量的房间
}
#endregion
#region 成员方法
// 增
public void Add(int value)
{
// 如果要增加就涉及扩容
// 扩容就涉及 "搬家"
// 但是若每次增加一个元素 就搬一次家的话
// 会消耗很多性能和产生很多垃圾
// 当前使用了几个房间的值 小于房间容量
if (length < capacity)
{
// 直接放
array[length] = value;
// 使用的房间数+1
++length;
}
// 当前使用了几个房间的值 大于等于房间容量
else
{
// 准备好开更大容量的新房间
capacity *= 2;
// 开新房间
int[] tempArray = new int[capacity];
Console.WriteLine("开始搬家,旧房间容量为{0},新房间容量为{1}.", capacity / 2, capacity);
// 开始搬家 遍历老房间的东西 放进新房间里
for (int i = 0; i < array.Length; i++)
{
tempArray[i] = array[i];
}
// 老的房间地址 指向新房间地址
array = tempArray;
// 当前房间要存的值 往后面放
array[length] = value;
// 使用的房间数+1
++length;
Console.WriteLine("搬家完成,搬家前使用的房间数为{0},搬家后使用的房间数为{1}.", length - 1, length);
}
}
// 删
// 移除指定值
public void Remove(int value)
{
// 找到传入值在哪个位置
for (int i = 0; i < length; i++)
{
if (array[i] == value)
{
RemoveAt(i);
return;
}
}
// 使用的房间数-1
Console.WriteLine("没有在数组中找到{0}", value);
}
// 移除指定位置
public void RemoveAt(int index)
{
// 判断要移除的索引是否越界
if (index > length - 1)
{
Console.WriteLine("当前数组只有{0},你越界了", length);
return;
}
Console.WriteLine("准备移除索引是{0}的元素,该位置的值是{1}", index, array[index]);
// 要移除位置的后面所有元素逐个往前搬 覆盖前一个的值
// 为什么是length - 1不是length
// 是因为最后一个元素已经往前搬了 值已经copy出来了
for (int i = index; i < length - 1; i++)
{
array[i] = array[i + 1];
}
// 搬完后 最后一个空出来的可以回设置默认值
也可以不处理
array[length - 1] = 0;
// 使用的房间数-1
--length;
Console.WriteLine("移除完成,删除前使用的房间数为{0},删除后使用的房间数为{1}.", length + 1, length);
}
#endregion
#region 索引器
// 查改
public int this[int index]
{
get
{
if (index >= length || index < 0)
{
Console.WriteLine("越界");
return 0;
}
return array[index];
}
set
{
if (index >= length || index < 0)
{
Console.WriteLine("越界");
}
array[index] = value;
}
}
#endregion
}
主函数内
// 主函数内
IntArray myIntArray = new IntArray();
myIntArray.Add(100);
Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:100
myIntArray.Add(200);
myIntArray.Add(300);
myIntArray.Add(400);
Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:4
Console.WriteLine("myIntArray.Capacity:" + myIntArray.Capacity);//myIntArray.Capacity:4
myIntArray.Add(500);
//开始搬家,旧房间容量为4,新房间容量为8.
//搬家完成,搬家前使用的房间数为4,搬家后使用的房间数为5
Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:5
Console.WriteLine("myIntArray.Capacity:" + myIntArray.Capacity);//myIntArray.Capacity:8
Console.WriteLine("myIntArray[1]:" + myIntArray[1]);//myIntArray[1]:200
myIntArray.RemoveAt(10);//当前数组只有5,你越界了
myIntArray.RemoveAt(1);
//准备移除索引是1的元素,该位置的值是200
//移除完成,删除前使用的房间数为5,删除后使用的房间数为4.
Console.WriteLine("myIntArray[1]:" + myIntArray[1]);//myIntArray[1]:300 200已经被移除
myIntArray.Remove(200);//没有在数组中找到200 200已经被移除
Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:100
myIntArray.Remove(100);
//准备移除索引是0的元素,该位置的值是100
//移除完成,删除前使用的房间数为4,删除后使用的房间数为3.
Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:300 100和200已经被移除
Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:3
8.4 练习题代码
using System;
namespace Lesson6_练习题
{
#region 练习题
//自定义一个整型数组类,该类中有一个整形数组变量
//为它封装增删查改的方法
//class语句块外 namespace语句块内
// 整型数组 类
class IntArray
{
//基本思路
//使用list的底层实现原理
//初始化时给定一定的房间容量
//记录当前使用了几个房间
//当前使用了几个房间的值 小于房间容量 时 直接放
//当前使用了几个房间的值 大于等于房间容量 时 开更大容量的新房间 搬家
//避免产生很多垃圾 消耗过多的性能 造成卡顿
#region 成员变量
//整型数组数组
private int[] array;
//当前房间容量
private int capacity;
//当前使用了几个房间
private int length;
#endregion
#region 成员属性
public int Length
{
get
{
return length;
}
}
public int Capacity
{
get
{
return capacity;
}
}
#endregion
#region 构造函数
public IntArray()
{
capacity = 4;//初始化时 只只准备有4个空房间
length = 0;//初始化时 1个房间都没有使用
array = new int[capacity];//开对应数量的房间
}
#endregion
#region 成员方法
//增
public void Add(int value)
{
//如果要增加就涉及扩容
//扩容就涉及 "搬家"
//但是若每次增加一个元素 就搬一次家的话
//会消耗很多性能和产生很多垃圾
//当前使用了几个房间的值 小于房间容量
if ( length < capacity )
{
//直接放
array[length] = value;
//使用的房间数+1
++length;
}
//当前使用了几个房间的值 大于等于房间容量
else
{
//准备好开更大容量的新房间
capacity *= 2;
//开新房间
int[] tempArray = new int[capacity];
Console.WriteLine("开始搬家,旧房间容量为{0},新房间容量为{1}.", capacity / 2, capacity);
//开始搬家 遍历老房间的东西 放进新房间里
for (int i = 0; i < array.Length; i++)
{
tempArray[i] = array[i];
}
//老的房间地址 指向新房间地址
array = tempArray;
//当前房间要存的值 往后面放
array[length] = value;
//使用的房间数+1
++length;
Console.WriteLine("搬家完成,搬家前使用的房间数为{0},搬家后使用的房间数为{1}.", length-1, length);
}
}
//删
//移除指定值
public void Remove(int value)
{
//找到 传入值 在哪个位置
for (int i = 0; i < length; i++)
{
if(array[i] == value)
{
RemoveAt(i);
return;
}
}
//使用的房间数-1
Console.WriteLine("没有在数组中找到{0}", value);
}
//移除指定位置
public void RemoveAt(int index)
{
//判断要移除的索引是否越界
if( index > length - 1 )
{
Console.WriteLine("当前数组只有{0},你越界了", length);
return;
}
Console.WriteLine("准备移除索引是{0}的元素,该位置的值是{1}", index, array[index]);
//要移除位置的后面所有元素逐个往前搬 覆盖前一个的值
//为什么是length - 1不是length
//是因为最后一个元素已经往前搬了 值已经copy出来了
for (int i = index; i < length - 1; i++)
{
array[i] = array[i + 1];
}
//搬完后 最后一个空出来的可以回设置默认值 也可以不处理
array[length-1] = 0;
//使用的房间数-1
--length;
Console.WriteLine("移除完成,删除前使用的房间数为{0},删除后使用的房间数为{1}.", length + 1, length);
}
#endregion
#region 索引器
//查改
public int this[int index]
{
get
{
if( index >= length || index < 0)
{
Console.WriteLine("越界");
return 0;
}
return array[index];
}
set
{
if (index >= length || index < 0)
{
Console.WriteLine("越界");
}
array[index] = value;
}
}
#endregion
}
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("索引器练习题");
//主函数内
IntArray myInyArray = new IntArray();
myInyArray.Add(100);
Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:100
myInyArray.Add(200);
myInyArray.Add(300);
myInyArray.Add(400);
Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:4
Console.WriteLine("myInyArray.Capacity:" + myInyArray.Capacity);//myInyArray.Capacity:4
myInyArray.Add(500);
//开始搬家,旧房间容量为4,新房间容量为8.
//搬家完成,搬家前使用的房间数为4,搬家后使用的房间数为5
Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:5
Console.WriteLine("myInyArray.Capacity:" + myInyArray.Capacity);//myInyArray.Capacity:8
Console.WriteLine("myInyArray[1]:" + myInyArray[1]);//myInyArray[1]:200
myInyArray.RemoveAt(10);//当前数组只有5,你越界了
myInyArray.RemoveAt(1);
//准备移除索引是1的元素,该位置的值是200
//移除完成,删除前使用的房间数为5,删除后使用的房间数为4.
Console.WriteLine("myInyArray[1]:" + myInyArray[1]);//myInyArray[1]:300 200已经被移除
myInyArray.Remove(200);//没有在数组中找到200 200已经被移除
Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:100
myInyArray.Remove(100);
//准备移除索引是0的元素,该位置的值是100
//移除完成,删除前使用的房间数为4,删除后使用的房间数为3.
Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:300 100和200已经被移除
Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:3
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com