Почему метод .equals () не переопределяется для массивов примитивов в Java? - PullRequest
0 голосов
/ 01 июня 2018

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

Я имел в виду нечто подобное:

public boolean verifyUser( String username, char[] password ) 
{
  List<char[]> dbpass = getPasswords( username );
  if ( dbpass.contains( password ) )
  {
    overwriteWithNonsense( password );
    return true;
  }
  overwriteWithNonsense( password );
  return false;
}

когда я заметил, что мои модульные тесты провалились.Поэтому я более глубоко взглянул на это и заметил, что метод Object::equals не переопределяется для массивов примитивов, что объясняет, почему List::contains будет всегда оценивать как false.

Iзнаю, что возможен обходной путь, используя:

if ( dbpass.stream().anyMatch( pw -> Arrays.equals( pw, password ) ) )
{
  overwriteWithNonsense( password );
  return true;
}

Мой вопрос: почему дизайнер решил оставить реализацию по умолчанию Object::equals?Разве это не было бы намного удобнее, чем реализация фреймворка с помощью статических утилит, таких как Arrays.equals(array1,array2)?

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

В Java array не является классом, но из Java Doc section 4.3.1 он рассматривается как объект.Теперь, когда это не класс, нет кода для equals/hashCode.

. Теперь для решения для сравнения массивов можно использовать метод Arrays.equals для сравнения двух массивов:

public boolean verifyUser( String username, char[] password ) 
{
    List<char[]> dbpass = getPasswords( username );
    for(char[] arr : dbpass)
    {
        if ( Arrays.equals(arr,password) )
        {
            overwriteWithNonsense( password );
            return true;
        }
    }

    overwriteWithNonsense( password );
    return false;
}
0 голосов
/ 01 июня 2018

Я не думаю, что есть веская причина.Вам обычно рекомендуется использовать ArrayList в качестве полноценного контейнера.Но, кажется, только хорошо иметь реализацию 10000 * согласно AbstractList.Всегда есть ==, чтобы определить, являются ли две ссылки одним и тем же объектом.

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

Являются ли эти массивы равными?

Integer objects[]={Integer.valueOf(1),Integer.valueOf(1000)};
int integers[]={1,1000}; 

Я бы сказал «нет» как наиболее последовательный.Но если нет, вы получите потенциально неожиданную семантику о том, что эти объекты не будут равны:

int ai[]={1,2,3}; 
long al[]={1,2,3};

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

0 голосов
/ 01 июня 2018

Любые Collection с array с - это в основном плохой дизайн.Они не должны использоваться вместе.Вы, вероятно, лучше, введя тривиальный, но нужно class:

public class Password{
     private final char[] password;

     public Password(char[] password){
         this.password = password;
     }

     @Override
     public boolean equals(Object obj){
         // equals logic
     }

     @Override
     public int hashCode(){
         // hashCode logic
     }
}

И затем иметь List<Password>.(Я также сократил ваш verifyUser метод, потому что он казался немного избыточным):

public boolean verifyUser( String username, char[] password ){
    List<Password> dbpass = getPasswords(username);
    boolean contained = dbpass.contains(new Password(password));
    overwriteWithNonsense(password);
    return contained;
}

(Ваш другой вопрос, касающийся , почему не переопределен, по большей части отключентема, потому что только java-разработчики могли ответить на этот вопрос.)

...