জাভা জেনেরিক্স - কেন "টি প্রসারিত করে" অনুমোদিত তবে "টি প্রয়োগ করে"?


306

আমি অবাক হয়েছি জাভাতে টাইপপ্যারামিটারের সীমা নির্ধারণের জন্য " extends" পরিবর্তে সর্বদা " " ব্যবহার করার জন্য যদি কোনও বিশেষ কারণ implementsথাকে।

উদাহরণ:

public interface C {}
public class A<B implements C>{} 

নিষিদ্ধ কিন্তু

public class A<B extends C>{} 

সঠিক. এর কারণ কী?


14
আমি জানি না কেন লোকেরা মনে করে কেন তেতুজিন নো ওনির উত্তর সত্যই প্রশ্নের উত্তর দেয়। এটি মূলত একাডেমিক শব্দ ব্যবহার করে ওপি'র পর্যবেক্ষণগুলিকে পুনরায় জবাব দেয়, তবে কোনও যুক্তি দেয় না। "কেন নেই implements?" - "কারণ কেবল আছে extends"।
থমাসআর

1
থমাসআর: কারণ এটি "অনুমোদিত" এর প্রশ্ন নয়, তবে অর্থটির: আপনি কোনও জেনেরিক কীভাবে কোনও প্রতিবন্ধকতা সহ কোনও প্রকার গ্রহণ করে লিখবেন তাতে কোনও পার্থক্য নেই যে সীমাবদ্ধতা ইন্টারফেস বা পূর্বপুরুষের ধরণের কিনা is
তেটসুজন নো ওনি

আমার যুক্তি সহ একটি উত্তর যুক্ত করা হয়েছে ( stackoverflow.com/a/56304595/4922375 ) কেন implementsনতুন কিছু আনবে না এবং বিষয়গুলিকে আরও জটিল করে তুলবে কেন । আমি আশা করি এটি আপনার পক্ষে সহায়ক হবে।
অ্যান্ড্রু টবিলকো

উত্তর:


328

শ্রেণি 'প্রয়োগ' বা 'প্রসারিত' কিনা এর মধ্যে জেনেরিক বাধা ভাষার কোনও অর্থগত পার্থক্য নেই। সীমাবদ্ধতার সম্ভাবনাগুলি হ'ল 'প্রসারিত' এবং 'সুপার' - অর্থাত্ এই শ্রেণিটি সেই অন্যটির সাথে বরাদ্দযোগ্য (প্রসারিত) কাজ করে, বা এই শ্রেণিটি সেই (সুপার) থেকে কার্যনির্বাহযোগ্য।


@ কমডোডেভ (আমি মনে করি উত্তরের পাশের নম্বরটি এটি সঠিক হিসাবে চিহ্নিত করেছে, আমি নিশ্চিত নই যে এটি চিহ্নিত করার অন্য কোনও উপায় আছে কিনা, কখনও কখনও অন্যান্য উত্তরে অতিরিক্ত তথ্য থাকতে পারে - যেমন আমার একটি বিশেষ সমস্যা ছিল যা আমি সমাধান করতে পারিনি এবং গুগল এটি অনুসন্ধানের জন্য আপনাকে এখানে পাঠায়)) @ টেটসুজিন নো ওনি (স্পষ্ট করার জন্য কিছু কোড ব্যবহার করা সম্ভব হবে?
থেক্স

@ এনটিজি, উদাহরণগুলির সন্ধান করা একটি প্রশ্নের এটি একটি খুব ভাল উদাহরণ - আমি এটিকে উত্তরটিতে এম্বেড করার পরিবর্তে মন্তব্যে এটি যুক্ত করব। stackoverflow.com/a/6828257/93922
তেতসুজিন

1
আমি মনে করি কারণটি কমপক্ষে আমার কাছে এমন একটি জেনেরিক থাকতে হবে যাতে একটি নির্মাণকারী এবং পদ্ধতি থাকতে পারে যে কোনও শ্রেণি গ্রহণ করতে পারে যা উভয়ই একটি বেস শ্রেণি তৈরি করে এবং একটি ইন্টারফেস প্রদর্শন করে যা কেবল কোনও ইন্টারফেসকে প্রসারিত করে না। তারপরে ইন্টারফেসের প্রেজেন্সের জন্য জেনেরিক পরীক্ষার ইনস্ট্যান্টেশন করুন এবং প্রকৃত শ্রেণিটি টাইপ প্যারামিটার হিসাবে নির্দিষ্ট করুন। আদর্শভাবে আমি চাই যে class Generic<RenderableT extends Renderable implements Draggable, Droppable, ...> { Generic(RenderableT toDrag) { x = (Draggable)toDrag; } }কেউ সময় চেক সংকলন চায়।
পিটার্ক

1
@ পিটারক এবং আপনি পেয়েছেন যে রেন্ডারেবলটি দিয়ে রেন্ডারেবল, ড্রাগগ্রেবল, ড্রপপ্যাবল প্রসারিত .... যদি না বুঝতে পারি যে আপনি মুছার জেনেরিকগুলি আপনার জন্য এটি করতে চান যা এটি সরবরাহ করে না।
তেটসুজন নো ওনি

@ টেটসুজিন্নো আপনি যা চান তা তেমন নয় যা কেবলমাত্র একটি নির্দিষ্ট শ্রেণীর ইন্টারফেস প্রয়োগ করে এমন ক্লাস গ্রহণের সংকলনের সময় প্রয়োগের জন্য, এবং তারপরে জেনেরিকের মধ্যে ওবিজেইসিটি ক্লাসের (যা সেই ইন্টারফেসগুলিকে প্রদর্শন করে) রেফারেন্স করতে সক্ষম হন এবং তা জেনে রাখুন কমপক্ষে কমপাইল করার সময় (এবং রান টাইমে কাম্য) জেনেরিককে দেওয়া যে কোনও কিছু নির্দিষ্টভাবে নির্দিষ্ট ইন্টারফেসে নিরাপদে কাস্ট করা যেতে পারে। এখন জাভা যেভাবে প্রয়োগ করা হয় তা এটি নয়। তবে ভালো লাগবে :)
পিটার্ক

77

উত্তরটি এখানে রয়েছে  :

বাউন্ডেড টাইপ পরামিতি ঘোষণা করতে, extendsকীওয়ার্ডের পরে প্যারামিটারের নামটি টাইপ করুন , তারপরে তার উপরের বাউন্ড […]। দ্রষ্টব্য, এই প্রসঙ্গে, প্রসারগুলি সাধারণ অর্থে ব্যবহৃত হয় extends(ক্লাস হিসাবে) বা implements(ইন্টারফেস হিসাবে ) বোঝাতে ।

সুতরাং সেখানে আপনার এটি আছে, এটি কিছুটা বিভ্রান্তিকর, এবং ওরাকল এটি জানে।


1
বিভ্রান্তি যুক্ত করতে getFoo(List<? super Foo> fooList) কেবল ক্লাসের সাথেই কাজ করে যা আক্ষরিকভাবে ফু এর দ্বারা প্রসারিত class Foo extends WildcardClass। এই ক্ষেত্রে একটি List<WildcardClass>গ্রহণযোগ্য ইনপুট হবে। তবে যে কোনও শ্রেণি Fooপ্রয়োগ করে যা কাজ করবে না class Foo implements NonWorkingWildcardClassতার অর্থ এই নয় যে List<NonWorkingWildcardClass>এটি কার্যকর হবে getFoo(List<? super Foo> fooList)। স্ফটিক পরিষ্কার!
রায়

19

সম্ভবত কারণ উভয় পক্ষের (বি এবং সি) কেবল প্রকারটি প্রাসঙ্গিক, বাস্তবায়ন নয়। আপনার উদাহরণে

public class A<B extends C>{}

বি পাশাপাশি ইন্টারফেস হতে পারে। "প্রসারিত" সাব-ইন্টারফেসের পাশাপাশি উপ-শ্রেণীর সংজ্ঞা দিতে ব্যবহৃত হয়।

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

আমি সাধারণত মনে 'সাব প্রসারিত সুপার' হিসেবে ' সাব মত হল সুপার তবে অতিরিক্ত ক্ষমতা', এবং 'Clz কার্যকরী Intf' হিসেবে ' Clz একটি আদায় হয় Intf '। আপনার উদাহরণে এটি মিলবে: বি সি এর মতো তবে অতিরিক্ত ক্ষমতা সহ। ক্ষমতাগুলি এখানে প্রাসঙ্গিক, আদায় নয়।


10
<বি প্রসারিত ডি ও ই> বিবেচনা করুন। E <ক্যাপস> অবশ্যই একটি বর্গ হবে না।
টম হাটিন -

7

এটি হতে পারে যে বেস টাইপটি একটি জেনেরিক প্যারামিটার হয়, সুতরাং প্রকৃত প্রকারটি কোনও শ্রেণির ইন্টারফেস হতে পারে। বিবেচনা:

class MyGen<T, U extends T> {

ক্লায়েন্ট কোড দৃষ্টিকোণ থেকে ইন্টারফেসগুলি ক্লাস থেকে প্রায় পৃথক পৃথক, যেখানে সাব টাইপের জন্য এটি গুরুত্বপূর্ণ।


7

এখানে প্রসারিত হওয়ার অনুমতি রয়েছে এবং সম্ভবত আপনি যা চান তার আরও জড়িত উদাহরণ এখানে রয়েছে:

public class A<T1 extends Comparable<T1>>


5

এটি কোন ধরণের স্বেচ্ছাসেবী পদক্ষেপ ব্যবহার করা উচিত। এটি কোনওভাবেই হতে পারত। সম্ভবত ভাষা ডিজাইনাররা সর্বাধিক মৌলিক শব্দ হিসাবে "প্রসারিত" এবং ইন্টারফেসের জন্য বিশেষ ক্ষেত্রে হিসাবে "প্রয়োগ" করার কথা ভাবেন।

তবে আমি মনে করি implementsকিছুটা বুদ্ধিমান হবে। আমি মনে করি যে আরও বেশি যোগাযোগ করে যে প্যারামিটারের ধরণগুলি উত্তরাধিকারের সম্পর্কের সাথে থাকতে হবে না, তারা যে কোনও ক্ষেত্রে থাকতে পারে ধরণের সাব টাইপের সম্পর্কের ।

জাভা গ্লোসারি একই মত প্রকাশ করে ।


3

আমরা অভ্যস্ত

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

এবং এই বিধিগুলি থেকে কোনও সামান্য বিচ্যুতি আমাদের বিভ্রান্ত করে।

একটি টাইপ বাউন্ডের বাক্য গঠনটি সংজ্ঞায়িত করা হয়

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

( জেএলএস 12> ৪.৪। ভেরিয়েবলগুলি টাইপ করুনTypeBound ))

আমরা এটি পরিবর্তন করতে হলে, আমরা নিশ্চয় যোগ হবে implementsকেস

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

এবং দুটি অভিন্ন প্রক্রিয়াযুক্ত ধারা সহ শেষ

ClassOrInterfaceType:
    ClassType 
    InterfaceType

( জেএলএস 12> 4.3। রেফারেন্সের ধরণ এবং মানগুলি>ClassOrInterfaceType )

বাদে আমাদেরও যত্ন নেওয়া দরকার implements, যা বিষয়গুলিকে আরও জটিল করে তুলবে।

আমি বিশ্বাস করি যে জটিল ধারণার মধ্যে জিনিসগুলি সহজ রাখার extends ClassOrInterfaceTypeপরিবর্তে extends ClassTypeএবং এর পরিবর্তে কেন ব্যবহৃত হয় এটিই মূল কারণ implements InterfaceType। সমস্যা আমরা সঠিক শব্দ উভয় আবরণ হবে না হয় extendsএবং implementsএবং আমরা স্পষ্টভাবে এক পরিচয় করিয়ে দিতে চাই না।

<T is ClassTypeA>
<T is InterfaceTypeA>

যদিও extendsএটি কোনও ইন্টারফেসের সাথে সাথে আসে তখন কিছুটা গোলযোগ এনে দেয়, এটি একটি বিস্তৃত শব্দ এবং এটি উভয় ক্ষেত্রেই বর্ণনা করতে ব্যবহার করা যেতে পারে। আপনার মনকে কোনও প্রকার বাড়ানোর ধারণার সাথে সুর দেওয়ার চেষ্টা করুন ( কোনও শ্রেণি প্রসারিত করা হবে না, কোনও ইন্টারফেস প্রয়োগ করা হচ্ছে না )। আপনি কোনও প্রকারের প্যারামিটারকে অন্য ধরণের দ্বারা সীমাবদ্ধ করেন এবং সেই ধরণের আসলে কী তা বিবেচ্য নয়। এটি কেবল গুরুত্বপূর্ণ যে এটি এর উপরের আবদ্ধ এবং এটি এর সুপারটাইপ


-1

আসলে, ইন্টারফেসে জেনেরিক ব্যবহার করার সময়, কীওয়ার্ডটিও প্রসারিত হয় । কোডের উদাহরণ এখানে:

2 টি ক্লাস রয়েছে যা গ্রিটিং ইন্টারফেস প্রয়োগ করে:

interface Greeting {
    void sayHello();
}

class Dog implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Dog: Hello ");
    }
}

class Cat implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Cat: Hello ");
    }
}

এবং পরীক্ষার কোড:

@Test
public void testGeneric() {
    Collection<? extends Greeting> animals;

    List<Dog> dogs = Arrays.asList(new Dog(), new Dog(), new Dog());
    List<Cat> cats = Arrays.asList(new Cat(), new Cat(), new Cat());

    animals = dogs;
    for(Greeting g: animals) g.sayHello();

    animals = cats;
    for(Greeting g: animals) g.sayHello();
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.