Java作业-1
使用泛型类型的优势是什么?
使用什么样的语法来声明一个使用原始类型的ArrayList引用变量,以及将一个原始类型的ArrayList对象赋值给该变量?
什么是非受限通配、受限通配、下限通配?
······
使用泛型类型的优势是什么?
泛型可以在编译时就发现错误
使用什么样的语法来声明一个使用原始类型的ArrayList引用变量,以及将一个原始类型的ArrayList对象赋值给该变量?
声明一个使用原始类型的ArrayList引用变量: ArrayList rawList;
将一个原始类型的ArrayList对象赋值给该变量: rawList = new ArrayList();
什么是非受限通配、受限通配、下限通配?
这三种通配类型可以对一个泛型类型指定范围。T为泛型类型
| 通配类型 | 形式 | 说明 |
|---|---|---|
| 非受限通配 | ? | 等同于? extends object |
| 受限通配 | ? extends T | 表示T或T的一个子类型 |
| 下限通配 | ? super T | 表示T或T的一个父类型 |
什么是消除?为什么使用消除来实现Java泛型?
“消除”(Erasure)是Java泛型(Generics)实现的一种机制。在Java中,泛型是一种允许在编译时进行类型检查的机制,但是在运行时,这些类型信息会被移除或“擦除”,这就是所谓的类型擦除(Type Erasure)。
- 向后兼容性:Java泛型是在Java 5中引入的,而Java已经有了很多版本和大量的代码库。使用类型擦除可以确保新代码能与旧代码库和旧版本的Java虚拟机(JVM)兼容。
- 运行时性能:由于类型信息在运行时被擦除,这意味着没有额外的运行时开销,因此不会影响程序的性能。
- 简化虚拟机设计:类型擦除意味着Java虚拟机(JVM)不需要进行大量的修改就可以支持泛型。
- 代码复用:类型擦除允许在运行时使用相同的代码来处理不同的类型,从而提高代码复用性。
- 类型安全:尽管类型信息在运行时被擦除,但在编译时,编译器会进行严格的类型检查,确保类型安全。
然而,类型擦除也有其局限性和缺点,例如无法在运行时获取泛型类型信息,以及某些复杂的泛型操作可能需要使用通配符或其他复杂的语法。
总体而言,类型擦除是Java为了平衡向后兼容性、性能和复杂性而采取的一种妥协方案。
修改GenericStack类,使用数组而不是ArrayList来实现他。应该在给栈添加新元素之前检查数组的大小。如果数组满了,就创建一个新数组。该数组是当前数组大小的两倍,然后将当前数组的元素复制到新数组中
public class GenericStack1<E> {
private Object[] list;
private int size = 0;
private static final int DEFAULT_CAPACITY = 10;
public GenericStack1() {
list = new Object[DEFAULT_CAPACITY];
}
public int getSize() {
return size;
}
@SuppressWarnings("unchecked")
public E peek() {
if (size == 0) {
return null; // 或抛出异常
}
return (E) list[size - 1];
}
@SuppressWarnings("unchecked")
public E pop() {
if (size == 0) {
return null;
}
E element = (E) list[--size];
list[size] = null;
return element;
}
public void push(E element) {
if (size == list.length) {
ensureCapacity();
}
list[size++] = element;
}
private void ensureCapacity() {
int newCapacity = list.length * 2;
Object[] newList = new Object[newCapacity];
System.arraycopy(list, 0, newList, 0, list.length);
list = newList;
}
}
(使用继承实现GenericStack)程序清单19-1中,GenericStack是使用组合实现的。定义一个新的继承自ArrayList的栈类。实现GenericStack。编写一个测试程序,提示用户输人5个字符串,然后以逆序显示它们
package code;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
import java.util.function.Consumer;
public class GenericStack2<E> extends ArrayList<E> {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
GenericStack2<String> stack = new GenericStack2<>();
int n = 5;
System.out.println("请输入5个字符串:");
for (int i = 0; i < n; i++) {
System.out.print("第" + (i + 1) + "个:");
stack.push(scanner.nextLine());
}
scanner.close();
stack.printAllRerseve();
System.out.println();
stack.forEach(element -> System.out.print(element));
System.out.println();
stack.Iterate(element -> System.out.print(element));
}
public void push(E element) {
add(element);
}
public E pop() {
if (isEmpty()) {
return null;
}
return remove(size() - 1);
}
public E peek() {
if (isEmpty()) {
return null;
}
return get(size() - 1);
}
public void printAllRerseve() {
for (int i = size() - 1; i >= 0; i--) {
System.out.print(get(i));
}
}
// 其实可以直接用ArrayList的isEmpty
public boolean isEmpty() {
return size() == 0;
}
public void forEach(Consumer<? super E> action) {
for (E element : this) {
action.accept(element);
}
}
public void Iterate(Consumer<? super E> action) {
Iterator<E> iterator = this.iterator();
while (iterator.hasNext()) {
action.accept(iterator.next());
}
}
}
(ArrayList中的不同元素)编写以下方法,返回一个新的ArrayList。新的列表中包含来自原列表中的不重复元素
public static <E>ArrayList<E> removeDuplicates(ArrayList<E> list)
package code;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.function.Consumer;
public class RemoveDuplicates {
public static void main(String[] args) {
int[] arrayPre = GenerateRandomArray.generateRandomArray(10, 4);
ArrayList<Integer> array = new ArrayList<>();
for (int item : arrayPre) {
array.add(item);
}
printAll(array);
ArrayList<Integer> uniqueArray = removeDuplicates(array);
System.out.println("手动:");
getAll(uniqueArray, element -> System.out.print(element + " "));
System.out.println("哈希:");
ArrayList<Integer> uniqueArray1 = removeDuplicatesUsingHashSet(array);
getAll(uniqueArray1, element -> System.out.print(element + " "));
}
// 手动去重
public static <E> ArrayList<E> removeDuplicates(ArrayList<E> list) {
Iterator<E> iterator = list.iterator();
ArrayList<E> uniqueList = new ArrayList<>();
if (iterator.hasNext()) {
uniqueList.add(iterator.next());
} else {
return uniqueList;
}
while (iterator.hasNext()) {
E element = iterator.next();
printAll(list);
for (int i = 0; i < uniqueList.size(); i++) {
if (element == uniqueList.get(i)) {
break;
} else if (i == uniqueList.size() - 1) {
uniqueList.add(element);
}
}
}
return uniqueList;
}
// 哈希去重
public static <E> ArrayList<E> removeDuplicatesUsingHashSet(ArrayList<E> list) {
LinkedHashSet<E> uniqueSet = new LinkedHashSet<>(list);
return new ArrayList<>(uniqueSet);
}
public static <E> void getAll(ArrayList<E> list, Consumer<? super E> action) {
for (E element : list) {
action.accept(element);
}
}
public static <E> void printAll(ArrayList<E> list) {
getAll(list, element -> System.out.print(element + " "));
System.out.println();
}
}
(二维数组中的最大元素)编写一个泛型方法,返回二维数组中的最大元素
public static <E extends Comparable<E>> E max(E[][] list) {
if (list == null || list.length == 0 || list[0].length == 0) {
return null;
}
E max = list[0][0];
for (E[] es : list) {
for (E es2 : es) {
if (es2 != null && (max == null || es2.compareTo(max) > 0)) {
max = es2;
}
}
}
return max;
}
(打乱ArrayList)编写以下方法,打乱ArrayList
package code;
import java.util.ArrayList;
import java.util.Random;
public class ArrayShuffle {
// Fisher-Yates洗牌算法,这个算法在原地打乱数组。每次随机交换两张牌
public static <E> void shuffle(ArrayList<E> list) {
Random random = new Random(); // 创建一个Random对象用于生成随机数
for (int i = list.size() - 1; i > 0; i--) {
// 生成一个随机索引,该索引位于[0, i]范围内
int randomIndex = random.nextInt(i + 1);
// 交换list[i]和list[randomIndex]的元素
E temp = list.get(i);
list.set(i, list.get(randomIndex));
list.set(randomIndex, temp);
}
}
public static void main(String[] args) {
// 创建一个包含整数的ArrayList
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
// 打印原始列表
System.out.println("Original list: " + list);
// 打乱列表
shuffle(list);
// 打印打乱后的列表
System.out.println("Shuffled list: " + list);
}
}