在java程序设计中,经常需要用到数组,数组的存储和读取速度是数据结构中最快的一种。但是,在稍为复杂的程序设计中,我们就会发现数组的局限性,其局限性有一部分是其优点所带来的。例如:数组的长度是固定的,而且数组所存储的数据类型也是固定的。然而,在实际应用中,经常需要根据所要存储的数据的长度确定要开辟的内存空间,而且,需要存储不同类型的数据,例如存储对象。另一方面,我们需要一些通用的方法,以便对不同类型的对象进行处理,例如:一种通用的排序方法,对所有类型的对象都可以进行排序。这样,就可以增加代码的重用度,减少工作量。
由于在java中,Object是所有类的父类,因此在这些方法中,要把参数,返回值设为Object类型的,以便接收所有类型的对象。
为深入体会泛型的作用,我们先在不使用泛型的前提下,写一个数组队列类,对所有类型的传人对象都能进行处理。数组队列具有数组所不具有的灵活性,其长度可变,存储的数据类型可变。
下面是一个自定义的数组队列类,具有增删查改功能
package cn.lzj0724; /** * 纯粹的数组队列,实行增删改查等功能,一个第三方的类 * * @author lzj * */ public class MyArrayList{ private Object[] array;// 声明对象数组 private int size = 0;// 声明size属性,设置初值为0 /** * 构造方法 */ public MyArrayList() { array = new Object[0];// 初始化 } public MyArrayList(int size) { array = new Object[size];// 初始化 } /** * 向数组队列中添加元素的方法 * * @param elements要添加的元素 */ public void add(Object element) { // 创建一个新的数组,长度为size+1 Object[] newArray = new Object[size + 1]; for (int i = 0; i < size; i++) { newArray[i] = array[i];// 赋值 } newArray[size] = element;// 添加元素至数组最后的位置 size++;// size加1 array = newArray;// 把newArray的地址给array } /** * 根据索引删除对应的元素(删除区别于移除,删除需要释放空间) * * @param index要删除的元素的索引 * @return */ public Object delete(int index) { if (index < 0 || index >= size)// 防止所给下标为负值或超出size return null; Object temp;// Object类型变量 temp = array[index];// 将被删除的元素赋予临时变量temp Object[] newArray = new Object[size - 1];// 创建Object类数组,数组长度减1 // 小于索引时,照搬过去 for (int i = 0; i < index; i++) { newArray[i] = array[i];// 把值移到新数组中 } // 大于索引时 for (int i = index; i < size - 1; i++) { array[i] = array[i + 1];// 移位填补空位 newArray[i] = array[i];// 把值移到新数组中 } array = newArray;// 把newArray的地址给array size--; return temp;// 返回被删除的元素 } /** * 根据索引插入对应的元素 * * @param index要插入的位置的索引 * @return */ public Object ins(int index, Object element) { Object[] newArray = new Object[size + 1];// 创建Object类数组,数组长度减1 // 小于索引时,照搬过去 for (int i = 0; i < index; i++) { newArray[i] = array[i];// 把值移到新数组中 } newArray[index] = element; // 大于索引时 for (int i = index; i < size; i++) { newArray[i + 1] = array[i];// 把值移到新数组中 } array = newArray;// 把newArray的地址给array size++; return element;// 返回被插入的元素 } // 得到数组队列的长度的方法 public int size() { return size; } // 根据索引和传人的元素设定相应的元素 public void set(int index, Object obj) { array[index] = obj; } // 根据索引得到相应的元素 public Object get(int index) { if (index < 0 || index >= size)// 防止所给下标为负值或超出size return null; return array[index]; } public Object find(Object obj) { for (int i = 0; i < size; i++) { if (array[i].equals(obj)) return array[i]; } return null; } // 修改元素,根据元素和下标 public void modify(Object element, int index) { array[index] = element; } }
测试数组队列:
package cn.lzj0724; import java.util.Scanner; /** * 测试数组队列的类 * * @author lzj * */ public class TestArrayList { public static void main(String[] args) { // 实例化MyArrayList类的对象 数组队列对象 MyArrayList list = new MyArrayList(); Student[] stu = new Student[5];//实例化一个Student类型的数组 // 实例化一个随机类对象 java.util.Random rand = new java.util.Random(); int size = stu.length; // 循环添加元素 for (int i = 0; i < size; i++) { stu[i] = new Student("张" + i, "male", i, rand.nextInt(100), rand.nextInt(100), rand.nextInt(100));// 创建学生数组,随机分数 list.add(stu[i]);// 将Student元素添加到数组队列之中 System.out.println(list.get(i));// 输出 } System.out.println("------------------------"); list.delete(2);// 删除数组队列中下标为2的元素 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i));// 输出 } System.out.println("------------------------"); list.modify(stu[1], 3);// 把数组队列中下标为3的元素修改为下标为1的元素 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("----排序后-------"); sort(list);//调用排序方法 for (int i = 0; i < list.size(); i++) {// 输出 System.out.println(list.get(i)); } System.out.println("------------------------"); Student stu9 =new Student("张六", "male", 9, rand.nextInt(100), rand.nextInt(100), rand.nextInt(100)); list.ins(3,stu9);// 创建学生数组,随机分数) for (int i = 0; i < list.size(); i++) {// 输出 System.out.println(list.get(i)); } // 选择排序 public static void sort(MyArrayList list) { Student[] stu = new Student[list.size()];// 定义Student类型数组 for (int i = 0; i < list.size(); i++) { stu[i] = (Student) list.get(i);// 强制转换为Student类型 } for (int i = 0; i < list.size(); i++) { int minIndex = i; // 找出最小的一个索引 for (int j = i + 1; j < list.size(); j++) { if (stu[j].getAverage() < stu[minIndex].getAverage()) { minIndex = j; } } // 交换 Student temp = stu[i]; stu[i] = stu[minIndex]; stu[minIndex] = temp; } for (int i = 0; i < list.size(); i++) { list.set(i, stu[i]);//把改变后的stu数组应用到list中 } } }
运行结果如下:
代码实现了对学生信息的管理和排序处理,也可以看出,由于list不能直接调用Student类的子方法,该代码排序时事实上是对学生数组进行了排序处理,然后才逐个add到数组队列list中的。若不能实现对list的直接处理的话,代码的冗余度将会很高,在对不同的类进行处理时,也要修改,添加很多行的代码。
那么如何解决这个问题呢?
需要用到泛型。对MyArrayList类进行修改
泛型可以泛指java中的任意一种引用类型(不能指代基本数据类型)。
泛型的格式:
类名<引用数据类型> 对象名 = new 类名<引用数据类型> ( );
Java中的泛型有三种,分别为E、K、V,E是element,代表元素的数据类型;K即key,代表键值类型;V即value,代表值的类型。
声明支持泛型的类的方法:
Public class 类名 <E> { }
为方法添加元素的时候,形参表中应将元素声明为泛型型,泛指任意一种引用类型,即用户可以在实参表中填入任意数据类型。方法的返回值类型也应为泛型,在返回之前需要强制转型为泛型。
对于支持泛型的类,在创建类的对象时为了防止任意类型的元素被传入,可以再创建对象时使用尖括号指定特定的引用数据类型,此时如果向对象中传入非指定的引用类型的数据类型便会引发错误提示。
例如:
public E get(int index){ E st = (E)array[index]; return st; }
这样,在使用该队列对象前,只要指定要放入对象的类型,之后,这个队列就只能放入这种类型的对象,而且,取出后,也是这种类型的对象
使用泛型的数组队列类如下:
package cn.lzj0724; /** * 纯粹的数组队列,实行增删改查等功能,一个第三方的类 * * @author lzj * */ public class MyArrayList<E> { private Object[] array;// 声明对象数组 private int size = 0;// 声明size属性,设置初值为0 /** * 构造方法 */ public MyArrayList() { array = new Object[0];// 初始化 } public MyArrayList(int size) { array = new Object[size];// 初始化 } /** * 向数组队列中添加元素的方法 * * @param elements要添加的元素 */ public void add(E element) { // 创建一个新的数组,长度为size+1 Object[] newArray = new Object[size + 1]; for (int i = 0; i < size; i++) { newArray[i] = array[i];// 赋值 } newArray[size] = element;// 添加元素至数组最后的位置 size++;// size加1 array = newArray;// 把newArray的地址给array } /** * 根据索引删除对应的元素(删除区别于移除,删除需要释放空间) * * @param index要删除的元素的索引 * @return */ public E delete(int index) { if (index < 0 || index >= size)// 防止所给下标为负值或超出size return null; Object temp;// Object类型变量 temp = array[index];// 将被删除的元素赋予临时变量temp Object[] newArray = new Object[size - 1];// 创建Object类数组,数组长度减1 // 小于索引时,照搬过去 for (int i = 0; i < index; i++) { newArray[i] = array[i];// 把值移到新数组中 } // 大于索引时 for (int i = index; i < size - 1; i++) { array[i] = array[i + 1];// 移位填补空位 newArray[i] = array[i];// 把值移到新数组中 } array = newArray;// 把newArray的地址给array size--; return (E) temp;// 返回被删除的元素 } /** * 根据索引插入对应的元素 * * @param index要插入的位置的索引 * @return */ public E ins(int index, E element) { Object[] newArray = new Object[size + 1];// 创建Object类数组,数组长度减1 // 小于索引时,照搬过去 for (int i = 0; i < index; i++) { newArray[i] = array[i];// 把值移到新数组中 } newArray[index] = element; // 大于索引时 for (int i = index; i < size; i++) { newArray[i + 1] = array[i];// 把值移到新数组中 } array = newArray;// 把newArray的地址给array size++; return element;// 返回被插入的元素 } // 得到数组队列的长度的方法 public int size() { return size; } // 根据索引和传人的元素设定相应的元素 public void set(int index, E obj) { array[index] = obj; } // 根据索引得到相应的元素 public E get(int index) { if (index < 0 || index >= size)// 防止所给下标为负值或超出size return null; return (E) array[index]; } public E find(E obj) { for (int i = 0; i < size; i++) { if (array[i].equals(obj)) return (E) array[i]; } return null; } // 修改元素,根据元素和下标 public void modify(E element, int index) { array[index] = element; } }
使用泛型的测试类如下:
package cn.lzj0724; import java.util.Scanner; /** * 测试数组队列的类 * * @author lzj * */ public class TestArrayList { public static void main(String[] args) { // 实例化MyArrayList类的对象 数组队列对象 MyArrayList<Student> list = new MyArrayList<Student>(); Student[] stu = new Student[5];// 实例化一个Student类型的数组 // 实例化一个随机类对象 java.util.Random rand = new java.util.Random(); int size = stu.length; // 循环添加元素 for (int i = 0; i < size; i++) { stu[i] = new Student("张" + i, "male", i, rand.nextInt(100), rand.nextInt(100), rand.nextInt(100));// 创建学生数组,随机分数 list.add(stu[i]);// 将Student元素添加到数组队列之中 System.out.println(list.get(i));// 输出 } System.out.println("------------------------"); list.delete(2);// 删除数组队列中下标为2的元素 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("------------------------"); list.modify(stu[1], 3);// 把数组队列中下标为3的元素修改为下标为1的元素 // 输出 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("----排序后-------"); sort(list);// 调用排序方法,传人MyArrayList类型对象 // 输出 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("------------------------"); Student stu9 = new Student("张六", "male", 9, rand.nextInt(100), rand.nextInt(100), rand.nextInt(100)); list.ins(3, stu9);// 把学生对象stu9插入数组队列3处 // 输出 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // 修改学生信息 Scanner read = new Scanner(System.in);// 实例化Scanner int i = -1; System.out.println(" 修改学生信息"); System.out.println(); System.out.println("======================="); System.out.println(); System.out.println("请输入要修改的学生学号:"); int number1 = read.nextInt();// 得到键盘输入的数字 for (i = 0; i < size; i++) { if (list.get(i).getNumber() == number1) { System.out.println(number1 + "学号的学生姓名为:" + list.get(i).getName()); System.out.println("1 姓名 2 性别 3 语文成绩 4 数学成绩 5 英语成绩"); System.out.println("该学生的哪一项信息需要修改:"); int r = read.nextInt();// 得到键盘输入的数字 switch (r) { case 1: System.out.println("原姓名为" + list.get(i).getName() + "现姓名修改为:"); String s1 = read.nextLine(); s1 = read.nextLine(); list.get(i).setName(s1);// 调用数组队列的第i个元素的setName方法,把name属性设置为s1 break; case 2: System.out.println("原姓别为" + list.get(i).getSex() + "现姓别修改为:"); String s2 = read.nextLine(); s2 = read.nextLine(); list.get(i).setSex(s2);// 调用数组队列的第i个元素的setSex方法,把sex属性设置为s2 break; case 3: System.out.println("原语文成绩为" + list.get(i).getChinese() + "现语文修改为:"); double d1 = read.nextDouble(); list.get(i).setChinese(d1);// 调用数组队列的第i个元素的setChinese方法,把Chinese属性设置为d1 break; case 4: System.out.println("原数学成绩为" + list.get(i).getChinese() + "现数学修改为:"); double d2 = read.nextDouble(); list.get(i).setMath(d2);// 调用数组队列的第i个元素的setMath方法,把Math属性设置为d2 break; case 5: System.out.println("原英语成绩为" + list.get(i).getChinese() + "现英语修改为:"); double d3 = read.nextDouble(); list.get(i).setEnglish(d3);// 调用数组队列的第i个元素的setEnglish方法,把English属性设置为d3 break; } } } for (int j = 0; j < list.size(); j++) {// 输出list数组队列中的内容 System.out.println(list.get(j)); } // 查找学生信息 Scanner read1 = new Scanner(System.in);// 实例化Scanner int j = -1; System.out.println(" 查找学生信息"); System.out.println(); System.out.println("======================="); System.out.println(); System.out.println("请输入要查找的学生学号:"); int number2 = read.nextInt(); System.out.println(number2 + "学号的学生姓名为:" + list.get(number2).getName()); System.out.println(list.get(number2));// 输出所查找的学生的全部信息 } // 选择排序 public static void sort(MyArrayList<Student> list) { for (int i = 0; i < list.size(); i++) { int minIndex = i; // 找出最小的一个索引 for (int j = i + 1; j < list.size(); j++) { if (list.get(j).getAverage() < list.get(minIndex).getAverage()) {// 调用第i个元素的getAverage方法,与下标为minIndex的元素的Average比较,若前者小于后者 minIndex = j;//把minIndex的值改为j } } // 交换 Student temp = list.get(i); list.set(i, list.get(minIndex)); list.set(minIndex, temp); } } }
所使用的学生类如下:
package cn.lzj0724; public class Student { private String name;// 姓名 private String sex;// 性别 private int number;// 学号 private double chinese, math, english;// 科目 private double average;// 平均分 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public double getChinese() { return chinese; } public void setChinese(double chinese) { this.chinese = chinese; } public double getMath() { return math; } public void setMath(double math) { this.math = math; } public double getEnglish() { return english; } public void setEnglish(double english) { this.english = english; } public double getAverage() { return average; } public void setAverage(double average) { this.average = average; } public Student() { } public Student(String name, String sex, int number, double chinese, double math, double english) { this.name = name; this.sex = sex; this.number = number; this.chinese = chinese; this.math = math; this.english = english; average = (chinese + math + english) / 3; } // 控制输出格式 public String toString() { return name + " " + "性别:" + sex + " 学号:" + number + " " + "语文:" + chinese + " " + "数学:" + math + " " + "英语:" + english + "平均分" + average; } /** * 重写比较方法,然后进行比较时调用 * @param stu * @return */ public boolean equals(Student [] stu){ return false; } }
收获:
1.学会了泛型的使用
2.学会了编写和使用数组队列,为五子棋的悔棋的实现打下了基础
不足:
1.对泛型的理解还不够深刻透彻
2.未实现学生信息管理的图形界面
相关推荐
在实际开发中,理解和熟练运用Java集合框架和泛型能够大大提高代码的可维护性和安全性,减少类型转换的麻烦,并使得代码更易于理解和复用。通过以上讲解,相信你已经对这两个主题有了更深入的理解。通过练习和应用,...
这个练习和学习资料将帮助你深入理解Java数组的各个方面。 1. **数组定义与声明**: 在Java中,数组的定义通常包含类型和数组名,例如 `int[] numbers` 定义了一个整型数组。声明数组后,需要通过 `new` 关键字...
泛型是Java 5引入的一项创新特性,极大地增强了集合框架的安全性和效率。本讲解将深入探讨这两个主题,以及与之相关的枚举类型。 首先,Java集合框架包括List、Set、Queue等接口,以及ArrayList、LinkedList、...
这个实例185可能是进一步讨论泛型数组类如何应用于实际项目,例如作为缓存、队列或其他数据结构的基础,或者作为工具类帮助处理不同类型的数据集。标签中的"源码"表明可能有具体的代码实现供学习,而"工具"可能意味...
Java 泛型集合和Java集合框架是Java编程中不可或缺的部分,它们为开发者提供了高效的数据存储和操作机制。本文将深入探讨这两个主题,并着重讲解`Collection`接口及其在Java中的应用。 首先,Java泛型是一种在编译...
在这个Java队列实现的数据结构作业练习中,我们将会探讨如何使用Java来创建一个简单的队列,并分析`Queue.java`和`Node.java`这两个文件可能包含的内容。 首先,`Queue.java`很可能是实现队列接口或类的文件。在...
Java 1.5 引入了泛型(generics)这一强大的特性,旨在提升类型安全性,减少类型转换的烦恼,并优化代码的可读性。泛型允许我们在编程时指定容器(如列表、队列等)...理解和熟练运用泛型是现代Java开发中的必备技能。
总的来说,Java集合框架和泛型机制共同构建了一个强大而灵活的工具箱,使开发者能够高效地处理各种数据结构和对象。了解并熟练掌握这些概念对于编写高质量、易于维护的Java代码至关重要。在实际开发中,应根据具体...
在Java中,集合和泛型是两个重要的概念,集合用于存储和操作数据,而泛型用于确保类型安全。Java集合框架提供了多种类型的集合,例如Collection、Set、List、Queue、Map等,每种集合类型都有其特点和应用场景。 ...
2. 集合接口:Java集合框架的核心接口有List、Set和Queue,分别对应有序列表、无序不重复集合和先进先出的队列。 3. 实现类:ArrayList实现了List接口,基于动态数组实现,适合频繁的元素访问;LinkedList实现了List...
在Java编程中,泛型是一种强大的工具,它允许我们在编写代码时指定容器(如堆栈、队列等)可以容纳的数据类型,从而提高了代码的可读性和安全性。在这个例子中,我们将探讨如何使用泛型实现一个堆栈类——`...
集合框架与泛型是Java编程语言中的核心概念,它们极大地提高了代码的可读性、安全性和效率。在Java中,集合框架是一组接口和类,它们提供了存储和操作对象的统一方式。泛型则是Java 5引入的一个特性,用于在编译时...
本文将详细探讨如何在Java或C#等支持泛型的语言中,为JWList和JWArray类加入泛型支持,以实现更加灵活和强大的功能。 首先,我们来理解什么是泛型。泛型是现代编程语言中的一个特性,允许开发者在编写代码时定义可...
**集合框架与泛型**是Java编程语言中的核心特性,对于初学者来说,理解并熟练掌握这两个...结合提供的课件“第六章 集合框架与泛型.ppt”,初学者可以通过系统学习和实践,进一步提升对Java高级特性的理解和应用能力。
通过对泛型和集合的深入分析,我们不仅了解了它们的基本概念和用途,还掌握了如何有效地使用这些特性来构建健壮的应用程序。泛型提高了代码的灵活性和可维护性,而集合则为我们提供了丰富的数据管理工具。这些概念和...
这个类包含了一个泛型数组`arr`,用于存储队列中的元素,以及两个整型变量`front`和`rear`,分别表示队头和队尾的位置。`Sequeue`类作为顺序队列的实现,其构造函数初始化了队列的容量和前后指针,并提供了上述的...
在Java编程语言中,集合类泛型是编程实践中不可或缺的一部分,尤其对于初学者而言,理解并熟练运用它们至关重要。...在Java的学习旅程中,集合类泛型无疑是一个重要的里程碑,值得你投入时间和精力去理解和掌握。
在Java中,可以使用数组或链表来实现栈和队列。数组实现简单但大小固定,而链表实现则允许动态扩展。循环队列是队列的一种优化,它通过循环数组来避免数组满时的扩容问题,提高了效率。 在实际应用中,栈常用于...
队列(Queues)用于先进先出(FIFO)的数据管理,fastutil提供了数组队列(ArrayQueues)和链接队列(LinkedQueues),可用于线程安全和非线程安全的场景。 除了上述数据结构,fastutil还包括堆(Heaps)和双端队列...