Search code examples
javaarraysequalslanguage-design

Why is the .equals() method not overriden for arrays of primitives in Java?


I am currently working on a project where I want to implement a login mechanism using a username and a password that gets compared against a database.

I had something like this in mind:

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

when I noticed that my unit tests were failing. So I took a deeper look at it an noticed that the Object::equals method is not overriden for arrays of primitives which explained why List::contains would always evaluate to false.

I know there is a possible workaround using:

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

My question is why the designer chose to keep the 'default implementation' of Object::equals? Wouldn't it be way more convenient than implementing a framework with static utility methods like Arrays.equals(array1,array2)?


Solution

  • Any Collections of arrays is mostly bad design. They should not be used together. You're probably better of by introducing a trivial, but needed 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
         }
    }
    

    And then having a List<Password>. (I also shortened your verifyUser method because it seemed a bit redundant):

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

    (Your other question regarding the why it is not overriden is mostly off-topic, because only the java-devs could really answer that.)