一、泛型

import java.util.Comparator;

class MyArray<T> { // 泛型类语法

    Object[] arr = new Object[5];

    public void setArr(int pos, T val) {
        this.arr[pos] = val;
    }

    public T getArr(int pos) {
        return (T) arr[pos];
    }

}

class StringMyArray extends MyArray<String>{ // 继承时尖括号内需要填写
    @Override // 由于参数列表不相同,此类中 setArr 方法未覆盖父类,因此编译器会在 StringMyArray 类中生成桥接方法
    public void setArr(int pos, String val) {
        super.setArr(pos, val);
    }
}

class MyArray2<E extends Comparator<E>> {
    // 使用 extends 规定泛型的上届,即传入类型的边界
    // 例如,E必须实现的了 Comparator 接口
}

class util { // 泛型方法语法
    public static <T> void swap(T[] arr, int i, int j) { // 在返回类型前加上 <T>
        T tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

public class GenericClass {
    public static void main(String[] args) {

        MyArray<Integer> myArray = new MyArray<>(); // 泛型类的实例化
        myArray.setArr(1, 2);
        int ret = myArray.getArr(5);
        System.out.println(ret);

        util.swap(new Integer[]{1, 2, 3}, 1, 2); // 传入的必须为包装类型


    }
}
class Food {}

class Fruit extends Food{}

class Apple extends Fruit {}

class Banana extends Fruit {}

class Plate<T> { // 设置泛型

    private T data ;
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
}

class TestDemo { // 通配符上届,下届同理
    public static void main(String[] args) {
        Plate<Apple> plate = new Plate<>();
        plate.setData(new Apple());
        fun(plate); // 只能传入 Fruit 及其子类
        Plate<Banana> plate2 = new Plate<>();
        plate2.setData(new Banana());
        fun(plate2);
    }

    public static void fun(Plate<? extends Fruit> temp){
        // 此时⽆法在fun函数中对temp进⾏添加元素,因为temp接收的是Fruit和他的⼦类,此时存储的元素应该是哪个⼦类⽆法确定。所以添加会报错!
        // temp.setData(new Banana()); error
        // temp.setData(new Apple()); error
        System.out.println(temp.getData());
    }
}

二、反射

这里有一个学生类。通过反射可以在运行时检查,访问和修改类,接口,字段和方法的机制。

public class Student {

    private String name = "meat";
    private int age = 18;

    public Student() {
        System.out.println("Student()");
    }

    private Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("meat eat");
    }

    public void sleep() {
        System.out.println("meat sleep");
    }

    public void func(String str) {
        System.out.println(str);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

获取Class对象

通过Class.forName()

class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> stu1 = Class.forName("Student");
    }
}
  1. 使用"包名.类名"获取
  2. 返回值是Class<?>
  3. 需要抛出异常。
  4. 使用频率最多

通过类名.class

class Test {
    public static void main(String[] args) {
        Class<?> stu2 = Student.class;
    }
}

使用类对象的getClass方法

class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Class<?> stu3 = student.getClass();
    }
}

注意:需要先实例化对象,且无论获取了几次,这个Class对象只有一个。

通过Class对象实例化类

class Test {
    public static void main(String[] args) {
        Class<?> stu;
        try {
            stu = Class.forName("Student");
            Student student = (Student) stu.newInstance();
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 使用stu.newInstance()方法获取Student对象。
  2. 返回值是泛型,因此需要强制转换。
  3. 此时调用的是Student类不带参数的构造方法。
  4. 缺点:代码量大,效率不高。

获取对象的构造方法

class Test {
    public static void main(String[] args) {
        Class<?> stu;
        try {
            stu = Class.forName("Student");
            Constructor<?> constructor = stu.getDeclaredConstructor(String.class, int.class);
            constructor.setAccessible(true);
            Student student = (Student) constructor.newInstance("肉肉", 1);
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

1.通过类名.getDeclaredConstructor(可变参数)方法获取类的构造方法
2.在通过constructor实例化对象前,需要setAccessible()true

修改对象的字段

class Test {
    public static void main(String[] args) {
        Class<?> stu;
        try {
            stu = Class.forName("Student");
            Field field = stu.getDeclaredField("name");
            field.setAccessible(true);
            Student student = (Student) stu.newInstance();
            field.set(student, "肥肉肉"); // 1. 修改哪个对象 2. 修改成什么
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}

调用对象的方法

class Test {
    public static void main(String[] args) {
        Class<?> stu;
        try {
            stu = Class.forName("Student");
            Method method = stu.getDeclaredMethod("func", String.class);
            Student student = (Student) stu.newInstance();
            method.setAccessible(true);
            method.invoke(student, "吃肉肉");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

    }
}

三、枚举

所有的Enum都默认继承于Enum类。

public enum Color {
    RED, YELLOW, BLUE;
}

使用

public enum Color {
    RED, YELLOW, BLUE;

    public static void main(String[] args) {
        Color color = RED;
        switch (color) {
            case RED:
                System.out.println(RED);
                break;
            case BLUE:
                System.out.println(BLUE);
                break;
            case YELLOW:
                System.out.println(YELLOW);
                break;
            default:
                System.out.println("null");
                break;
        }
    }
}

常用方法

public enum Color {
    RED, YELLOW, BLUE;

    public static void main(String[] args) {
    
        Color[] colors = Color.values();
        for (int i = 0; i < colors.length; i++) {
            System.out.println(colors[i] + "-->" + colors[i].ordinal());
        }
        
        Color tmp = Color.valueOf("RED");
        System.out.println(tmp);
        
        System.out.println(RED.compareTo(YELLOW));
    }
}
  1. .values()以数组形式返回枚举所有成员
  2. .ordinal()获取枚举成员的索引位置
  3. .valueOf()将字符串转换为枚举实例
  4. compareTo()比较两个枚举成员下标

枚举

Enum的构造方法默认是私有的,但反射不能创造枚举实例。
下面代码运行会报错。

public enum Color{
    
    RED("红色", 1), YELLOW("黄色", 2), BLUE("蓝色", 3);

    private String name;
    private int key;

    Color(String name, int key) {
        this.name = name;
        this.key = key;
    }
    
}

class main {
    public static void main(String[] args) {
        Class<?> col;
        try {
            col = Class.forName("Color");
            Constructor<?> constructor = col.getDeclaredConstructor(String.class, int.class, String.class, int.class);
            constructor.setAccessible(true);
            Color color = (Color) constructor.newInstance("棕色", 4, "黑色", 4);
            System.out.println(color);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

四、lambda表达式

函数式接口

只有一个方法的接口叫做函数式接口,可以用@FunctionalInterface声明。

@FunctionalInterface
public interface Test {
    void test();
}

lambda表达式是匿名内部类的简化。实际上lambda表达式创建了一个类,实现接口,重写方法。

lambda表达式语法

lambda表达式基本语法:()-> {}

其中:

  1. ()内填写参数
  2. ->可以理解为被用于
  3. {}填写表达式或代码块

lambda表达式简写

  1. 传入的参数类型可以省略
  2. 如果需传入一个参数,则()可以省略
  3. 如果方法体只有一句代码,则{}可以省略
  4. 如果方法体只有一条return语句,那么{}return都可以省略

注意!lambda表达式简化的是重写方法的过程!

变量捕获

@FunctionalInterface
public interface lambda {
    void test();
}

public class Test {
    public static void main(String[] args) {
        int a = 100;
        lambda lambda = new lambda() {
            @Override
            public void test() {
                a = 10; // 报错
                System.out.println(a);
            }
        };
        lambda.test();
    }
}

打印元素

import java.util.ArrayList;
import java.util.function.Consumer;

public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("meat");
        list.add("OK!");
        /*list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/
        list.forEach(s -> System.out.println(s));
    }
}

排序元素

import java.util.ArrayList;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("meat");
        list.add("OK!");
        /*list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });*/
        list.sort(((o1, o2) -> o1.compareTo(o2)));
    }
}