Могу ли я кэшировать getClass.hashCode()?

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

@MappedSuperclass
abstract Some {

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

    @Override
    public int hashCode() {
        return getClass().hashCode(); // TODO: cache, maybe?
    }
}
  1. Могу ли я кэшировать значение getClass().hashCode()?
  2. Есть ли возможность изменения значения во время работы в JVM?
  3. Это какое-то дерьмо с преждевременной оптимизацией?

Не зная, для чего вам это нужно, это звучит как преждевременная оптимизация.

Syed Aqeel Ashiq 16.02.2023 05:54
Лучшая компания по разработке спортивных приложений
Лучшая компания по разработке спортивных приложений
Ищете лучшую компанию по разработке спортивных приложений? Этот список, несомненно, облегчит вашу работу!
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Если вы являетесь веб-разработчиком или тестировщиком, вы можете быть знакомы с Selenium, популярным инструментом для автоматизации работы...
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Что такое Java 8 Streams API? Java 8 Stream API
Деревья поиска (Алгоритм4 Заметки к учебнику)
Деревья поиска (Алгоритм4 Заметки к учебнику)
(1) Двоичные деревья поиска: среднее lgN, наихудшее N для вставки и поиска.
1
1
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
Могу ли я кэшировать значение getClass().hashCode()?

Можно, но...

Есть ли возможность изменения значения во время работы в JVM?

Нет возможности. Класс объекта Java не может измениться, и хэш-код объекта Java Class (который является типом результата для getClass()) не может измениться.

Это преждевременная оптимизация?

Наверное да1.

Однако использование хэш-кода класса объекта в качестве хэш-кода объекта — очень плохая идея с точки зрения производительности.

Это означает, что все экземпляры класса (например, Some) будут иметь один и тот же хэш-код 2. Это приведет к миллиону коллизий хешей и сделает большинство операций HashSet и HashMap O(N) или O(logN) (в зависимости от вашей версии Java), а не O(1).


1 - I am assuming you have not done a bunch of performance analysis that you haven't told us about. If you had already done the analysis, then maybe this is not a premature optimization. 2 - I am assuming that the Some::hashCode method is not overridden to something more sensible by concrete subclasses of Some.

Это хороший ответ. У меня есть одна путаница: может ли быть несколько экземпляров Class<Some>, если несколько загрузчиков классов загружают класс Some. Если да, то в этом случае getClass().hashcode() может возвращать разные значения.

Syed Aqeel Ashiq 17.02.2023 06:03

Я говорил о нескольких загрузчиках классов, загружающих класс Some. Потому что getClass().hashcode() учится в Some классе. Итак, если класс Some загружается несколькими загрузчиками классов, будет ли getClass().hashcode() возвращать разные значения для них обоих?

Syed Aqeel Ashiq 17.02.2023 06:22

А... я неправильно понял. Если несколько загрузчиков классов загружают Some, то это будут разные классы (с точки зрения системы типов Java), и они будут иметь разные объекты Class<Some> и их хэш-коды, вероятно, будут разными.

Stephen C 17.02.2023 06:27

Ответ Стивена С - хороший ответ. Однако для полноты я считаю необходимым добавить к этому, что если класс загружается, скажем, двумя разными загрузчиками классов, то для этого класса getClass().hashcode() вернет два разных значения.

Чтобы убедиться в этом, я написал программу и загрузил класс с помощью системного загрузчика классов, а затем с помощью своего собственного пользовательского загрузчика классов. Оба возвращают разные hashcode():

Сначала код для пользовательского загрузчика классов, который я скопировал с https://www.digitalocean.com/community/tutorials/java-classloader:

package com.journaldev.classloader;

import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * Our Custom ClassLoader to load the classes. Any class in the
 * com.journaldev package will be loaded using this ClassLoader.
 * For other classes, it will delegate the request to its Parent
 * ClassLoader.
 */
public class CCLoader extends ClassLoader {

  /**
   * This constructor is used to set the parent ClassLoader
   */
  public CCLoader(ClassLoader parent) {
    super(parent);
  }

  /**
   * Loads the class from the file system. The class file should be located in
   * the file system. The name should be relative to get the file location
   *
   * @param name Fully Classified name of the class, for example, com.journaldev.Foo
   */
  private Class getClass(String name) throws ClassNotFoundException {
    String file = name.replace('.', File.separatorChar) + ".class";
    byte[] b = null;
    try {
      // This loads the byte code data from the file
      b = loadClassFileData(file);
      // defineClass is inherited from the ClassLoader class
      // that converts byte array into a Class. defineClass is Final
      // so we cannot override it
      Class c = defineClass(name, b, 0, b.length);
      resolveClass(c);
      return c;
    } catch (IOException e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * Every request for a class passes through this method. If the class is in
   * com.journaldev package, we will use this classloader or else delegate the
   * request to parent classloader.
   *
   * @param name Full class name
   */
  @Override
  public Class loadClass(String name) throws ClassNotFoundException {
    if (name.startsWith("com.journaldev.")) {
      return getClass(name);
    }
    return super.loadClass(name);
  }

  /**
   * Reads the file (.class) into a byte array. The file should be
   * accessible as a resource and make sure that it's not in Classpath to avoid
   * any confusion.
   *
   * @param name Filename
   * @return Byte array read from the file
   * @throws IOException if an exception comes in reading the file
   */
  private byte[] loadClassFileData(String name) throws IOException {
    InputStream stream = getClass().getClassLoader().getResourceAsStream(
        name);
    int size = stream.available();
    byte buff[] = new byte[size];
    DataInputStream in = new DataInputStream(stream);
    in.readFully(buff);
    in.close();
    return buff;
  }
}

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

package com.journaldev.test;

import com.journaldev.classloader.CCLoader;

public class Test {

  public static void main(String[] args) throws Exception {
    System.out.println(new CCLoader(ClassLoader.getSystemClassLoader())
        .loadClass(Test.class.getCanonicalName()).hashCode());
    System.out.println(ClassLoader.getSystemClassLoader()
        .loadClass(Test.class.getCanonicalName()).hashCode());
  }
}

Вывод показывает разные хэш-коды для одного и того же класса, загруженного разными загрузчиками классов:

1554547125
1072591677

Другие вопросы по теме