Якщо мій IDE такий розумний, навіщо мені робити "clone ()"?


13

Мій тип IDE ( NetBeans ) перевіряє мій Collectionsпід час введення коду. Але тоді, чому я повинен кидати повернутий об'єкт Object.clone()? Що добре. Ні шкоди, ні фолу. Але все-таки я не розумію.

Чи неможлива перевірка типу без кастингу поверненого об'єкта Object.clone()? Дженерики структура змушує мене думати IDE може перевірити тип посилань на об'єкти на правій стороні « = марки» без лиття в той час як я друкую? Я не розумію.

Додаток
Мій випадок використання полягав у тому, що я мав приватне Calendarполе, публікувати . Я збирався написати:

Calendar getPubdate() {
    return pubdate;
}

але є ризик, що користувач може змінити моє оновлення , тому я повернув копію:

Calendar getPubdate() {
    return (Calendar) pubdate.clone();
}

Потім я задумався, навіщо мені потрібно грати pubdate.clone(). Підпис методу має тип саме там. NetBeans повинен мати можливість це зрозуміти. І NetBeans, здавалося, робить щось подібне стосовно Collections.


5
Короткий (!) Приклад коду був би корисним.
Док Браун

78
IDE відокремлений від самої мови, тому наскільки розумні Netbeans не впливають на те, як працює мова мови.
ЖакБ

7
Зауважте, через коваріацію типу повернення рекомендується повертатися MyObjectз, clone()а не Object- це видаляє всю цю проблему. Крім того, рекомендується ніколи не використовувати clone()(Ефективний елемент Java №11).
Борис Павук

Акцент вашого питання на I або на "литому" клоні () " ? Тому що питання, що виникає внаслідок першого, насправді може бути набагато кращим питанням, ніж від другого.
користувач541686

Коли я читаю заголовок питання, єдине, про що я думаю, - це this.clone()об’єкт програміста, особливо в ніч на ср після звільнення Тю. Вибачте, але я мушу написати цей коментар. Чому не може смарт-IDE виправити всі помилки для нас LOL
Май

Відповіді:


53

чому мені потрібно відкинути повернутий об’єкт Object.clone()?

Тому що вона повертається Object.

Дженерики структура змушує мене думати IDE може перевірити тип посилань на об'єкти на правій стороні « = марки» без лиття в той час як я друкую? Я не розумію.

Object.clone не є загальним.

Якби дженерики існували тоді, коли cloneбув розроблений, він, мабуть, виглядав би так (використовуючи F-Bounded Polymorphism):

interface Cloneable<T extends Cloneable<T>> {
  T clone();
}

Якби у Java була функція MyType, це, можливо, виглядатиме так:

interface Cloneable {
  this clone();
}

Але Generics не існувало тоді, коли Object.cloneбуло розроблено, і у Java немає MyTypes, тому над небезпечною для вас версією Object.cloneє те, з чим ми маємо працювати.


Я щойно зрозумів, що функція IDE, яка мене бентежила, - це складання фону? Я маю на увазі, саме це дозволяє завершити код і перевірити автоматичний тип за допомогою дженериків? Особисто я вважаю за краще затягувати перевірку типу до явної компіляції. Але я люблю доповнення коду.
konishiki

1
@konishiki з Java 8 (і певною мірою Java 7) виводу типу , щоб надати будь-яку допомогу, IDE потрібно зробити висновок про типи. Це вимагає часткового складання. Перед тим, як зробити висновок, для автоматичного завершення не потрібно проводити компіляцію.
Борис Павук

@BoristheSpider Дуже дякую за відгуки! Мені обов'язково потрібно зробити ще тестування / мислення. дуже цінується.
konishiki

Навіщо тобі потрібно проїхати original?
Clashsoft

@Clashsoft: Дурний тонкий під час адаптації очевидної версії функціонального програмування. Спасибі.
Йорг W Міттаг

26

Це не особливість жодної IDE, а визначення мови.

IDE допомагає ефективніше використовувати мову програмування, вона не змінює семантику цієї мови. Це означає, що помічник редактора може автоматично вставити кастинг, коли очевидно, який саме ви хочете, але він не може просто порушити правила мови та зробити вигляд, що код, який не компілюється, є дійсним.

Редагування Це правда, що IDE може поєднати власний компілятор, і насправді багато хто робить саме це, наприклад, для кращого повідомлення про помилки з більшою кількістю внутрішньої інформації в дереві часткового розбору. Однак було б дуже поганою ідеєю дозволити цьому внутрішньому компілятору реалізовувати іншу мовну семантику, ніж офіційний SDK, оскільки це означатиме, що код, який працює в розробці, може таємниче почати виходити з ладу при встановленні у виробництві - створюючи проблеми, які за визначенням є не- налагодження!


Так сталося: я майже впевнений, що заповнення коду - це функція IDE (зроблена за допомогою відображення). А автоматична перевірка типу, про яку я говорив, відбувається в IDE (за допомогою компіляції фону). Я сподіваюся, що саме це відбувається.
konishiki

1
IDE може дуже легко порушити всі правила мовної специфікації та просто скомпілювати код у будь-якому разі. Я знаю, що і NetBeans, і Eclipse використовують, наприклад, свої власні компілятори. Тож у цих випадках IDE і компілятор - це те саме. Не кажучи, що це гарна ідея, але компілятори C, безумовно, роблять це постійно.
MichaelS

@MichaelS Специфікація мови C розроблена таким чином, щоб забезпечити значну різницю між реалізаціями, так що різні постачальники можуть вибирати між різними можливими підходами та додавати додаткові функції. Це створює різні характеристики неоднозначності в специфікації, які необхідні, щоб дозволити ці варіанти. Назва "C" не є торговою маркою, тому ніхто не контролює використання цього терміна. Специфікація Java призначена для усунення якомога більшої неоднозначності, а Java є торговою маркою, а власник торговельної марки примушує її використовувати лише в сумісних реалізаціях.
Жуль

Сучасним IDE так чи інакше потрібен компілятор. Підказки щодо заповнення коду вимагають розбору коду перед курсором розбору. І, звичайно, з дженериками (або шаблонами C ++), що вимагає повного компілятора, а не просто парсера.
MSalters

3

Це пов’язано з підписом типу методу Object.clone. Підпис типу вказує, що метод поверне об'єкт типу Object.

protected Object clone() throws CloneNotSupportedException

Колекції будуть використовувати так звані загальні типи для автоматичної заміни типу кастингу.

Тож якщо у вас є цей код:

List<Integer> ints = Arrays.asList(1,2,3);
int x = ints.get(0);`

компілятор додасть касти для вас за кадром, так що насправді код буде таким:

List ints = Arrays.asList(1,2,3);
int x = (Integer)ints.get(0);

0

Для повноти, оскільки у Java 5 дозволені типи повернення коваріанта . Тож ви можете написати наступне:

public MyObject implements Cloneable {
  @Override
  public MyObject clone() {
    try {
      return (MyObject)super.clone();
    } catch (CloneNotSupportedException e) {
      throw new AssertionError();
    }
  }
}

З цим законним є наступний код:

MyObject original = new MyObject();
MyObject clone = original.clone();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.