Поведение Java Integer Wrapper [дубликат]

Статические методы не могут подвергаться полиморфному поведению. Это не имеет большого смысла. Создайте этот вариант использования, предположив, что вы хотите:

public void foo(MyInterface i) {
    i.getInstance("abc");
}

теперь я хочу вызвать этот метод с реализацией MyInterface (класс A), но поскольку я не могу передать класс, мне нужно передать объект:

A a = new A();
foo(a);

теперь внутри foo переопределение static getInstance вызывается в экземпляре класса A. Итак, теперь я застрял в создании объекта, чтобы вызвать статический метод.

Я хочу сказать, что вы все равно должны были бы создать объект в большинстве случаев полиморфизма, поскольку в вашем исходном интерфейсе метод был метод экземпляра.

167
задан shmosel 1 September 2017 в 18:00
поделиться

8 ответов

== все равно проверит равномерность объекта. Однако легко обмануть:

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

Ваши примеры с неравенствами будут работать, поскольку они не определены в объектах. Однако при сравнении == все равно будет проверяться равенство. В этом случае, когда вы инициализируете объекты из примитива в штучной упаковке, используется тот же объект (для a и b). Это хорошая оптимизация, поскольку примитивные классы ящиков неизменяемы.

38
ответ дан Adam Lewis 15 August 2018 в 17:45
поделиться
  • 1
    Я полагал, что проверялось равенство объектов. У меня были некоторые странные результаты. Должен ли я заменить его на .equals ()? Кроме того, чувствуете ли вы, что я должен оставить неравенство так, как есть, или сделать это по-другому? – user 3 October 2009 в 22:42
  • 2
    Есть некоторые неочевидные граничные случаи с автобоксированием. У меня есть IDE (Eclipse), чтобы покрасить все, что было в коробке красным цветом, это несколько раз избавило меня от ошибок. Если вы сравниваете два целых числа, используйте .equals, если вы хотите, чтобы ваши неравенства были ясными, напишите в листинге явно: if ((int) c & lt; (int) d) ...; Вы также можете сделать: c.compareTo (d) & lt; 0 // === c & lt; d – Adam Lewis 3 October 2009 в 23:40
  • 3
    И если вы измените числовые литералы на 200, оба теста будут печатать false. – Daniel Earwicker 4 October 2009 в 00:11
  • 4
    ... на большинстве реализаций JVM, то есть. В соответствии с спецификацией языка результат может варьироваться в зависимости от реализации. – Daniel Earwicker 4 October 2009 в 00:12
  • 5
    Я думаю, что более понятно назвать это «ссылочное равенство». - Таким образом, очевидно, что вы имеете в виду. Обычно я понимаю «равенство объектов». для обозначения "результата equals, называемого". – Jon Skeet 4 October 2009 в 08:03

этот метод сравнивает два целых числа с нулевой проверкой, см. тесты

public static boolean compare(Integer int1, Integer int2) {
    if(int1!=null) {
        return int1.equals(int2);
    } else {
        return int2==null;
    }
    //inline version:
    //return (int1!=null) ? int1.equals(int2) : int2==null;
}

//results:
System.out.println(compare(1,1));           //true
System.out.println(compare(0,1));           //false
System.out.println(compare(1,0));           //false
System.out.println(compare(null,0));        //false
System.out.println(compare(0,null));        //false
System.out.println(compare(null,null));     //true
-1
ответ дан Alex Torson 15 August 2018 в 17:45
поделиться
  • 1
    добавьте некоторое объяснение в свой ответ. – RamPrakash 2 March 2017 в 13:37
  • 2
    Для этого, я думаю, было бы лучше использовать метод Objects.equals(x,y) вместо того, чтобы кататься самостоятельно. – ryvantage 8 June 2017 в 04:04

Нет, == между Integer, Long и т. д. будет проверяться на ссылочное равенство - то есть

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

, это будет проверять, относятся ли x и y к тот же объект , а не , равный объектам.

Таким образом,

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

гарантированно печатает false. Интерполяция «малых» значений автобокса может привести к сложным результатам:

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

Это будет печатать true из-за правил бокса ( JLS раздел 5.1.7 ) , По-прежнему используется ссылочное равенство, но ссылки действительно равны .

Лично я бы использовал:

if (x.intValue() == y.intValue())

или

if (x.equals(y))

Последнее немного менее эффективно - нет перегрузки для Integer.equals(Integer), поэтому ему придется выполнять проверку типа времени выполнения, тогда как первый использует тот факт, что мы уже знаем, что оба объекта Integer s.

К счастью, compareTo знает о типах, поэтому:

if (x.compareTo(y) < 0)

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

Как вы говорите, для любого сравнения между типом оболочки (Integer, Long и числовой тип (int, long и т. д.) значение типа оболочки - unboxed , и тест применяется к примитивным значениям.

происходит как часть двоичной цифровой рекламы ( JLS раздел 5.6.2 ). Посмотрите документацию каждого отдельного оператора, чтобы узнать, применяется ли она. Например, из документов для == и! = ( JLS 15.21.1 ):

Если операнды оператора равенства являются как числовыми, так и один из них имеет числовой тип, а другой является конвертируемым (п. 5.1.8) в числовой тип, двоичная цифровая продвижение выполняется в операндах (§5.6.2).

и для & lt; , & lt; =,> and> = ( JLS 15.20.1 )

Тип каждого из операндов оператора цифрового сравнения должен быть типом, который является (§5.1.8) к примитивному числовому типу, или возникает ошибка времени компиляции. Бинарное числовое продвижение выполняется в операндах (§5.6.2). Если продвинутый тип операндов является int или long, выполняется сопоставление целого числа со знаком; если этот продвинутый тип является float или double, выполняется сравнение с плавающей запятой.

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

232
ответ дан assylias 15 August 2018 в 17:45
поделиться
  • 1
    Есть ли причина, по которой вы хотели бы написать x.compareTo(y) < 0 вместо x < y? – Max Nanasy 29 August 2015 в 01:06
  • 2
    @MaxNanasy: Не то, о чем я могу сразу подумать. – Jon Skeet 29 August 2015 в 08:14
  • 3
    Начиная с Java 1.6.27+, существует перегрузка на равных в классе Integer, поэтому она должна быть такой же эффективной, как вызов .intValue (). Он сравнивает значения как примитивные int. – otterslide 22 September 2016 в 17:44
  • 4
    Как сказал @otterslide, это не обязательно в Java 8. Сравнение Integer с Integer по умолчанию по умолчанию. – Axel Prieto 21 July 2018 в 11:12
  • 5
    @Axel: добавление перегрузки не изменило бы поведение оператора ==, хотя, не так ли? Я сейчас не в состоянии проверить, но я был бы очень удивлен, если бы это изменилось. – Jon Skeet 21 July 2018 в 14:51

== проверяет ссылочное равенство, однако при написании кода типа:

Integer a = 1;
Integer b = 1;

Java достаточно умен, чтобы повторно использовать неизменное значение для a и b, поэтому это верно: a == b. Любопытно, что я написал небольшой пример, показывающий, где java останавливает оптимизацию таким образом:

public class BoxingLol {
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Integer a = i;
            Integer b = i;
            if (a != b) {
                System.out.println("Done: " + i);
                System.exit(0);
            }
        }
        System.out.println("Done, all values equal");
    }
}

Когда я компилирую и запускаю это (на моей машине), я получаю:

Done: 128
9
ответ дан Cory Kendall 15 August 2018 в 17:45
поделиться
  • 1
    tl; dr -1 для ручной работы; stackoverflow.com/questions/15052216/… stackoverflow.com/questions/20897020/… stackoverflow.com/questions/3131136/integers-caching-in -java и т. д. подробно объясняют вопрос, который вы упомянули; лучше читать документы (или источник lib), чем создавать псевдо-тесты с риском высокой локальности результатов - вы не только полностью забыли о нижней границе кеша (т. е. -128 по умолчанию), а не только у вас есть один за другим (максимум 127, а не 128), – vaxquis 22 December 2015 в 01:08
  • 2
    но у вас нет гарантии получить тот же результат на любом компьютере, так как вы можете легко увеличить размер кеша, YMMV. Кроме того, вопрос OP состоял в том, что правильно сравнить два целых числа - вы вообще не ответили на него . – vaxquis 22 December 2015 в 01:08
  • 3
    Я уважаю ваше мнение и восприятие здесь. Я думаю, что у нас есть принципиально разные подходы к CS. – Cory Kendall 22 December 2015 в 04:06
  • 4
    это не о мнению и восприятии - речь идет о фактах , которые вы искренне пропустили. Выполнение псевдо-теста, ничего не доказывающего, без каких-либо жестких данных резервного копирования (docs, source и т. Д.) И без ответа на вопросы OP не заслуживает того, чтобы называться ни хорошим Q & amp; A, ни CS. Что касается «разного подхода», - CS по определению является science ; что вы сделали наука не ; это вводящие в заблуждение мелочи (или это будет интригующий комментарий , если указано правильно) - если вы хотите, чтобы это была science , исправьте фундаментальный недостатки в вашем ответе или развенчать их разумно , так как это работает peer review . – vaxquis 22 December 2015 в 16:02
  • 5
    Конечно, я попытаюсь устранить недостатки. Я не забыл о нижней границе, я не чувствовал, что это интересно, и решил не включать его. Я не верю, что у меня одна ошибка, я заявил, что это java (который я выяснил на своей машине, в моей ситуации) остановился , оптимизировав это, это было 128. Если я высказал максимальное значение, которое он сделал для этого, чем вы правы, ответ был бы 127. – Cory Kendall 23 December 2015 в 23:29

Начиная с Java 1.7 вы можете использовать Objects.equals :

java.util.Objects.equals(oneInteger, anotherInteger);

Возвращает true, если аргументы равны друг другу и false в противном случае. Следовательно, если оба аргумента равны null, возвращается true, и если только один аргумент имеет значение null, возвращается false. В противном случае равенство определяется с помощью метода equals первого аргумента.

7
ответ дан Justas 15 August 2018 в 17:45
поделиться

Вызов

if (a == b)

Будет работать большую часть времени, но он не всегда будет работать, поэтому не используйте его.

Самый правильный способ сравнения двух целых чисел классы для равенства, считая, что они называются 'a' и 'b', должны вызывать:

if(a != null && a.equals(b)) {
  System.out.println("They are equal");
}

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

   if(a != null && b != null && (a.intValue() == b.intValue())) {
      System.out.println("They are equal");
    } 

На моей машине 99 миллиардов операций заняли 47 секунд, используя первый метод, и 46 секунд, используя второй метод. Вам нужно будет сравнить миллиарды значений, чтобы увидеть разницу.

Обратите внимание, что «a» может быть пустым, поскольку это объект. Сравнение таким образом не приведет к исключению нулевого указателя.

Для сравнения большего и меньшего, используйте

if (a != null && b!=null) {
    int compareValue = a.compareTo(b);
    if (compareValue > 0) {
        System.out.println("a is greater than b");
    } else if (compareValue < 0) {
        System.out.println("b is greater than a");
    } else {
            System.out.println("a and b are equal");
    }
} else {
    System.out.println("a or b is null, cannot compare");
}
7
ответ дан otterslide 15 August 2018 в 17:45
поделиться
  • 1
    if (a==b) работает только для небольших значений и не будет работать большую часть времени. – Tony 30 August 2017 в 15:04
  • 2
    Он работает до 127, поскольку это кеш-память Integer Java по умолчанию, которая гарантирует, что все номера до 127 имеют одинаковое ссылочное значение. Вы можете настроить кеш выше 127, если хотите, но просто не используйте == для обеспечения безопасности. – otterslide 31 August 2017 в 15:53

tl; dr Мое мнение состоит в том, чтобы использовать унарный +, чтобы вызвать unboxing на одном из операндов при проверке равенства значений и просто использовать математические операторы в противном случае. Обоснование следует:

Уже упоминалось, что сравнение == для Integer - сравнение идентичности, которое обычно не то, что хочет программист, и что целью является сравнение значений; Тем не менее, я сделал немного science о том, как сделать это сравнение наиболее эффективно, как с точки зрения компактности, правильности и скорости кода.

Я использовал обычную кучу методов :

public boolean method1() {
    Integer i1 = 7, i2 = 5;
    return i1.equals( i2 );
}

public boolean method2() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2.intValue();
}

public boolean method3() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2;
}

public boolean method4() {
    Integer i1 = 7, i2 = 5;
    return i1 == +i2;
}

public boolean method5() { // obviously not what we want..
    Integer i1 = 7, i2 = 5;
    return i1 == i2;
}

и получил этот код после компиляции и декомпиляции:

public boolean method1() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    return var1.equals( var2 );
}

public boolean method2() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method3() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method4() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method5() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2 == var1 ) {
        return true;
    } else {
        return false;
    }
}

Как вы можете легко видеть, метод 1 вызывает Integer.equals() (очевидно), методы 2-4 приведут к точно к тому же коду , разворачивая значения с помощью .intValue(), а затем сравнивая их напрямую, а метод 5 просто запускает сравнение идентичности, являясь неправильным способом сравнения значений.

Поскольку (как уже упоминалось, например, JS) equals() несет накладные расходы (он должен делать instanceof и неконтролируемый отбор), методы 2-4 будут работать с точно такой же скоростью, заметно лучше, чем метод 1, когда используется в жестких петлях, поскольку HotSpot вряд ли оптимизирует отливки & amp; instanceof.

Это очень похоже на другие операторы сравнения (например, < / >) - они вызовут unboxing, в то время как использование compareTo() не будет - но на этот раз операция очень оптимизирован HS, поскольку intValue() - всего лишь метод getter (главный кандидат на оптимизацию).

На мой взгляд, редко используемая версия 4 является наиболее кратким способом - каждый опытный разработчик C / Java знает, что унарный плюс в большинстве случаев равен касту на int / .intValue() - в то время как для некоторых (немного) WTF момент для некоторых (в основном тех, кто не использовал унарный плюс в своей жизни ), он, возможно, показывает намерение наиболее четко и наиболее кратко - он показывает, что мы хотим значение int одного из операндов, заставляя другое значение также распаковываться. Также неоспоримо наиболее похож на обычном i1 == i2 сравнение используется для примитивных int значений

Мой голос идет на i1 == +i2 и усилитель. i1 > i2 для объектов Integer, как для производительности, так и для причинам согласованности. Он также переносит код в примитивы, не изменяя ничего, кроме объявления типа. Использование названных методов похоже на введение семантического шума для меня, похоже на сильно критикуемый стиль bigInt.add(10).multiply(-3).

6
ответ дан vaxquis 15 August 2018 в 17:45
поделиться
  • 1
    Можете ли вы объяснить, что означает «+» в методе 4? Я попытался это сделать, но я получил нормальные обычаи этого символа (добавление, конкатенация). – Alex Li 13 July 2018 в 19:39
  • 2
    @AlexLi означает то, что я написал - unary + (унарный плюс), см., Например, [Д0] stackoverflow.com/questions/2624410/… – vaxquis 13 July 2018 в 21:56
0
ответ дан JackHammer 29 October 2018 в 00:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: