“Çocuk x = yeni Çocuk ();” yerine “Üst x = yeni Çocuk ();”, ikincisini kullanabilirsek kötü bir uygulama mı?


32

Örneğin, bunun gibi bir parça oluşturan bazı kodlar görmüştüm:

Fragment myFragment=new MyFragment();

bu bir değişkeni MyFragment yerine Fragment olarak bildirir, ki MyFragment bir Fragment alt sınıfıdır. Bu kod satırını karşılamam çünkü bu kodun olması gerektiğini düşünüyorum:

MyFragment myFragment=new MyFragment();

Hangisi daha belirgin, bu doğru mu?

Veya sorunun genelleştirmesinde, kullanımı kötü bir uygulama mıdır:

Parent x=new Child();

yerine

Child x=new Child();

eski olanı derleme hatası olmadan ikincisine çevirebilir miyiz?


6
İkincisini yaparsak, soyutlama / genelleme artık bir anlamı yoktur. Tabii ki istisnalar var ...
Walfrat

2
Üzerinde çalıştığım bir projede, işlevlerim ebeveyn türünü bekliyor ve ebeveyn tür yöntemlerini çalıştırıyor. Bazı çocuklardan herhangi birini kabul edebilirim ve bu (kalıtsal ve geçersiz kılınan) yöntemlerinin arkasındaki kod farklıdır, ancak hangi çocuğu kullanırsam kullansın bu kodu çalıştırmak istiyorum.
Stephen S

4
@Walfrat Aslında, zaten beton tipine hazırlanırken soyutlamanın çok az noktası var, ancak müşteri kodunu memnuniyetsizce cahil etmesi için soyut tipini yine de geri getirebilirsiniz .
Jacob Raihle

4
Ebeveyn / Çocuk kullanmayın. Arabirim / Sınıfı kullanın (Java için).
Thorbjørn Ravn Andersen

4
Google, neden kullanmanın Parent x = new Child()iyi bir fikir olduğu hakkında birkaç açıklama için “bir arayüze programlama” .
Kevin Workman

Yanıtlar:


69

Bağlama bağlı, ancak mümkün olan en soyut türü açıklamanız gerektiğini savunuyorum . Bu şekilde kodunuz mümkün olduğu kadar genel olacak ve alakasız ayrıntılara bağlı olmayacaktır.

Bir örnek, her ikisinden de gelen LinkedListve sahip olacaktı . Eğer kod herhangi bir listeyle eşit derecede çalışırsa, keyfi olarak alt sınıflardan birine sınırlamak için bir sebep yoktur.ArrayListList


24
Kesinlikle. Bir örnek eklemek için, düşünün List list = new ArrayList(), Listeyi kullanan kodun ne tür bir liste olduğu önemli değildir, yalnızca Liste arayüzünün sözleşmesini karşılamaktadır. Gelecekte, farklı bir Liste uygulamasına kolayca geçebilirdik ve temeldeki kodun değiştirilmesi veya güncellenmesi gerekmez.
Maybe_Factor

19
iyi cevap, ancak mümkün olan en soyut türün genişlemesi gerekir, kapsamdaki kodun çocuğa özel bir işlem yapmak için çocuğa geri verilmemesi gerektiği anlamına gelir.
Mike,

10
@Mike: Söylemeye gerek kalmadan devam ediyorum, aksi takdirde tüm değişkenler, parametreler ve alanlar olarak ilan edilir Object!
JacquesB

3
@JacquesB: Bu soru ve cevap çok fazla dikkat çektiğinden beri, açık olmanın farklı beceri seviyelerine sahip kişiler için faydalı olacağını düşünüyordum.
Mike,

1
Bağlamın bir cevap olmadığı bağlamına bağlıdır .
Billal Begueradj

11

JacquesB'nin cevabı doğru olsa da, biraz soyut. Bazı yönleri daha net vurgulayayım:

Kod snippet'inizde, newanahtar kelimeyi açıkça kullanırsınız ve belki de somut tür için büyük olasılıkla özel olan başka başlatma adımlarına devam etmek istersiniz: o zaman değişkeni o somut türle belirtmeniz gerekir.

Bu maddeyi başka bir yerden aldığınızda, durum farklı IFragment fragment = SomeFactory.GiveMeFragments(...);. Burada, fabrika normalde mümkün olan en soyut tipi iade etmeli ve aşağı kod uygulama detaylarına bağlı olmamalıdır.


18
"biraz soyut olsa da". Badumtish.
rosuav

1
Bu bir düzenleme olamaz mıydı?
beppe9000

6

Potansiyel olarak performans farklılıkları vardır.

Eğer türetilmiş sınıf mühürlenirse, derleyici sanal çağrılar ne olabilir diye sıraya sokabilir ve optimize edebilir veya ortadan kaldırabilir. Yani önemli bir performans farkı olabilir.

Örnek: ToStringsanal bir çağrıdır, ancak Stringmühürlenmiştir. Açık String, ToStringno-op, yani objectsanal bir çağrı olduğunu bildirirseniz, bir Stringderleyiciyi ilan ederseniz, türetilmiş bir sınıfın, metodu geçersiz kılmadığını bilir, çünkü sınıf mühürlüdür, yani bu bir no-op'tur. Benzer düşünceler ArrayListvs için de geçerlidir LinkedList.

Bu nedenle, nesnenin somut türünü biliyorsanız (ve onu gizlemek için bir kapsülleme sebebi yoktur), bu tür olarak beyan etmelisiniz. Nesneyi yeni oluşturduğunuzdan, beton türünü biliyorsunuz.


4
Çoğu durumda, performans farklılıkları küçüktür. Ve çoğu durumda (bunun zamanın% 90'ı olduğunu söylediğini duydum) bu küçük farklılıkları unutmalıyız. Yalnızca kodun performans kritik bölümü olarak yaşadığımızı (tercihen ölçüm yoluyla) bildiğimiz zaman, bu tür optimizasyonlara önem vermeliyiz.
Jules

Ve derleyici, "new Child ()" nin bir Ebeveyn olarak atanmasına rağmen bir Çocuk döndürdüğünü bilir ve bildiği sürece, bu bilgiyi kullanabilir ve Child () kodunu çağırabilir.
gnasher729

+1. Ayrıca cevabımı örnek olarak çaldı. = P
Nat

1
Her şeyi tartışmaya sokan performans optimizasyonları olduğunu unutmayın. Örneğin HotSpot, bir işleve iletilen bir parametrenin her zaman belirli bir sınıf olduğunu fark eder ve buna göre optimize eder. Bu varsayımın yanlış olduğu ortaya çıkarsa, yöntem deoptimizimizize edilir. Ancak bu kesinlikle derleyici / çalışma zamanı ortamına bağlıdır. CLR'yi en son kontrol ettiğimde, p'nin Parent p = new Child()her zaman bir çocuk olduğunu fark etmenin önemsiz bir optimizasyonunu bile yapamadım ..
Voo

4

Önemli fark, gereken erişim düzeyidir. Ve soyutlama ile ilgili her iyi cevap hayvanları içerir, ya da bana söylenir.

Farz edelim ki birkaç hayvanınız var - Cat Birdve Dog. Şimdi bu hayvanlar birkaç genel davranışlara sahip - move(), eat()ve speak(). Hepsi farklı yiyorlar ve farklı konuşuyorlar, fakat benim hayvanımı yemek veya konuşmak için ihtiyacım olursa, nasıl yaptıklarını gerçekten umursamıyorum.

Ama bazen yapıyorum. Asla bir bekçi kedisi veya bekçi kuşu istemedim, ama bir bekçi köpeğim var. Birisi evime girdiğinde, davetsiz misafirleri korkutmak için konuşmaya güvenemem. Gerçekten havlamak için köpeğime ihtiyacım var - bu sadece konuşması olan konuşmasından farklı.

Yani bir davetsiz misafir gerektiren kodunda gerçekten yapmam gereken Dog fido = getDog(); fido.barkMenancingly();

Ama çoğu zaman, herhangi bir hayvanın, dokunma, miyavlama veya tweet atmalarının olduğu püf noktaları yapmalarını sağlayabilirim. Animal pet = getAnimal(); pet.speak();

Daha somut olmak için, ArrayList'in yapmayan bazı yöntemleri var List. Özellikle trimToSize(),. Şimdi, vakaların% 99'unda bunu umursamıyoruz. ListBizim bakım için neredeyse hiç büyük yeterlidir. Ama olduğu zamanlar vardır. Bu nedenle, zaman zaman özellikle bir yedekleme dizisini ArrayListyürütmek trimToSize()ve küçültmek için sormamız gerekir .

Bunun yapım aşamasında yapılması gerekmediğine dikkat edin - kesinlikle emin olursak bir geri dönüş yöntemi veya hatta bir döküm ile yapılabilir.


Bunun neden bir aşağı oylama olabileceği konusunda karıştı. Şahsen kanonik görünüyor. Programlanabilir bir bekçi köpeği fikri dışında ...
corsiKa

En iyi cevabı bulmak için neden sayfaları okumak zorunda kaldım? Değerlendirme berbat.
Basilevs,

Nazik sözleriniz için teşekkürler. Derecelendirme sistemlerinin lehte ve aleyhte olanlar var ve bunlardan biri, daha sonra cevapların bazen toza girebileceği yönünde. Olur!
corsiKa

2

Genel olarak konuşursanız, kullanmalısınız

var x = new Child(); // C#

veya

auto x = new Child(); // C++

yerel değişkenler için, değişkenin başlangıçta başlatıldığı gibi farklı bir tür olması iyi bir neden olmadığı sürece.

(Burada, C ++ kodunun büyük olasılıkla akıllı bir işaretçi kullanması gerektiği gerçeğini görmezden geliyorum. Aslında bilemeyeceğim birden fazla satırın olmadığı ve olmadığı durumlar var.)

Buradaki genel fikir, değişkenlerin otomatik tür algılamasını destekleyen dillerle ilgilidir, kullanımı kodun okunmasını kolaylaştırır ve doğru olanı yapar (yani, derleyicinin tür sistemi mümkün olduğu kadar en iyi duruma getirebilir ve ilklendirmeyi yeni olacak şekilde değiştirebilir) tür, çoğu özet kullanılmış olsaydı da çalışır.


1
C ++ 'da değişkenler çoğunlukla yeni anahtar kelime olmadan oluşturulur: stackoverflow.com/questions/6500313/…
Marian Spanik

1
Soru, C # / C ++ ile ilgili değil, en azından bir tür statik yazım biçimine sahip bir dilde (yani Ruby gibi bir şey sormak için saçma sapan) genel bir nesne yönelimli sorun hakkındadır. Ayrıca, bu iki dilde bile, söylediğin gibi yapmamız için neden iyi bir sebep göremiyorum.
AnoE

1

İyi çünkü bu kodu anlamak ve değiştirmek kolay:

var x = new Child(); 
x.DoSomething();

İyi çünkü niyetini iletiyor:

Parent x = new Child(); 
x.DoSomething(); 

Tamam, çünkü yaygın ve anlaşılması kolaydır:

Child x = new Child(); 
x.DoSomething(); 

Gerçekten kötü olan bir seçenek, Parentsadece Childbir yöntem varsa kullanmaktır DoSomething(). Kötü çünkü niyetini yanlış iletiyor:

Parent x = new Child(); 
(x as Child).DoSomething(); // DON'T DO THIS! IF YOU WANT x AS CHILD, STORE x AS CHILD

Şimdi, sorunun özellikle sorduğu durum hakkında biraz daha ayrıntı verelim:

Parent x = new Child(); 
x.DoSomething(); 

İkinci yarıda bir işlev çağrısı yaparak bunu farklı bir biçimde formatlayalım:

WhichType x = new Child(); 
FunctionCall(x);

void FunctionCall(WhichType x)
    x.DoSomething(); 

Bu kısaltılabilir:

FunctionCall(new Child());

void FunctionCall(WhichType x)
    x.DoSomething();

Burada, WhichTypeişlevin çalışmasına izin veren en temel / soyut tür olması gerektiği (performans kaygıları olmadığı sürece) yaygın olarak kabul edildiğini kabul ediyorum . Bu durumda doğru türünün olacağını Parentfalan Parenttüretilmiştir.

Bu akıl yürütme türü Parent, türü kullanmanın neden iyi bir seçim olduğunu açıklamaktadır, ancak diğer seçimlerin kötü olduğu (havaya girmeyen) havaya girmez.


1

tl, dr - kullanmaChildüzerindeParentyerel kapsamında tercih edilir. Yalnızca okunabilirliğe yardımcı olmakla kalmaz, aynı zamanda aşırı yüklenmiş yöntem çözünürlüğünün düzgün çalıştığından ve verimli derlemeye olanak sağladığından emin olmak için de gereklidir.


Yerel kapsamda

Parent obj = new Child();  // Works
Child  obj = new Child();  // Better
var    obj = new Child();  // Best

Kavramsal olarak, mümkün olan en fazla bilgiyi sağlamakla ilgilidir. Eğer düşürürsek Parent, aslında sadece yararlı olabilecek tipteki bilgileri çıkartıyoruz.

Tam tip bilgiyi saklamanın dört ana avantajı vardır:

  1. Derleyiciye daha fazla bilgi sağlar.
  2. Okuyucuya daha fazla bilgi sağlar.
  3. Daha temiz, daha standart kod.
  4. Program mantığını daha değişken kılar.

Avantaj 1: Derleyiciye daha fazla bilgi

Belirgin tip aşırı yüklenmiş yöntem çözünürlüğünde ve optimizasyonda kullanılır.

Örnek: Aşırı yüklenmiş yöntem çözünürlüğü

main()
{
    Parent parent = new Child();
    foo(parent);

    Child  child  = new Child();
    foo(child);
}
foo(Parent arg) { /* ... */ }  // More general
foo(Child  arg) { /* ... */ }  // Case-specific optimizations

Yukarıdaki örnekte, her iki foo()çağrı da işe yarar , ancak bir durumda daha iyi aşırı yüklenmiş yöntem çözünürlüğünü elde ederiz.

Örnek: Derleyici optimizasyonu

main()
{
    Parent parent = new Child();
    var x = parent.Foo();

    Child  child  = new Child();
    var y = child .Foo();
}
class Parent
{
    virtual         int Foo() { return 1; }
}
class Child : Parent
{
    sealed override int Foo() { return 2; }
}

Yukarıdaki örnekte, her iki .Foo()çağrı da sonuçta overridegeri dönen aynı yöntemi çağırır 2. Sadece, ilk durumda, doğru yöntemi bulmak için sanal bir yöntem arama var; Bu sanal yöntem arama, bu yöntemden bu yana ikinci durumda gerekli değildir sealed.

Benzer bir örnek teşkil @Ben Kredi onun cevabını .

Avantaj 2: Okuyucuya daha fazla bilgi

Tam tipini bilmek, yani Child, kodu okuyanlara programın ne yaptığını görmeyi kolaylaştıran daha fazla bilgi sağlar.

Elbette, belki de her ikisi için de geçerli olan kod için bir önemi yoktur parent.Foo();ve child.Foo();mantıklıdır, ancak biri kodu ilk defa gören biri için daha fazla bilgi basit olur.

Ayrıca, geliştirme ortamına bağlı olarak, IDE hakkında daha yararlı ipuçları ve meta verilerini sağlayan mümkün olabilir Childdaha Parent.

Avantaj 3: Daha temiz, daha standart kod

Son zamanlarda gördüğüm C # kod örneklerinin çoğu var, bunun için temelde steno olan Child.

Parent obj = new Child();  // Sub-optimal
Child  obj = new Child();  // Optimal, but anti-pattern syntax
var    obj = new Child();  // Optimal, clean, patterned syntax "everyone" uses now

varBeyanname dışı bir ifadeyi görmek sadece göze çarpıyor; durumsal bir neden varsa, harika, ama aksi takdirde anti-pattern görünüyor.

// Clean:
var foo1 = new Person();
var foo2 = new Job();
var foo3 = new Residence();

// Staggered:
Person foo1 = new Person();
Job foo2 = new Job();
Residence foo3 = new Residence();   

Avantaj 4: Prototipleme için daha değişken program mantığı

İlk üç avantaj, büyük avantajlardı; bu çok daha durumsal.

Yine de, diğerleri gibi kod kullananlar için Excel kullanıyor, kodumuzu sürekli değiştiriyoruz. Belki özgü bir yöntemi çağırmak gerekmez Childiçinde bu kod sürümü, ama biz repurpose veya daha sonra kodu biçim verebilirsiniz.

Güçlü bir tip sistemin avantajı, bize program mantığımız hakkında bazı meta veriler sağlayarak olanakları daha kolay ortaya çıkarmasıdır. Bu prototip yapımında inanılmaz derecede faydalıdır, bu yüzden mümkün olduğunda saklamak en iyisidir.

özet

Kullanılması ParentAşırı yüklü yöntem çözünürlüğü kadar pisliklerimizi, bazı derleyici optimizasyonlar inhibe okuyucudan bilgileri kaldırır ve kod çirkin yapar.

Kullanımı vargerçekten gitmek yoludur. Hızlı, temiz, desenli ve derleyicinin ve IDE'nin işlerini doğru yapmasına yardımcı olur.


Önemli : Bu cevap hakkındadırParentvs.Childbir yöntemin yerel kapsamında. SorunuParentvsChilddönüş türleri, argümanlar ve sınıf alanları için çok farklıdır.


2
Bunun Parent list = new Child()çok anlamlı olmadığını da eklerdim. Bir nesnenin somut örneğini doğrudan yaratan kod (fabrikalar, fabrika yöntemleri vb. İle dolaysız olarak), yaratılan tür hakkında mükemmel bilgiye sahiptir, yeni oluşturulan nesneyi yapılandırmak için somut arayüzle etkileşime girmesi gerekebilir. Yerel kapsam, esnekliği sağladığınız yerde değildir . Yeni oluşturulan nesneyi daha soyut bir arabirim kullanarak sınıfınızın bir müşterisine gösterdiğiniz zaman esneklik elde edilir (fabrikalar ve fabrika yöntemleri mükemmel bir örnektir)
crizzis

"tl; dr Çocuğu Ebeveyn Üzerinde Kullanmak yerel kapsamda tercih edilir. Yalnızca okunabilirliğe yardımcı olmaz," - zorunlu değil ... eğer çocuk özelliklerini kullanmazsanız, gerekenden daha fazla ayrıntı ekler. "ancak aşırı yüklenmiş yöntem çözünürlüğünün düzgün çalıştığından ve verimli derlemeye olanak sağladığından emin olmak için de gerekli." - bu programlama diline çok fazla bağlı. Bundan kaynaklanan hiçbir sorunu olmayan çok şey var.
AnoE

1
Bunun kaynağı var mı Parent p = new Child(); p.doSomething();ve Child c = new Child; c.doSomething();farklı davranışa sahip? Belki bu, bir dilde bir tuhaflık olsa da, nesnenin referansı değil davranışı kontrol ettiği farz edilir. Mirasın güzelliği bu! Ebeveyn uygulama sözleşmesini yerine getirmek için çocuk uygulamalarına güvenebileceğiniz sürece, gitmeniz iyi olur.
corsiKa

@corsiKa Evet, birkaç şekilde mümkündür. İki hızlı örnek, yöntem imzalarının üzerine yazıldığı, örneğin newC # içindeki anahtar kelimeyle ve birden çok tanım olduğunda, örneğin C ++ ' da çoklu kalıtımla ilgili olabilir .
Nat

@corsiKa Sadece hızlı bir üçüncü örnek (çünkü C ++ ve C # arasında düzgün bir kontrast olduğunu düşündüğüm için), C # 'nın C ++ gibi bir sorunu var , bu davranışı açık arabirim yöntemlerinden de alabilirsiniz . Komik çünkü C # gibi diller bu sorunları önlemek için kısmen miras yerine ara yüzleri kullanıyorlar, ancak ara yüzleri benimseyerek hala konunun bir parçası oldular - ama, o kadar da kötü değil çünkü bu senaryoda, sadece geçerlidir ne zaman Parentbir olduğunu interface.
Nat

0

Verilen parentType foo = new childType1();kod, ebeveyn-tipi metotların kullanımı ile sınırlı olacak foo, fakat sadece-değil foo, türünden türetilen herhangi bir nesneye referansta parentsaklanabilecek childType1. Yeni childType1örnek, fooreferans alabilecek tek şeyse , footürünü bildirmek daha iyi olabilir childType1. Öte yandan, foodiğer türlere atıfta bulunulması gerekebilirse, bunu parentTypemümkün kılacak şekilde beyan ettirmek.


0

Kullanmanızı öneririm

Child x = new Child();

yerine

Parent x = new Child();

İkincisi, eski değil iken bilgi kaybeder.

Eski ile yapabileceğiniz her şeyi yapabilirsiniz, ikincisiyle de yapabilirsiniz ancak bunun tersi mümkün değildir.


İşaretçiyi daha fazla ayrıntılandırmak için, birden fazla kalıtım seviyesine sahip olalım.

Base-> DerivedL1->DerivedL2

Ve new DerivedL2()bir değişkenin sonucunu başlatmak istiyorsunuz . Taban türünü kullanmak, Baseya da seçeneğini kullanma seçeneği sunar DerivedL1.

Kullanabilirsiniz

Base x = new DerivedL2();

veya

DerivedL1 x = new DerivedL2();

Birini diğerine tercih etmenin mantıklı bir yolunu görmüyorum.

Eğer kullanırsan

DerivedL2 x = new DerivedL2();

tartışacak bir şey yok.


3
Daha fazlasını yapmanıza gerek yoksa daha azını yapabilmek iyi bir şey, değil mi?
Peter,

1
@Peter, daha az yapabilme kabiliyeti kısıtlı değildir. Her zaman mümkün. Daha fazlasını yapma yeteneği kısıtlıysa, bir boğaz noktası olabilir.
R Sahu

Ancak bilgi kaybetmek bazen iyi bir şeydir. Hiyerarşi konusunda, çoğu insan muhtemelen Baseişe yarayacağını düşünüyor. En spesifik olanı tercih edersiniz, AFAIK çoğunluk en az spesifik olanı tercih eder. Yerel değişkenler için çok önemli olmadığını söyleyebilirim.
maaartinus

@maaartinus, kullanıcıların çoğunun bilgi kaybetmeyi tercih etmesine şaşırdım. Bilgiyi kaybetmenin yararlarını diğerleri kadar net göremiyorum.
R Sahu

Bunu beyan Base x = new DerivedL2();ettiğinizde en kısıtlı olursunuz ve bu başka bir (büyük) çocuğu asgari çabayla değiştirmenize izin verir. Ayrıca, bunun mümkün olduğunu hemen anlıyorsunuz . +++ Bundan void f(Base)daha iyi olduğuna katılıyor muyuz void f(DerivedL2)?
maaartinus

0

Değişkenleri her zaman en spesifik tür olarak döndürmeyi veya saklamayı, ancak parametreleri en geniş tür olarak kabul etmeyi öneririm.

Örneğin

<K, V> LinkedHashMap<K, V> keyValuePairsToMap(List<K> keys, List<V> values) {
   //...
}

Parametreler List<T>çok genel bir türdür. ArrayList<T>, LinkedList<T>Ve diğerleri hepsi bu yöntemle kabul edilebilir.

Önemlisi, dönüş türü LinkedHashMap<K, V>değil Map<K, V>. Birisi bu yöntemin sonucunu a'ya atamak isterse Map<K, V>, bunu yapabilir. Bu sonucun sadece bir haritadan ibaret değil, tanımlanmış bir sıraya sahip bir harita olduğunu açıkça ifade ediyor.

Bu yöntemin geri döndüğünü varsayalım Map<K, V>. Arayan bir kişi LinkedHashMap<K, V>isterse, gerçekten zahmetli olan bir tür kontrol, döküm ve hata işlemesi yapmak zorunda kalacaklardı.


Sizi bir parametre olarak geniş bir tip kabul etmeye zorlayan aynı mantık aynı zamanda dönüş tipine de uygulanmalıdır. Fonksiyonun amacı değerlerine anahtarları eşleştirme ise, bir dönmelidir Mapdeğil LinkedHashMap- sadece bir iade isteyeyim LinkedHashMapbir benzeri işlev için keyValuePairsToFifoMapfalan. Yapmamak için belirli bir nedeniniz oluncaya kadar daha geniş.
corsiKa

@corsiKa Hmm Daha iyi bir isim olduğuna katılıyorum, ancak bu sadece bir örnek. (Genel olarak) iade türünüzü genişletmenin daha iyi olduğuna katılmıyorum. Herhangi bir gerekçesiz, yapay olarak kaldırma tipi bilgileriniz. Kullanıcınızın, sağladığınız geniş türü geri alması gerekeceğini düşünüyorsanız, o zaman bir kötülük yaptınız.
Alexander - Monica

"herhangi bir gerekçe olmadan" - ancak gerekçe vardır! Daha geniş bir tipe geri dönmekten kurtulabilirsem, yeniden yapılanmayı yolda daha kolay hale getirir. Birisi bazı davranış nedeniyle belirli bir tip İHTİYACI VARSA, ben uygun tipini döndürdüğüm için. Ama bana mecbur değilsem, belirli bir tipte kilitli kalmak istemiyorum. Bunu tüketmek olanlar zarar vermeden benim yöntemin özelliklerini değiştirmeye özgür olmak ister ve ben onu değiştirirseniz, derdim LinkedHashMapiçin TreeMapşimdi değişikliğine bir sürü şey var, sebebi ne olursa olsun.
corsiKa

Aslında, son cümleye kadar tamamen aynı fikirdeyim. Sen değişti LinkedHashMapiçin TreeMapböyle değişen gibi önemsiz bir değişiklik olmadığı ArrayListiçin LinkedList. Anlamsal öneme sahip bir değişiklik. Bu durumda , derleyicinin bir hata yapmasını, geri dönüş değerindeki tüketicileri değişikliği farketmesi ve uygun işlemi yapması için zorlamak istersiniz .
Alexander - Monica

Ama olabilir umurunda tüm ilgili harita davranışı ise önemsiz bir değişiklik (ki sen, yapmalısın. Yapabilirsen) sözleşme ise için de geçerlidir ki ( "Bir anahtar değeri harita alacak" ve sipariş önemli değil çoğu harita) o zaman bir ağaç mı yoksa karma harita mı olduğu önemli değil. Örneğin, Thread#getAllStackTraces()- özellikle yolun aşağısındaki Map<Thread,StackTraceElement[]>yerine bir dönüş döndürür , HashMapistedikleri türle değiştirebilirler Map.
corsiKa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.