您好,当我想在不更改hashCode()方法的情况下拥有一个自定义HashSet时,有人可以为我指出正确的方向.用法是拥有一组必须具有不同的一个(或多个)属性的对象.

例如,对于这个类:

@FieldDefaults(level = AccessLevel.PRIVATE)
@Getter @Setter
public class User{
    String name;
    String email;
    String age;
}

我想有一个UserNameSet,它允许只包含具有不同名称的用户.我不想重写User中的hashCode和equals方法,因为我仍然想区分名称相同但邮箱不同的用户.

I would like to somehow override the hashCode() method just for this one HashMap.

EDITED

我第一眼就想到了这个解决方案,它很有效,有人能判断一下吗?

package com.znamenacek.debtor.util;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.experimental.FieldDefaults;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class CustomizableHashSet<T> implements Set<T> {
    Function<T, Integer> customHashCode = Object::hashCode;
    HashSet<ClassWrapper> storage = new HashSet<>();

    public CustomizableHashSet(Function<T, Integer> customHashCode) {
        this.customHashCode = customHashCode;
    }

    public CustomizableHashSet() {
    }


    public CustomizableHashSet(Collection<? extends T> c, Function<T, Integer> customHashCode) {
        storage = new HashSet<>(c.stream().map(ClassWrapper::new).toList());
        this.customHashCode = customHashCode;
    }
    public CustomizableHashSet(Collection<? extends T> c) {
        storage = new HashSet<>(c.stream().map(ClassWrapper::new).toList());
    }

    public CustomizableHashSet(int initialCapacity, float loadFactor, Function<T, Integer> customHashCode) {
        storage = new HashSet<>(initialCapacity, loadFactor);
        this.customHashCode = customHashCode;
    }

    public CustomizableHashSet(int initialCapacity, float loadFactor) {
        storage = new HashSet<>(initialCapacity, loadFactor);
    }


    public CustomizableHashSet(int initialCapacity, Function<T, Integer> customHashCode) {
        storage = new HashSet<>(initialCapacity);
        this.customHashCode = customHashCode;
    }

    public CustomizableHashSet(int initialCapacity) {
        storage = new HashSet<>(initialCapacity);
    }


    @Override
    public Iterator<T> iterator() {
        return storage.stream().map(ClassWrapper::get).iterator();
    }

    @Override
    public int size() {
        return storage.size();
    }

    @Override
    public boolean isEmpty() {
        return storage.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return storage.stream().map(ClassWrapper::get).collect(Collectors.toSet()).contains(o);
    }

    @Override
    public boolean add(T t) {
        return storage.add(new ClassWrapper(t));
    }

    @Override
    public boolean remove(Object o) {
        boolean returnValue;
        var storageContent = storage.stream().map(ClassWrapper::get).collect(Collectors.toSet());
        returnValue = storageContent.remove(o);
        storage = storageContent.stream().map(ClassWrapper::new).collect(Collectors.toCollection(HashSet::new));

        return returnValue;
    }

    @Override
    public void clear() {
        storage.clear();
    }

    @Override
    public Object clone() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Spliterator<T> spliterator() {
        return storage.stream().map(ClassWrapper::get).spliterator();
    }

    @Override
    public Object[] toArray() {
        return storage.stream().map(ClassWrapper::get).toArray();
    }

    @Override
    public <T1> T1[] toArray(T1[] a) {
        return storage.stream().map(ClassWrapper::get).collect(Collectors.toSet()).toArray(a);
    }



    @Override
    public boolean removeAll(Collection<?> c) {
        boolean returnValue;
        var storageContent = storage.stream().map(ClassWrapper::get).collect(Collectors.toSet());
        returnValue = storageContent.removeAll(c);
        storage = storageContent.stream().map(ClassWrapper::new).collect(Collectors.toCollection(HashSet::new));

        return returnValue;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        boolean returnValue;
        var storageContent = storage.stream().map(ClassWrapper::get).collect(Collectors.toSet());
        returnValue = storageContent.containsAll(c);
        storage = storageContent.stream().map(ClassWrapper::new).collect(Collectors.toCollection(HashSet::new));

        return returnValue;
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        return storage.addAll(c.stream().map(ClassWrapper::new).collect(Collectors.toSet()));
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean returnValue;
        var storageContent = storage.stream().map(ClassWrapper::get).collect(Collectors.toSet());
        returnValue = storageContent.retainAll(c);
        storage = storageContent.stream().map(ClassWrapper::new).collect(Collectors.toCollection(HashSet::new));

        return returnValue;
    }

    @Override
    public String toString() {
        return storage.stream().map(ClassWrapper::get).collect(Collectors.toSet()).toString();
    }

    @Override
    public <T1> T1[] toArray(IntFunction<T1[]> generator) {
        return storage.stream().map(ClassWrapper::get).collect(Collectors.toSet()).toArray(generator);
    }

    @Override
    public boolean removeIf(Predicate<? super T> filter) {
        boolean returnValue;
        var storageContent = storage.stream().map(ClassWrapper::get).collect(Collectors.toSet());
        returnValue = storageContent.removeIf(filter);
        storage = storageContent.stream().map(ClassWrapper::new).collect(Collectors.toCollection(HashSet::new));

        return returnValue;
    }

    @Override
    public Stream<T> stream() {
        return storage.stream().map(ClassWrapper::get);
    }

    @Override
    public Stream<T> parallelStream() {
        return storage.parallelStream().map(ClassWrapper::get);
    }

    @Override
    public void forEach(Consumer<? super T> action) {
        storage.stream().map(ClassWrapper::get).forEach(action);
    }

    @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
    @AllArgsConstructor
    public class ClassWrapper{
        T object;

        @Override
        public int hashCode() {
            return customHashCode.apply(object);
        }

        @Override
        public boolean equals(Object obj) {
            if(this == obj) return true;

            if(obj == null) return false;

            return hashCode() == obj.hashCode();
        }

        public T get(){
            return object;
        }

        @Override
        public String toString() {
            return "" + hashCode() + " - " + object.toString();
        }
    }




}

推荐答案

我想有一个UserNameSet,它允许只包含具有不同名称的用户

您可以应用组合并创建一个类来维护映射并将所有调用委托给它.

这种方法比扩展集合更灵活,也不太繁琐,而且不会产生紧密耦合.

class UserNameSet {
    private Map<String, User> userByName = new HashMap<>();
    
    public User add(User user) {
        return userByName.put(user.getName(), user);
    }
    
    public User remove(User user) {
        return userByName.remove(user.getName());
    }
    
    public User remove(String name) {
        return userByName.remove(name);
    }
    
    public boolean contain(String name) {
        return userByName.containsKey(name);
    }
    
    public boolean contain(User user) {
        return userByName.containsValue(user.getName());
    }
    
    // all other methods that are required
}

Java相关问答推荐

即使我正在使用并发方法,使用Javascript的应用程序也会继续冻结'

为什么一个java函数会返回一个作为参数传递给它的对象?

Java模式匹配记录

使用Testcontainers与OpenLiberty Server进行集成测试会抛出SocketException

在Spring Boot中使用哪个Java类来存储创建时间戳?

用OSQL创建索引

如何在antlr4中跳过所有反斜杠-换行符而保留换行符?

Domino Designer 14中的保存代理添加了重影库

继续收到错误SQLJDBC EXCEPTION执行";org.springframework.dao.InvalidDataAccessResourceUsageException:&

带有Health Check的Spring Boot BuildPack打破了本机映像构建过程

如何使用log4j2(Json)记录由";异常引起的所有";?

错误:未找到扩展元素在JBossEAP 7.2中安装FUSE时出错

使IntelliJ在导入时优先 Select 一个类或将另一个标记为错误

为什么没有加载java.se模块?

ResponseEntity.控制器截断响应的JSON部分

Eureka客户端无法使用用户/通行证注册到Eureka服务器

Spring Boot Security-每个端点都被403禁止,Spring记录一个BasicErrorController#错误(HttpServlet请求)

JavaFX中ListView中的问题

元音变音字符:如何在 Java 中将Á<0x9c>转换为Ü?

如何在 Spring Security 版本 6.x 和 Spring Boot 3.x 中允许 http 删除端点