Осмелитесь ли вы использовать дженерики при создании колес? Вам достаточно это прочитать!

Java

Прочитайте эту статью, чтобы решить, какую проблему?

Решите проблему, заключающуюся в том, что многие Java-разработчики или разработчики Android не осмеливаются использовать дженерики, когда они обычно пишут какую-то инфраструктуру или создают какие-то колеса, и они не могут правильно использовать дженерики. Даже когда некоторые люди сообщают об ошибках при использовании дженериков, они будут использовать только метод, предложенный idea для изменения кода, но они не знают причины этого изменения, а также не знают, каковы будут последствия принудительного использования дженериков.

Какие проблемы решают дженерики?

Сначала определите общий список, который имитирует List. Давайте посмотрим, что эта нищенская версия списка может сделать для нас.

public class CustomList<T> {
    Object[] array = new Object[0];

    public T get(int index) {
        return (T) array[index];
    }

    public void add(T instance) {
        array[array.length - 1] = instance;
    }
}

посмотри как его использовать

 CustomList<String> customList = new CustomList<>();
        customList.add("hahahaha");
        String c = customList.get(0);

Вот, давайте посмотрим, каковы преимущества. Сначала взгляните на метод add.С дженериками нам не нужно беспокоиться об ошибках преобразования типов. Поскольку мы указываем универсальный тип при его определении, если мы передаем нестроковый тип при вызове метода добавления Тогда ide сообщит об ошибке, даже если вы не используете ide для записи в блокноте, вы получите ошибку при компиляции. Это преимущество статических языков. Многие ошибки говорят вам при компиляции, что вам не нужно быть таким болезненным, как js.

Затем снова взгляните на функцию get и подумайте: если универсального типа нет, полученное значение должно быть преобразовано в строку, прежде чем его можно будет присвоить c. Но теперь есть дженерики, так что вы можете получить их напрямую, и этот тип преобразования уже сделан за вас.

Подводя итог преимуществам дженериков:

  1. Избегайте ошибок во время выполнения, сообщите об этом во время компиляции
  2. Вам удобно пользоваться, опуская код принудительного преобразования типов

Почему дженерики не могут быть статическими?

Здесь вы можете подумать об этом, почему дженерики не могут быть определены статически? Как бы вы его ни меняли, вы не сможете нарушить это правило и не сможете его успешно скомпилировать.

Из предыдущего примера мы знаем, что дженерики в основном используются для инициализации каждого экземпляра. Обратите внимание, что для каждого экземпляра он определяется динамически,

Зависит от того, какие параметры передаются при его использовании, например List List List

Для статической переменной, если вы используете дженерики, это испортится. Например, в примере на нашем снимке экрана выше, что происходит, когда вы используете дженерики?

статические объекты? статические строки? статические входы учителя? Всех называют инами, так откуда мне знать, что это инсты

Какой тип должен быть? Статические переменные глобально уникальны. такДженерики никогда не могут быть изменены с помощью статики..

Это место нужно понять, чтобы понять, вам полезно понимать дженерики.

Неправильный способ написания дженериков

Это типичный неправильный способ написания, очевидно, что в интерфейсе присутствует дженерик-тип, и в результате дженерик-тип стирается в классе сущности.

Хотя его можно скомпилировать и передать, такой способ записи не имеет смысла.

Это правильный способ записи По сравнению с неправильным способом записи мы, очевидно, можем опустить приведение.

Сравнить эти два способа написания и два преимущества дженериков вы можете в начале статьи. Посмотрите внимательнее.

Как правильно расширять дженерики

Общие ограничения

interface IShop<T> {
    T buy(float price);
}


interface IPhoneShop2<T> extends IShop<T> {
    void repair(T phone);
}

Как мы уже говорили ранее, самым большим преимуществом дженериков является то, что они просты в использовании.Например, приведенный выше код очень прост в использовании, но из-за такого способа написания Слишком произвольно, поэтому добавьте слой ограничений. В приведенном выше коде мы, очевидно, являемся магазином мобильных телефонов, но когда мы действительно используем его, мы можем мимоходом передать его. Pass String pass Apple пропускает что угодно. Это противоречит первоначальному замыслу дизайнера.

Таким образом, дженерики также могут быть ограничены

interface Phone {

}

interface IPhoneShop2<T extends Phone> extends IShop<T> {
    void repair(T phone);
}

Таким образом, мы можем ограничить используемый тип, и это должен быть тип Phone. Учитывая, что java поддерживает несколько интерфейсов, но не поддерживает множественное наследование, ограничения на дженерики также следуют этому положению.

Путаница общих ограничений в списке

Давайте поговорим о месте в дженериках, которое многие люди не могут понять.

Определите фрукт, а затем съешьте яблоки и бананы.

interface TFruit {

}

class Apple2 implements TFruit {
}

class Banana2 implements TFruit {
}

Затем мы рассмотрим их использование

Почему красное место сообщает об ошибке? Это что-то, что многие люди не понимают? Наше название яблока является подклассом фруктов. Почему вы сообщаете об ошибке?

Подумайте об этом с другой стороны:

Таким образом, для общего типа списка его тип определяется динамически, и нет возможности определить его во время компиляции. Поэтому вам нужно убедиться, что дженерики по обе стороны от = абсолютно согласованы, чтобы объявить об успехе, иначе он потерпит неудачу.

Продолжай читать:

В этом примере на самом деле нетрудно понять, почему метод add не может быть скомпилирован.

Увидев это, я думаю, многие люди хотят попрощаться. . . У этого универсального типа tmd так много ограничений, как я могу его использовать? Нет, в будущем я сделаю свои собственные колеса, чтобы автоматически экранировать дженерики.

Все в порядке, просто потерпите, мы сделаем это снова.

// =左边: 代表 我想要一个水果  =右边 :我给你个苹果  逻辑没问题 编译通过
        TFruit fruit = new Apple2();
        // =左边: 代表 我想要一个水果的list 任意的水果 =右边 :我给你个任意水果的list 逻辑没问题 编译通过
        List<TFruit> tf1 = new ArrayList<TFruit>();
        //既然是个水果的list 那我 add 苹果香蕉 肯定没问题
        tf1.add(new Apple2());
        tf1.add(new Banana2());


        // =左边: 代表 我想要一个水果的list 任意的水果  =右边 :我给你一个苹果的list
        //这样编译肯定不通过,因为我想要的是水果的list 你却给我一个苹果的list 这样你让我就没办法玩了
        // 我想要水果 你只给我苹果 那香蕉 葡萄 西瓜 我就没办法要了,所以你肯定不行 编译不过
        List<TFruit> tf2 = new ArrayList<Apple2>();



        //=左边: 代表 我想要一个list,这个list 必须是一个水果的类型,且只能是一种水果的类型   =右边 :我给你一个苹果的list
        //符合要求 编译通过
        List<? extends TFruit> tf3 = new ArrayList<Apple2>();
        //我这个tf3 要求的是必须是一种水果的类型,但是我并不知道是那种类型,可能是水果 可能是葡萄 可能是香蕉
        // 所以你直接往我这塞一个确定好的水果  我肯定是不接受的,编译肯定失败
        tf3.add(new Apple2());
        tf3.add(new Banana2());

? extends кажется немного глупым?

Прочитав предыдущую статью, вы так думаете? extends немного туповат, на самом деле он очень полезен в определенных сценариях (ерунда, иначе почему java устроена именно так)

Еще выше фрукт, мы добавляем метод для возврата цены соответствующего фрукта

interface TFruit {
    int getPrice();
}

class Apple2 implements TFruit {
    @Override
    public int getPrice() {
        return 1;
    }
}

class Banana2 implements TFruit {
    @Override
    public int getPrice() {
        return 2;
    }
}

посмотреть, что пойдет не так

Глядя на параметры этой функции, параметры этой функции означают, что я хочу список, и в этот список можно поместить любой фрукт. Пока это фрукты,

Но когда мы звоним, мы даем ему список яблок и список бананов, а это не то, что он хочет, я хочу любые фрукты. Вы дали мне яблоки или бананы и указали мне конкретный сорт, что определенно неприемлемо.

Так на этот раз? выходит на сцену

После изменения компиляция сразу проходит успешно:

Напомним из предыдущего подраздела, это? расширяется не значитХочешь какие-нибудь фрукты?

Так как вы хотите любых фруктов, я дам вам яблоки или бананы, это определенно нормально.

Используете ли вы дженерики, закопанные в яму?

И выдает ошибку во время работы. Последствия более серьезные и их трудно обнаружить.

Конечно, банан нельзя превратить в яблоко.

Не делайте этого при написании кода.

? Что такое супер и как этим пользоваться.

изменить на

Хорошо, как вы понимаете это здесь?

Плюс? super означает то, что находится справа от знака равенства.Вам нужно только принять список яблок.