При создании контейнеров почему использование Java Generics лучше, чем использование класса объектов? (Java Generics & DataStructures) - PullRequest
0 голосов
/ 13 октября 2019

Пожалуйста. Перед тем, как понизить голос, прочитайте весь вопрос и убедитесь, что я это заслужил. Если вы все еще чувствуете необходимость отказаться, проголосуйте за меня;может быть, вы можете сказать мне, чтобы вместо этого преобразовать его в вики сообщества.

РЕДАКТИРОВАТЬ / НАПОМИНАНИЕ / TODO : быстрый ответ -> google java "безопасность типов" или "проверка типов"

Итак, я просматривал свои структуры данных и натолкнулся на интересную мысль, касающуюся Generics Java и класса объектов . Я реализовал и запустил «универсальный пакет» двумя различными способами (обратите внимание: IObjectBag.java, ObjectBag.java, IGenericBag.java и GenericBag.java) и использовал их оба (Примечание: ниже main.java и Output) . Я удалил часть ненужного кода в соответствии с правилами переполнения стека, но если вы хотите полную реализацию, дайте мне знать =).

Кроме того, я исследовал эту тему на многих веб-сайтах, в книгах и курсах в дополнение к просмотруисходный код ArrayList Здесь , и я понимаю, что мой GenericBag является лучшим вариантом, чем мой ObjectBag , но не достаточно хорошо, чтобы объяснитьэто на практике во время интервью. И я запутался, что мой GenericBag использует больше операций приведения, чем мой ObjectBag в своей реализации (см. Remove и PrintBag) .

1) Так что, кроме синтаксического сахара, почему мой GenericBag лучше? Пожалуйста, используйте мои классы и main.js в качестве примеров.

2) Существуют ли какие-либо важные различия во времени выполнения / накладных расходах / пространстве / времени, которые я не замечаю?

3) Как бы вы ответили на этот вопрос или ожидали, что на него ответят в интервью?

Бонусные вопросы: Если вы хотите, пожалуйста, ответьте на бонусные вопросы в главномКомментарии .java & GenericBag.java (я думаю, что могу ответить на них сам, просто хочу услышать ваше мнение)


IObjectBag.java

public interface IObjectBag {
    void add(Object item);
    Object remove(Object item) throws NoSuchElementException;
    boolean isEmpty();
    int find(Object item);
    Object get(int index);
    int numItems();
}

ObjectBag.java

public class ObjectBag implements IObjectBag {
    private Object [] items; // the java class attribute that will hold out "ints"
    private int numItems;

    public static void printBag(IObjectBag bag) {
        for(int i = 0; i < bag.numItems(); i++) {
            System.out.println(bag.get(i));
        }
    }

    public ObjectBag(int size) {
        this.items = new Object[size]; // fills array with null values
        this.numItems = 0;
    }

    public void add(Object item){
        // adds item to end of bag
    }

    public Object remove(Object item) {
        int index = this.find(item);

        if(index == -1) throw new NoSuchElementException("oops nothing found");

        Object out = this.items[index];

        this.items[index] = null;
        this.numItems -= 1;

        if(index + 1 != this.items.length && this.items[index + 1] != null) {  
            for(int i = index; i < this.items.length; i++) {
                if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
            }

            this.items[this.items.length - 1] = null;
        }

        return out;
    }

    public int find(Object item) {
        // return index given item or -1 
    }

    public Object get(int index) {
        // returns item given index
    }

}


IGenericBag.java

public interface IGenericBag <T> {
    void add(T item);
    T remove(T item) throws NoSuchElementException;
    boolean isEmpty();
    int find(T item);
    T get(int index);
}


GenericBag.java

public class GenericBag<T> implements IGenericBag<T> {
    // private T[] items; can't use this b/c see comment in constructor
    private Object[] items;
    private int numItems;

    public static void printBag(GenericBag bag) {
        for(int i = 0; i < bag.numItems(); i++) {
            System.out.println(bag.get(i));
        }
    }

    public GenericBag(int size) {
        // this.items = new T[size]; Bonus: throws generic array creation error (why?)
        this.items = new Object[size];
        this.numItems = 0;
    }

    public void add(T item){
        this.items[this.numItems] = item;
        this.numItems += 1;
    }

    public T remove(T item) {
        int index = this.find(item);

        if(index == -1) throw new NoSuchElementException("oops nothing found");

        T out = (T) this.items[index];

        this.items[index] = null;
        this.numItems -= 1;

        if(index + 1 != this.items.length && this.items[index + 1] != null) {  
            for(int i = index; i < this.items.length; i++) {
                if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
            }

            this.items[this.items.length - 1] = null;
        }

        return out;
    }

    public int find(Object item) {
        // given object return index or throw exception
    }

    public T get(int index) {
        return (T) this.items[index];
    }

}

main.java

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        System.out.println("Wazzaaaaaaap StackOverFlow!");
        Object int1 = new Integer(1);
        Object int2 = new Integer(2);
        Object int3 = new Integer(3);


        /* using my object bag ************************************************/
        System.out.println("using my object bag");
        IObjectBag myObjectBag = new ObjectBag(3);

        myObjectBag.add(int1);
        myObjectBag.add(int2);
        myObjectBag.add(int3);
        myObjectBag.remove(int2);

        ObjectBag.printBag(myObjectBag);

        /* using my generic bag ***********************************************/
        System.out.println("using generic bag");


        // Bonus Question: using object like above causes error at add method (why?)
        Integer int4 = new Integer(4); 
        Integer int5 = new Integer(5);
        Integer int6 = new Integer(6);

        GenericBag<Integer> myGenericBag = new GenericBag<Integer>(3); 
        //Bonus Question: using Interface decllaration like above causes error in print bag (why?) 

        myGenericBag.add(int4);
        myGenericBag.add(int5);
        myGenericBag.add(int6);
        myGenericBag.remove(int4);

        GenericBag.printBag(myGenericBag);
    }

}

Вывод:

Wazzaaaaaaap StackOverFlow!
using my object bag
1
3
using generic bag
5
6

WOW спасибо за то, что вы действительно прочитали это далеко

Ответы [ 2 ]

1 голос
/ 13 октября 2019

Причина использования, скажем, GenericBag<String> сверх ObjectBag, по сути, та же, что и при использовании String (или любого другого типа) над Object:

Тип безопасности.

Вы заявляете, что какой-то метод возвращает коллекцию Strings и ничего больше, тем самым не позволяя себе помещать туда другие объекты или пытаясь обработать то, что вы получаете из сумки, как некоторый другой тип. Это может звучать глупо, когда у вас есть 100 строк кода, но это может сэкономить вам много времени на отладку, когда вы работаете с приличной базой кода.

Хотя безопасность типов - это не серебряная пуля, это всего лишь инструмент,что некоторые люди находят полезным, а некоторые нет. Я почти уверен, что это популярная тема Holywar для любого форума по программированию.

Если вы чувствуете себя комфортно, работая без этой парадигмы (фон Javascript, верно?), Вы можете попробовать использовать какой-нибудь динамически типизированный язык, например Python, вместоJava.

1 голос
/ 13 октября 2019

Проблемы с вашим ObjectBag, которые 'автоматически' решаются с помощью безопасности типов , предлагаемой вашей реализацией GenericBag:

  • Доступ к записи возвращает Object, на этом этапе вы не делаетезнать, что такое тип Object.
  • Вы можете вставить любые типы объектов (смешанные), например, String и Integer, в один и тот же список, это антишаблон и вызывает нечитаемый код (попробуйте его с помощью Generics). bag!)
  • Поскольку ваш компилятор знает тип вашего GenericBag после того, как вы объявили его, на любом этапе вашего кода, если вы наводите курсор мыши на экземпляр genericBag, вы будете знать его тип, это делает ваш код более читабельным итакже расширяемый для других людей

Дженерики также предлагают намного больше, представьте, что вы хотите, чтобы ваш GenericBag принимал только числа, тогда вы можете написать его следующим образом:

public class GenericBag<T extends Number>

Мое предложение дляВы должны прочитать некоторые статьи об основах Java и особенно об универсальных, хороший способ обучения на практике - это хорошо,но есть много статей, которые могут дать вам очень хорошее теоретическое понимание этого вопроса.

https://www.baeldung.com/java-generics

...