Почему не делает java.lang. Сопоставимая реализация числа? [дубликат]

Обратите внимание, что в C ++ «инициализация» (создание объекта определенным образом, например, std::string str = "hi";) и «присваивание» (изменение значения существующего объекта, например, str = "hi";) - это две разные вещи. [1116 ]

Когда вы пишете конструктор, такой как

Car::Car(double s)
{
     m_Speed = s;
}

, C ++ нуждается в объекте, и все его члены существуют, и поэтому уже инициализированы, к тому времени, как вы достигнете первого {. Оператор m_Speed = s; является присваиванием, а не инициализацией. Поскольку вы не указали, как следует инициализировать m_Speed, C ++ вставляет логику, чтобы «инициализировать по умолчанию» его перед началом тела конструктора (хотя для базового типа, такого как double, это просто означает, что он имеет неопределенное значение до назначения ).

Обычно это не имеет значения для члена типа double. Но это может быть для члена типа класса, и это определенно подходит для члена ссылочного типа: ссылка ДОЛЖНА быть инициализирована, потому что ссылка всегда должна ссылаться на некоторый объект, а присвоение, левая часть которого всегда является ссылочной переменной, всегда назначает этому указанному объекту; нет способа изменить объект, на который ссылается ссылка.

Способ указать, как конструктор инициализирует элементы, использует список инициализаторов элементов:

Car::Car(double s)
    : m_Speed(s)
{}

Race::Race(const Car& c, Track t)
    : m_Car(c), m_Track(t)
{
    m_Car.Show();
}

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

[Примечание 1: показанный выше конструктор Race по-прежнему не совсем работает из-за другой проблемы: вы не можете инициализировать ссылку Car& из const Car&. Вам нужно будет либо изменить конструктор, чтобы он принимал параметр не const, либо изменить член на тип const Car&. Не-const параметр также позволит избежать потенциальных проблем с привязкой к временному.]

[Примечание 2: Другой способ указать инициализатор для членов класса - это поставить = something; после объявления члена внутри учебный класс. Этот инициализатор по умолчанию будет использоваться, когда конструктор не указывает инициализатор для этого члена и в неявно определенном конструкторе по умолчанию, если таковой имеется. Это может быть удобно, если вы хотите, чтобы несколько конструкторов использовали один и тот же инициализатор.]

132
задан Joachim Sauer 27 April 2010 в 12:40
поделиться

10 ответов

Стоит упомянуть что следующее выражение:

new Long(10).equals(new Integer(10))

всегда false, который имеет тенденцию сбивать всех с толку в какой-то момент или другого. Так не только может Вы не выдерживать сравнение произвольный Number с, но и Вы не можете даже определить, равны ли они или нет.

кроме того, с реальными типами примитивов (float, double), определяя, равны ли два значения, хитро и должен быть сделан в приемлемом пределе погрешности. Попробуйте код как:

double d1 = 1.0d;
double d2 = 0.0d;
for (int i=0; i<10; i++) {
  d2 += 0.1d;
}
System.out.println(d2 - d1);

и Вас оставят с некоторой небольшой разницей.

Поэтому назад к проблеме создания Number Comparable. Как Вы реализовали бы его? Используя что-то как doubleValue() не сделал бы этого надежно. Помните Number, подтипы:

  • Byte;
  • Short;
  • Integer;
  • Long;
  • AtomicInteger;
  • AtomicLong;
  • Float;
  • Double;
  • BigInteger; и
  • BigDecimal.

Вы могли кодировать надежное compareTo() метод, который не опускается до серии если instanceof операторы? Number экземпляры только имеют шесть методов в наличии для них:

  • byteValue();
  • shortValue();
  • intValue();
  • longValue();
  • floatValue(); и
  • doubleValue().

, Таким образом, я предполагаю, что Sun принял (разумное) решение, что Number с были только [1 129] к экземплярам себя.

63
ответ дан 24 November 2019 в 00:12
поделиться

Для ответа посмотрите ошибку Java bugparade 4414323 . Можно также найти, что обсуждение от comp.lang.java.programmer

заключает в кавычки от ответа Sun до отчета об ошибках с 2001:

Все "числа" не сопоставимы; сопоставимый предполагает, что общее упорядочивание чисел возможно. Это даже не верно для чисел с плавающей запятой; NaN (не число) не является ни меньше, чем, больше, чем, ни равный никакому значению с плавающей точкой, даже самому. {Плавание, дважды} .compare налагают общее упорядочивание, отличающееся от упорядочивания "<" с плавающей точкой; и "=" операторы. Кроме того, как в настоящее время реализовано, подклассы Числа только сопоставимы с другими экземплярами того же класса. Существуют другие случаи, как комплексные числа, где никакое стандартное общее упорядочивание не существует, хотя можно было быть определен. Короче говоря, сопоставим ли подкласс Числа, должен быть оставлен как решение для того подкласса.

42
ответ дан 24 November 2019 в 00:12
поделиться

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

Вместо этого неатомарные подклассы Числа реализуют Сопоставимый самого.

Атомарные изменяемы, так не может реализовать атомарное сравнение.

3
ответ дан 24 November 2019 в 00:12
поделиться

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

4
ответ дан 24 November 2019 в 00:12
поделиться

нет никакого stardard сравнения для Чисел различных типов. Однако можно записать собственный Компаратор и использовать его для создания TreeMap< Число, Объект>, TreeSet< Число> или Collections.sort (List< Число>, Компаратор) или Arrays.sort (Число [], Компаратор);

1
ответ дан 24 November 2019 в 00:12
поделиться

Мое предположение - то, что, не реализовывая Сопоставимый, это дает больше гибкости классам с реализацией для реализации его или нет. Все общие числа (Целое число, Долго, дважды, и т.д.) действительно реализуют Сопоставимый. Можно все еще назвать Collections.sort, пока сами элементы реализуют Сопоставимый.

0
ответ дан 24 November 2019 в 00:12
поделиться

Рассмотрение иерархии классов. Классы обертки как Длинный, Целочисленное, и т.д., реализуют Сопоставимый, т.е. Целое число сопоставимо с целым числом, и длинное сопоставимо с длинным, но Вы не можете смешать их. По крайней мере, с этой парадигмой дженериков. То, которое я предполагаю, отвечает на Ваш вопрос 'почему'.

0
ответ дан 24 November 2019 в 00:12
поделиться

byte (примитивный) int (примитивны). Примитивы имеют только одно значение за один раз.
правила проектирования Языка позволяет это.

int i = 255

// down cast primitive
(byte) i == -1

А Byte не Integer. Byte Number, и Integer Number. Number объекты могут иметь больше чем одно значение одновременно.

Integer iObject = new Integer(255);
System.out.println(iObject.intValue());   // 255
System.out.println(iObject.byteValue());  // -1

, Если Byte Integer и Integer, Number, Какое значение Вы будете использовать в compareTo(Number number1, Number number2) метод?

0
ответ дан 24 November 2019 в 00:12
поделиться

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

NumberComparator numberComparator = new NumberComparator();
assertTrue(numberComparator.compare(12, 24) < 0);
assertTrue(numberComparator.compare((byte) 12, (long) 24) < 0);
assertTrue(numberComparator.compare((byte) 12, 24.0) < 0);
assertTrue(numberComparator.compare(25.0, 24.0) > 0);
assertTrue(numberComparator.compare((double) 25.0, (float) 24.0) > 0);
assertTrue(numberComparator.compare(new BigDecimal(25.0), (float) 24.0) > 0);
3
ответ дан 24 November 2019 в 00:12
поделиться

Напишите свой собственный компаратор

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class NumberComparator implements Comparator {
    @SuppressWarnings("unchecked")
    @Override
    public int compare(Number number1, Number number2) {
 if (((Object) number2).getClass().equals(((Object) number1).getClass())) {
     // both numbers are instances of the same type!
     if (number1 instanceof Comparable) {
  // and they implement the Comparable interface
  return ((Comparable) number1).compareTo(number2);
     }
 }
 // for all different Number types, let's check there double values
 if (number1.doubleValue() < number2.doubleValue())
     return -1;
 if (number1.doubleValue() > number2.doubleValue())
     return 1;
 return 0;
    }

    /**
     * DEMO: How to compare apples and oranges.
     */
    public static void main(String[] args) {
 ArrayList listToSort = new ArrayList();
 listToSort.add(new Long(10));
 listToSort.add(new Integer(1));
 listToSort.add(new Short((short) 14));
 listToSort.add(new Byte((byte) 10));
 listToSort.add(new Long(9));
 listToSort.add(new AtomicLong(2));
 listToSort.add(new Double(9.5));
 listToSort.add(new Double(9.0));
 listToSort.add(new Double(8.5));
 listToSort.add(new AtomicInteger(2));
 listToSort.add(new Long(11));
 listToSort.add(new Float(9));
 listToSort.add(new BigDecimal(3));
 listToSort.add(new BigInteger("12"));
 listToSort.add(new Long(8));
 System.out.println("unsorted: " + listToSort);
 Collections.sort(listToSort, new NumberComparator());
 System.out.println("sorted:   " + listToSort);
 System.out.print("Classes:  ");
 for (Number number : listToSort) {
     System.out.print(number.getClass().getSimpleName() + ", ");
 }
    }
}
1
ответ дан 24 November 2019 в 00:12
поделиться
Другие вопросы по тегам:

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