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)。

  1. 向后兼容性:Java泛型是在Java 5中引入的,而Java已经有了很多版本和大量的代码库。使用类型擦除可以确保新代码能与旧代码库和旧版本的Java虚拟机(JVM)兼容。
  2. 运行时性能:由于类型信息在运行时被擦除,这意味着没有额外的运行时开销,因此不会影响程序的性能。
  3. 简化虚拟机设计:类型擦除意味着Java虚拟机(JVM)不需要进行大量的修改就可以支持泛型。
  4. 代码复用:类型擦除允许在运行时使用相同的代码来处理不同的类型,从而提高代码复用性。
  5. 类型安全:尽管类型信息在运行时被擦除,但在编译时,编译器会进行严格的类型检查,确保类型安全。

然而,类型擦除也有其局限性和缺点,例如无法在运行时获取泛型类型信息,以及某些复杂的泛型操作可能需要使用通配符或其他复杂的语法。
总体而言,类型擦除是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);
    }
}