জাভাতে জেনেরিক ধরণের উদাহরণ তৈরি করুন?


576

জাভাতে জেনেরিক ধরণের উদাহরণ তৈরি করা কি সম্ভব? আমি উত্তরটি যা দেখেছি তার ভিত্তিতে ভাবছি no( টাইপ ইরেজরের কারণে ), তবে আমি যদি আগ্রহী এমন কিছু দেখতে পাই তবে আমি আগ্রহী:

class SomeContainer<E>
{
    E createContents()
    {
        return what???
    }
}

সম্পাদনা: দেখা যাচ্ছে যে সুপার টাইপ টোকেনগুলি আমার সমস্যা সমাধানের জন্য ব্যবহৃত হতে পারে তবে এর জন্য অনেকগুলি প্রতিবিম্ব-ভিত্তিক কোডের প্রয়োজন হয়, যেমন নীচের কয়েকটি উত্তর নির্দেশ করেছে।

ইয়ান রবার্টসনের আর্টিমা নিবন্ধের চেয়ে কেউ নাটকীয়ভাবে আলাদা কিছু নিয়ে আসে কিনা তা দেখার জন্য আমি এই অল্প সময়ের জন্য ছেড়ে দেব ।


2
Android ডিভাইসে সবেমাত্র পরীক্ষামূলক কর্মক্ষমতা performance 10000 ক্রিয়াকলাপ এবং: 8-9 এমএস নতুন সামারক্লাস লাগে (), 9-11 এমএস লাগে কারখানার <সোমক্লাস> .CreateInstance () এবং -৪-71১ এমএসের সংক্ষিপ্ত প্রতিচ্ছবি লাগে: সামার ক্লাস জেড = সামার ক্লাস.ক্লাস.নেউ ইনস্ট্যান্স ()। এবং সমস্ত পরীক্ষা একক চেষ্টা-ব্লক ছিল। প্রতিবিম্ব newInstance () নিক্ষেপ 4 বিভিন্ন ব্যতিক্রম, মনে আছে? তাই আমি কারখানার প্যাটার্নটি ব্যবহার করার সিদ্ধান্ত নিয়েছি
ডিপস্কর্ন


4
জাভা 8 এর সাহায্যে আপনি এখন কোনও কনস্ট্রাক্টর রেফারেন্স বা ল্যাম্বডায় পাস করতে পারেন যা এই সমস্যাটিকে চারপাশে কাজ করার জন্য বেশ তুচ্ছ করে তোলে। বিস্তারিত জানার জন্য নীচে আমার উত্তর দেখুন ।
ড্যানিয়েল প্রাইডেন

আমি মনে করি যে এই জাতীয় কোডটি লিখতে এটি খারাপ ধারণা, এটি নীচের সমস্যার সমাধানের জন্য আরও মার্জিত এবং পঠনযোগ্য উপায়।
ক্রিজিসটফ সিচোকি

1
@ ডেভিডসিট্রন "কিছুক্ষণের জন্য" তিনি বলেছিলেন ... তারপরে এগারো বছর কেটে গেছে ...
এমসির সম্রাট

উত্তর:


332

আপনি সঠিক. আপনি করতে পারবেন না new E()। তবে আপনি এটিতে পরিবর্তন করতে পারেন

private static class SomeContainer<E> {
    E createContents(Class<E> clazz) {
        return clazz.newInstance();
    }
}

এটি একটি ব্যথা। কিন্তু এটি কাজ করে. কারখানার প্যাটার্নে এটি মোড়ানো এটিকে আরও কিছুটা সহনীয় করে তোলে।


11
হ্যাঁ, আমি সেই সমাধানটি দেখেছি, তবে এটি কেবল তখনই কাজ করে যদি আপনি ইতিমধ্যে যে ধরণের শ্রেণীর অবজেক্টটি ইনস্ট্যান্ট করতে চান তার কোনও রেফারেন্স থাকে।
ডেভিড সিট্রন

11
হ্যাঁ আমি জানি. আপনি যদি ই ক্লাস করতে পারতেন তবে চমৎকার লাগবে তবে তা কেবল ক্ষয়জনিত কারণে আপনাকে Object.class দেয় :)
জাস্টিন রুড

6
এটিই এই সমস্যার সঠিক পন্থা। এটি সাধারণত আপনি যা চান তা নয়, তবে আপনি যা পান তা এটি।
জোছিম সৌর

38
এবং আপনি কীভাবে ক্রিয়েট কনটেন্টস () পদ্ধতিটিকে কল করবেন?
অ্যালেক্সিস ডুফরনয়

8
এটি করার এখন আর একমাত্র উপায় নয়, এখন আরও ভাল উপায় আছে যা Class<?>পেয়ারা এবং টাইপটোকেন ব্যবহার করে কোনও রেফারেন্স পাস করার প্রয়োজন হয় না , কোড এবং লিঙ্কগুলির জন্য এই উত্তরটি দেখুন!

129

ডুনো যদি এটি সহায়তা করে তবে আপনি যখন জেনেরিক প্রকারটি (বেনামে অন্তর্ভুক্ত) সাবক্লাস করেন তখন টাইপের তথ্য প্রতিবিম্বের মাধ্যমে পাওয়া যায়। যেমন,

public abstract class Foo<E> {

  public E instance;  

  public Foo() throws Exception {
    instance = ((Class)((ParameterizedType)this.getClass().
       getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
    ...
  }

}

সুতরাং, যখন আপনি ফু সাবক্লাস করেন, আপনি বারের উদাহরণ পাবেন যেমন,

// notice that this in anonymous subclass of Foo
assert( new Foo<Bar>() {}.instance instanceof Bar );

তবে এটি অনেক কাজ, এবং কেবলমাত্র সাবক্লাসের জন্য কাজ করে। যদিও সুবিধাজনক হতে পারে।


2
হ্যাঁ, এটি দুর্দান্ত, বিশেষত জেনেরিক ক্লাসটি বিমূর্ত থাকলে আপনি কংক্রিটের সাবক্লাসে এটি করতে পারেন :)
পিয়েরে হেনরি

শ্রেণি Fooবিমূর্ত না হলে এই পদ্ধতিটিও কাজ করে । তবে কেন এটি কেবল ফু এর বেনামে সাবক্লাসে কাজ করে? মনে করুন আমরা Fooকংক্রিট তৈরি করি (আমরা বাইরে চলে যাই abstract), new Foo<Bar>();ত্রুটির কারণ হবে কেন , যদিও new Foo<Bar>(){};না? (ব্যতিক্রম: "ক্লাসটি প্যারামিটারাইজড
টাইপে

2
@ টিমকুইপার্স <E>ইন class Foo<E>কোনও নির্দিষ্ট ধরণের সাথে আবদ্ধ নয়। আপনি ব্যতিক্রমী আচরণ যখনই দেখতে হবে Eনয় স্ট্যাটিক্যালি হিসাবে, আবদ্ধ: new Foo<Bar>(), new Foo<T>() {...}, অথবা class Fizz <E> extends Foo<E>। প্রথম কেসটি স্থিতিশীলভাবে আবদ্ধ নয়, এটি সংকলনের সময়ে মুছে ফেলা হয়। দ্বিতীয় কেসটির পরিবর্তে অন্য ধরণের ভেরিয়েবল (টি) কে প্রতিস্থাপন করে Eতবে এটি সীমাহীন। এবং শেষ ক্ষেত্রে এটি সুস্পষ্ট হওয়া উচিত যে Eএখনও সীমাহীন।
উইলিয়াম দাম

4
প্রকারের প্যারামিটারকে স্থায়ীভাবে বাঁধাই করার একটি উদাহরণ হতে পারে class Fizz extends Foo<Bar>- এই ক্ষেত্রে, ব্যবহারকারীরা Fizzএমন কিছু পান যা একটি Foo<Bar>এবং যা এ ছাড়া কিছুই হতে পারে না Foo<Bar>। সুতরাং এই ক্ষেত্রে, সংকলকটি ক্লাস মেটাডেটার জন্য সেই তথ্যটি এনকোড করে Fizzএবং ParameterizedTypeপ্রতিবিম্বের কোড হিসাবে এটি উপলভ্য করে খুশি । যখন আপনি কোনও বেনামি new Foo<Bar>() {...}অন্তর্গত শ্রেণি তৈরি করেন ঠিক যেমন এটি করা হয়, সংকলকটির পরিবর্তে Fizzএকটি "বেনামি" শ্রেণীর নাম উত্পন্ন করে যা আপনি বাইরের শ্রেণি সংকলন না হওয়া অবধি জানতে পারবেন না।
উইলিয়াম মূল্য

4
এটি লক্ষ করা উচিত যে এই ধরণের আর্গুমেন্টগুলি প্যারামিটারাইজড টাইপ হলেও এটি কাজ করবে না। উদাহরণস্বরূপ Foo<Bar<Baz>>,। আপনি এমন একটি উদাহরণ তৈরি করবেন ParameterizedTypeImplযা স্পষ্টভাবে তৈরি করা যায় না। সুতরাং, এটি getActualTypeArguments()[0]ফিরে আসছে কিনা তা যাচাই করা ভাল ধারণা ParameterizedType। যদি এটি হয় তবে আপনি কাঁচা টাইপ পেতে চান এবং তার পরিবর্তে একটি উদাহরণ তৈরি করতে চান।
পিষ্ট করুন

106

জাভা 8 এ আপনি এটি Supplierসহজেই অর্জন করতে ক্রিয়ামূলক ইন্টারফেস ব্যবহার করতে পারেন:

class SomeContainer<E> {
  private Supplier<E> supplier;

  SomeContainer(Supplier<E> supplier) {
    this.supplier = supplier;
  }

  E createContents() {
    return supplier.get();
  }
}

আপনি এই শ্রেণিটি এভাবে তৈরি করবেন:

SomeContainer<String> stringContainer = new SomeContainer<>(String::new);

এই String::newলাইনের বাক্য গঠনটি একটি নির্মাতা উল্লেখ

যদি আপনার কনস্ট্রাক্টর আর্গুমেন্ট নেয় তবে আপনি পরিবর্তে ল্যাম্বডা এক্সপ্রেশন ব্যবহার করতে পারেন:

SomeContainer<BigInteger> bigIntegerContainer
    = new SomeContainer<>(() -> new BigInteger(1));

6
ভাল একটা. এটি প্রতিফলন এবং ব্যতিক্রমগুলি চিকিত্সা করা এড়িয়ে চলে।
ব্রুনো লেইট

2
খুব সুন্দর. দুর্ভাগ্যক্রমে অ্যান্ড্রয়েড ব্যবহারকারীদের জন্য, এটির জন্য এপিআই স্তর 24 বা উচ্চতর প্রয়োজন।
মাইকেল আপডেটিকে

1
কম ঝগড়া এবং কার্যকরী পদ্ধতির মতে এটি আমার মতে উত্তর গৃহীত হবে
টমাস

2
… এবং এটি এমনকি এটিরও পুরানো উত্তরের চেয়ে আলাদা নয় যে এর পিছনে প্রযুক্তিগত প্যাটার্নটি জাভা ল্যাম্বডা এক্সপ্রেশন এবং পদ্ধতি রেফারেন্সের তুলনায় আরও পুরানো যখন আপনি আপনার সংকলকটি আপগ্রেড করার পরেও তাদের সাথে সেই পুরানো কোডটি ব্যবহার করতে পারবেন…
হোলার

ন্যায়বিচার করা সম্ভব হবে SomeContainer stringContainer = new SomeContainer(String::new);?
অ্যারন ফ্রাঙ্ক

87

আপনার কাছে বাক্সটি পাস করার জন্য আপনার এক ধরণের বিমূর্ত ফ্যাক্টরির প্রয়োজন হবে:

interface Factory<E> {
    E create();
}

class SomeContainer<E> {
    private final Factory<E> factory;
    SomeContainer(Factory<E> factory) {
        this.factory = factory;
    }
    E createContents() {
        return factory.create();
    }
}

..আর ফ্যাক্টরি.ক্রেট () কেমন দেখাচ্ছে?
ওহাদআর

6
@ ওহাদআর Factory<>একটি ইন্টারফেস এবং তাই কোনও শরীর নেই। মুল বক্তব্যটি হ'ল পদ্ধতিগুলিতে বাক্সটি পাস করার জন্য আপনাকে ইন্ডিয়ারিয়েশনের একটি স্তর প্রয়োজন যা কোনও উদাহরণ তৈরির জন্য প্রয়োজনীয় কোডটি "জানে" না। ধাতব ভাষাগত Classনা Constructorহয়ে প্রতিবিম্বের ফলে পুরো কোডটি আঘাতের দিকে নিয়ে আসে বরং সাধারণ কোড দিয়ে এটি করা আরও ভাল ।
টম হাটিন - ২:29

2
আজকাল আপনি এই জাতীয় পদ্ধতি রেফারেন্স এক্সপ্রেশন দিয়ে একটি কারখানার উদাহরণ তৈরি করতে পারেন:SomeContainer<SomeElement> cont = new SomeContainer<>(SomeElement::new);
লিই

24
package org.foo.com;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Basically the same answer as noah's.
 */
public class Home<E>
{

    @SuppressWarnings ("unchecked")
    public Class<E> getTypeParameterClass()
    {
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }

    private static class StringHome extends Home<String>
    {
    }

    private static class StringBuilderHome extends Home<StringBuilder>
    {
    }

    private static class StringBufferHome extends Home<StringBuffer>
    {
    }   

    /**
     * This prints "String", "StringBuilder" and "StringBuffer"
     */
    public static void main(String[] args) throws InstantiationException, IllegalAccessException
    {
        Object object0 = new StringHome().getTypeParameterClass().newInstance();
        Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
        Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
        System.out.println(object0.getClass().getSimpleName());
        System.out.println(object1.getClass().getSimpleName());
        System.out.println(object2.getClass().getSimpleName());
    }

}

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

3
Java.lang.ClassCastException: দ্বারা সৃষ্ট sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl java.lang.Class কাস্ট করা যাবে না
জুয়ান

@ ডামিয়ানলেস্কজিস্কি-ভ্যাশ এছাড়াও ব্যর্থ হবে, যেমনclass GenericHome<T> extends Home<T>{}
হোলগার

22

আপনার যদি জেনেরিক ক্লাসের মধ্যে কোনও ধরণের আর্গুমেন্টের নতুন উদাহরণের প্রয়োজন হয় তবে আপনার কনস্ট্রাক্টরদের তার শ্রেণীর দাবি করা ...

public final class Foo<T> {

    private Class<T> typeArgumentClass;

    public Foo(Class<T> typeArgumentClass) {

        this.typeArgumentClass = typeArgumentClass;
    }

    public void doSomethingThatRequiresNewT() throws Exception {

        T myNewT = typeArgumentClass.newInstance();
        ...
    }
}

ব্যবহার:

Foo<Bar> barFoo = new Foo<Bar>(Bar.class);
Foo<Etc> etcFoo = new Foo<Etc>(Etc.class);

পেশাদাররা:

  • রবার্টসনের সুপার টাইপ টোকেন (এসটিটি) পদ্ধতির চেয়ে অনেক বেশি সহজ (এবং কম সমস্যাযুক্ত)।
  • এসটিটি পদ্ধতির চেয়ে অনেক বেশি দক্ষ (যা প্রাতঃরাশের জন্য আপনার সেলফোনটি খাবে)।

কনস:

  • ডিফল্ট কনস্ট্রাক্টারে ক্লাস পাস করা যায় না (যার কারণে ফু চূড়ান্ত হয়)। আপনার যদি সত্যিই কোনও ডিফল্ট নির্মাণকারীর প্রয়োজন হয় তবে আপনি সর্বদা একটি সেটার পদ্ধতি যুক্ত করতে পারেন তবে তার পরে আপনাকে তার কল দেওয়ার কথা মনে রাখতে হবে।
  • রবার্টসনের আপত্তি ... একটি কালো ভেড়ার চেয়ে আরও বার (যদিও টাইপ আর্গুমেন্ট ক্লাসটি আরও একবার নির্দিষ্ট করে আপনাকে হত্যা করবে না)। এবং রবার্টসনের দাবির বিপরীতে এটি ডিআরওয়াই অধ্যক্ষকে যাইহোক লঙ্ঘন করে না কারণ সংকলকটি প্রকারের নির্ভুলতা নিশ্চিত করবে।
  • সম্পূর্ণ Foo<L>প্রমাণ নয়। নতুনদের জন্য...newInstance() টাইপ আর্গুমেন্ট শ্রেণিতে যদি ডিফল্ট নির্মাতারা না থাকে তবে একটি ডুবে যাবে। এটি যাইহোক যাইহোক সমস্ত জ্ঞাত সমাধানগুলিতে প্রযোজ্য।
  • এসটিটি পদ্ধতির মোট এনক্যাপসুলেশনের অভাব রয়েছে। যদিও এটি কোনও বড় বিষয় নয় (এসটিটির বিপর্যয়কর পারফরম্যান্স বিবেচনা করে)।

22

আপনি এখন এটি করতে পারেন এবং এতে প্রতিচ্ছবি কোডের একগুচ্ছ প্রয়োজন হয় না।

import com.google.common.reflect.TypeToken;

public class Q26289147
{
    public static void main(final String[] args) throws IllegalAccessException, InstantiationException
    {
        final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
        final String string = (String) smpc.type.getRawType().newInstance();
        System.out.format("string = \"%s\"",string);
    }

    static abstract class StrawManParameterizedClass<T>
    {
        final TypeToken<T> type = new TypeToken<T>(getClass()) {};
    }
}

অবশ্যই যদি আপনাকে এমন কনস্ট্রাক্টর কল করতে হয় যা কিছু প্রতিবিম্বের প্রয়োজন হবে তবে এটি খুব ভাল নথিভুক্ত, এই কৌশলটি নয়!

এখানে TypeToken জন্য JavaDoc


6
এই সমাধানটি সীমিত সংখ্যক মামলার জন্য কাজ করে, ঠিক যেমন প্রতিবিম্বের সাথে @ নোহের জবাব। আমি আজ তাদের সব চেষ্টা করেছি ... এবং আমি প্যারামিটার ক্লাসের একটি উদাহরণ প্যারামিটারাইজড ক্লাসে পৌঁছে দিয়ে শেষ করেছি (নতুন কল্পনা করতে সক্ষম হবার জন্য) (নতুন) ()। "জেনেরিক্স" এর খুব বড় ঘাটতি ... নতুন ফু <বার> (বার.class); ... ক্লাস ফু <T> {বেসরকারী চূড়ান্ত শ্রেণি <টি> এমটিফ্যাক্টরি; ফু (শ্রেণি <T> tClass) T এমটিফ্যাক্টরি = tClass; ...} টি দৃষ্টান্ত = tFactory.newInstance (); }
ইয়ভোলক

এটি সমস্ত ক্ষেত্রে কাজ করে, এমনকি স্থিতিশীল কারখানার পদ্ধতিগুলি যা জেনেরিক পরামিতিগুলি গ্রহণ করে

13

আরও কার্যকরী পদ্ধতির বিষয়ে চিন্তা করুন: কিছু না ছাড়িয়ে কিছু E তৈরি করার পরিবর্তে (যা স্পষ্টভাবে একটি কোডের গন্ধ), এমন একটি ফাংশন পাস করুন যা কীভাবে তৈরি করতে জানে, অর্থাৎ

E createContents(Callable<E> makeone) {
     return makeone.call(); // most simple case clearly not that useful
}

6
প্রযুক্তিগতভাবে আপনি কোনও ফাংশনটি পাস করছেন না, আপনি কোনও ফাংশন অবজেক্ট (একটি ফান্টেক্টর হিসাবেও পরিচিত ) পাস করছেন ।
লর্নি লালিবার্তে

3
অথবা এর পরিবর্তে ক্যাচিং Exceptionব্যবহারকে অতিক্রম করতে Supplier<E>
মার্টিন ডি

10

জাভা টিউটোরিয়াল থেকে - জেনারিকসের উপর বিধিনিষেধ :

প্রকারের পরামিতিগুলির উদাহরণ তৈরি করতে পারে না

আপনি কোনও প্রকারের প্যারামিটারের উদাহরণ তৈরি করতে পারবেন না। উদাহরণস্বরূপ, নিম্নলিখিত কোডটি একটি সংকলন-সময় ত্রুটির সৃষ্টি করে:

public static <E> void append(List<E> list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

কার্যকারণ হিসাবে, আপনি প্রতিবিম্বের মাধ্যমে টাইপ প্যারামিটারের একটি অবজেক্ট তৈরি করতে পারেন:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

আপনি সংযোজন পদ্ধতিটি নিম্নরূপ প্রার্থনা করতে পারেন:

List<String> ls = new ArrayList<>();
append(ls, String.class);

6

আমি এখানে একটি বিকল্প নিয়ে এসেছি, এটি সাহায্য করতে পারে:

public static class Container<E> {
    private Class<E> clazz;

    public Container(Class<E> clazz) {
        this.clazz = clazz;
    }

    public E createContents() throws Exception {
        return clazz.newInstance();
    }
}

সম্পাদনা: বিকল্পভাবে আপনি এই নির্মাণকারীটি ব্যবহার করতে পারেন (তবে এটির জন্য E এর উদাহরণ প্রয়োজন):

@SuppressWarnings("unchecked")
public Container(E instance) {
    this.clazz = (Class<E>) instance.getClass();
}

হ্যাঁ, জেনারিক ছাড়াই এটি একই কাজ করে - জেনারিকের সাথে এই ধারকটির ইনস্ট্যান্টেশনটি কিছুটা রিডান্ট্যান্ট হয়ে যায় (আপনাকে "E" দু'বার কী নির্দিষ্ট করতে হবে)।
ডেভিড সিট্রন

ঠিক আছে, আপনি যখন জাভা এবং জেনেরিক ব্যবহার করেন তখন এটি ঘটে ... সেগুলি সুন্দর নয়, এবং মারাত্মক সীমাবদ্ধতা রয়েছে ...
মাইক স্টোন

6

আপনি যদি ইনস্ট্যান্টেশনের সময় শ্রেণীর নামটি দু'বার টাইপ না করতে চান তবে:

new SomeContainer<SomeType>(SomeType.class);

আপনি কারখানার পদ্ধতি ব্যবহার করতে পারেন:

<E> SomeContainer<E> createContainer(Class<E> class); 

এতে পছন্দ করুন:

public class Container<E> {

    public static <E> Container<E> create(Class<E> c) {
        return new Container<E>(c);
    }

    Class<E> c;

    public Container(Class<E> c) {
        super();
        this.c = c;
    }

    public E createInstance()
            throws InstantiationException,
            IllegalAccessException {
        return c.newInstance();
    }

}

6

জাভা দুর্ভাগ্যক্রমে আপনি যা করতে চান তা অনুমতি দেয় না। অফিসিয়াল কাজ দেখুন :

আপনি কোনও প্রকারের প্যারামিটারের উদাহরণ তৈরি করতে পারবেন না। উদাহরণস্বরূপ, নিম্নলিখিত কোডটি একটি সংকলন-সময় ত্রুটির সৃষ্টি করে:

public static <E> void append(List<E> list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

কার্যকারণ হিসাবে, আপনি প্রতিবিম্বের মাধ্যমে টাইপ প্যারামিটারের একটি অবজেক্ট তৈরি করতে পারেন:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

আপনি সংযোজন পদ্ধতিটি নিম্নরূপ প্রার্থনা করতে পারেন:

List<String> ls = new ArrayList<>();
append(ls, String.class);

আপনি আমাকে দয়া করে বলতে পারেন যে আপনি কেন এমনটা করছেন? আমি দেখতে পাচ্ছি না কেন সরকারী কর্মসংস্থান একটি খারাপ সমাধান। ধন্যবাদ।
নীপসনিকেপ

আমার ধারণা আপনি ভোট নেমে এসেছেন, কারণ আপনার উত্তরটি মূলত জাস্টিন রুডের মতো: stackoverflow.com/a/75254/103412
টর্স্টেন

5

সংকলনের সময় আপনি যখন ইয়ের সাথে কাজ করছেন তখন আপনি প্রকৃত জেনেরিক টাইপ "ই" (যদি আপনি প্রতিবিম্ব ব্যবহার করেন বা জেনেরিক ধরণের বেস ক্লাসের সাথে কাজ করেন) যত্নশীল হন না তাই সাবক্লাসটি E এর উদাহরণ সরবরাহ করতে দিন

Abstract class SomeContainer<E>
{

    abstract protected  E createContents();
    public doWork(){
        E obj = createContents();
        // Do the work with E 

     }
}


BlackContainer extends SomeContainer<Black>{
    Black createContents() {
        return new  Black();
    }
}

4

তুমি ব্যবহার করতে পার:

Class.forName(String).getConstructor(arguments types).newInstance(arguments)

তবে আপনাকে অবশ্যই প্যাকেজ সহ ক্লাসের সঠিক নাম সরবরাহ করতে হবে। java.io.FileInputStream। আমি এটি একটি গণিতের এক্সপ্রেশন পার্সার তৈরি করতে ব্যবহার করেছি।


15
এবং রানটাইমে আপনি জেনেরিক ধরণের সঠিক শ্রেণির নাম কীভাবে পাবেন?
ডেভিড সিট্রন

আপনাকে এই শ্রেণীর উদাহরণ ব্যবহার করে এটি সংরক্ষণ করতে হবে। করণীয়, যদিও সহজেই সুবিধাজনক। যদি আপনার জেনেরিক টাইপ ই একজন সদস্য (অথবা টি বা যাই হোক না কেন), পেয়ে ছিল এটা বাইনারি নাম ঠিক হয় foo.getClass().getName()। এই উদাহরণটি কোথা থেকে আসে? আমি বর্তমানে আমি যে প্রকল্পে কাজ করছি তার একটি নির্মাণকারীর মধ্যে দিয়ে যাচ্ছি।
মার্ক স্টোরার

3

আশা করি এই সাহায্য করতে খুব দেরী হয়নি !!!

জাভা হ'ল টাইপ-সেফটি, কেবলমাত্র অবজেক্ট উদাহরণ তৈরি করতে সক্ষম।

আমার ক্ষেত্রে আমি createContentsপদ্ধতিতে পরামিতিগুলি পাস করতে পারি না । আমার সমাধানটি সমস্ত নম্র উত্তরের পরিবর্তে প্রসারগুলি ব্যবহার করছে।

private static class SomeContainer<E extends Object> {
    E e;
    E createContents() throws Exception{
        return (E) e.getClass().getDeclaredConstructor().newInstance();
    }
}

এটি আমার উদাহরণের ক্ষেত্রে যা আমি পরামিতিগুলি পাস করতে পারি না।

public class SomeContainer<E extends Object> {
    E object;

    void resetObject throws Exception{
        object = (E) object.getClass().getDeclaredConstructor().newInstance();
    }
}

প্রতিচ্ছবি ব্যবহার করে রান টাইম ত্রুটি তৈরি করুন, যদি আপনি কোনও জেনেরিক শ্রেণির সাথে কোনও বস্তুর প্রকার প্রসারিত করেন না। আপনার জেনেরিক প্রকারটি প্রসারিত করতে এই ত্রুটিটিকে সময় ত্রুটি সংকলনে রূপান্তর করতে হবে।


3

TypeToken<T>ক্লাসটি ব্যবহার করুন :

public class MyClass<T> {
    public T doSomething() {
        return (T) new TypeToken<T>(){}.getRawType().newInstance();
    }
}

আপনি যদি জিএসএন এর পরিবর্তে পেয়ারা ব্যবহার করেন তবে এটি কিছুটা আলাদা:(T) new TypeToken<T>(getClass()){}.getRawType().newInstance();
জ্যাকব ভ্যান

2

আমি ভেবেছিলাম আমি এটি করতে পারি, তবে বেশ হতাশ: এটি কাজ করে না, তবে আমি মনে করি এটি ভাগ করে নেওয়া ভাল।

হয়তো কেউ সংশোধন করতে পারেন:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface SomeContainer<E> {
    E createContents();
}

public class Main {

    @SuppressWarnings("unchecked")
    public static <E> SomeContainer<E> createSomeContainer() {
        return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(),
                new Class[]{ SomeContainer.class }, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Class<?> returnType = method.getReturnType();
                return returnType.newInstance();
            }
        });
    }

    public static void main(String[] args) {
        SomeContainer<String> container = createSomeContainer();

    [*] System.out.println("String created: [" +container.createContents()+"]");

    }
}

এটি উৎপন্ন করে:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
    at Main.main(Main.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

লাইন 26 এর সাথে একটি [*]

কেবলমাত্র কার্যকর সমাধানটি হ'ল @ জাস্টিনরুড by


2

@ নোহের উত্তরের একটি ইমপ্রোভমেন্ট।

পরিবর্তনের কারণ

a] যদি আপনি অর্ডার পরিবর্তন করেন তবে আরও 1 জেনেরিক প্রকার ব্যবহার করা বেশি নিরাপদ।

খ] একটি শ্রেণীর জেনেরিক ধরণের স্বাক্ষর সময়ে সময়ে পরিবর্তিত হয় যাতে রানটাইমে অব্যক্ত ব্যতিক্রমগুলি দেখে আপনি অবাক হবেন না।

দৃust় কোড

public abstract class Clazz<P extends Params, M extends Model> {

    protected M model;

    protected void createModel() {
    Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
    for (Type type : typeArguments) {
        if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
            try {
                model = ((Class<M>) type).newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

অথবা ওয়ান লাইনার ব্যবহার করুন

একটি লাইন কোড

model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();

2

আপনি যা করতে পারেন তা হ'ল -

  1. প্রথমে সেই জেনেরিক বর্গের পরিবর্তনশীল ঘোষণা করুন

    ২.এর পরে এটির কনস্ট্রাক্টর তৈরি করুন এবং সেই অবজেক্টটি ইনস্ট্যান্ট করুন

  2. তারপরে আপনি যেখানেই এটি ব্যবহার করতে চান তা ব্যবহার করুন

নিদর্শন

1

private Class<E> entity;

2

public xyzservice(Class<E> entity) {
        this.entity = entity;
    }



public E getEntity(Class<E> entity) throws InstantiationException, IllegalAccessException {
        return entity.newInstance();
    }

3।

E e = getEntity (সত্তা);


0

যেমনটি আপনি বলেছিলেন, মুছে ফেলার কারণে আপনি সত্যিই এটি করতে পারবেন না। আপনি এটি প্রতিস্থাপন ব্যবহার করে বাছাই করতে পারেন তবে এটির জন্য প্রচুর কোড এবং প্রচুর ত্রুটি পরিচালনার প্রয়োজন।


আপনি কিভাবে প্রতিবিম্ব ব্যবহার করে এটি করবেন? আমি দেখি একমাত্র পদ্ধতিটি Class.getTypeParaters (), তবে এটি কেবল ঘোষিত প্রকারগুলি প্রদান করে, রান-টাইম ধরণের নয়।
ডেভিড সিট্রন

আপনি এই সম্পর্কে কথা বলছেন? artima.com/weblogs/viewpost.jsp?thread=208860
ডেভিড সিট্রন

0

আপনি যদি বলতে চান new E() তবে এটি অসম্ভব। এবং আমি যুক্ত করব যে এটি সর্বদা সঠিক নয় - আপনি কীভাবে জানবেন যে E এর সর্বজনীন নো-আরগস নির্মাণকারী রয়েছে? তবে আপনি সর্বদা সৃজনকে অন্য কোনও শ্রেণীর কাছে প্রতিনিধি দিতে পারেন যা কোনও উদাহরণ তৈরি করতে জানে - এটি হতে পারে Class<E>বা আপনার পছন্দসই কোডটি এটি হতে পারে

interface Factory<E>{
    E create();
}    

class IntegerFactory implements Factory<Integer>{    
  private static int i = 0; 
  Integer create() {        
    return i++;    
  }
}

0
return   (E)((Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();

1
এটি আমার প্রশ্নে মূল প্রশ্নে কাজ করে না। জন্য সুপারক্লাস SomeContainerসহজভাবে হয় Object। অতএব, this.getClass().getGenericSuperclass()একটি Class(শ্রেণি java.lang.Object) প্রদান করে, একটি নয় ParameterizedType। এটি ইতিমধ্যে পিয়ার উত্তর stackoverflow.com/questions/75175/… দ্বারা ইতিমধ্যে চিহ্নিত করা হয়েছিল ।
ডেভিড সিট্রন

1
সম্পূর্ণ ভুল: থ্রেডে "মূল" java.lang.ClassCastException: java.lang.Class java.lang.reflect.ParameterizedType এ আটকানো যাবে না
অউবিন

0

আপনি নিম্নলিখিত স্নিপেট দিয়ে এটি অর্জন করতে পারেন:

import java.lang.reflect.ParameterizedType;

public class SomeContainer<E> {
   E createContents() throws InstantiationException, IllegalAccessException {
      ParameterizedType genericSuperclass = (ParameterizedType)
         getClass().getGenericSuperclass();
      @SuppressWarnings("unchecked")
      Class<E> clazz = (Class<E>)
         genericSuperclass.getActualTypeArguments()[0];
      return clazz.newInstance();
   }
   public static void main( String[] args ) throws Throwable {
      SomeContainer< Long > scl = new SomeContainer<>();
      Long l = scl.createContents();
      System.out.println( l );
   }
}

4
সম্পূর্ণ ভুল: থ্রেডে "মূল" java.lang.ClassCastException: java.lang.Class java.lang.reflect.ParameterizedType এ আটকানো যাবে না
অউবিন

0

Eরবার্টসন নিবন্ধটি যেমন আলোচিত হয়েছে তেমন কৌশল ব্যবহার করে আপনার জন্য সমাধান করতে পারে এমন বিভিন্ন গ্রন্থাগার রয়েছে । ই এর দ্বারা প্রতিনিধিত্ব করা কাঁচা শ্রেণীর সমাধান করতে এখানে টাইপটুলগুলিcreateContents ব্যবহার করার একটি প্রয়োগ রয়েছে :

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

এটি ধরে নিয়েছে যে getClass () সামারকন্টেইনারের একটি সাবক্লাসে সমাধান করে এবং অন্যথায় ব্যর্থ হবে যেহেতু ই এর প্রকৃত প্যারামিটারাইজড মান রানটাইমগুলিতে মুছে ফেলা হবে যদি এটি সাবক্লাসে ক্যাপচার না করা হয়।


0

এখানে এমন একটি বাস্তবায়ন রয়েছে createContentsযা দ্বারা প্রতিনিধিত্ব করা কাঁচা শ্রেণীর সমাধান করতে টাইপটুলগুলি ব্যবহার করে E:

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

এই পদ্ধতিটি কেবল তখন সাবস্ক্লসড থাকলে কাজ করে SomeContainerতাই এর প্রকৃত মান Eটাইপ সংজ্ঞায় ধরা পড়ে:

class SomeStringContainer extends SomeContainer<String>

অন্যথায় E এর মান রানটাইমের সময় মুছে ফেলা হয় এবং পুনরুদ্ধারযোগ্য নয়।


-1

আপনি ক্লাসলোডার এবং শ্রেণীর নাম দিয়ে শেষ পর্যন্ত কিছু প্যারামিটার দিয়ে নিতে পারেন।

final ClassLoader classLoader = ...
final Class<?> aClass = classLoader.loadClass("java.lang.Integer");
final Constructor<?> constructor = aClass.getConstructor(int.class);
final Object o = constructor.newInstance(123);
System.out.println("o = " + o);

এই মাত্র বর্গ বস্তুর ক্ষণস্থায়ী চেয়েও কঠিন অপরাধ
newacct

আপনার মোটেই ক্লাস লোডারটি স্পষ্টভাবে উল্লেখ করার দরকার নেই।
স্টিফান রেইচ

-1

এখানে একটি উন্নত সমাধান, উপর ভিত্তি করে ParameterizedType.getActualTypeArguments ইতিমধ্যে @noah, @ লার্স বোহল এবং আরও কিছু দ্বারা উল্লিখিত হয়েছে।

বাস্তবায়নে প্রথম ছোট উন্নতি। কারখানার উদাহরণ না দিয়ে ফিরে আসা উচিত, তবে একধরণের। ব্যবহারের Class.newInstance()সুযোগ হ্রাস করে আপনি উদাহরণটি ফিরে আসার সাথে সাথে soon কারণ কেবল নো-আর্গুমেন্ট কনস্ট্রাক্টরদের এভাবেই প্রার্থনা করা যেতে পারে। আরও ভাল উপায় হ'ল কোনও প্রকার ফেরত দেওয়া এবং কোনও ক্লায়েন্টকে চয়ন করার অনুমতি দেওয়া, তিনি কোন নির্মাতাকে ডাকতে চান:

public class TypeReference<T> {
  public Class<T> type(){
    try {
      ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
      if (pt.getActualTypeArguments() == null || pt.getActualTypeArguments().length == 0){
        throw new IllegalStateException("Could not define type");
      }
      if (pt.getActualTypeArguments().length != 1){
        throw new IllegalStateException("More than one type has been found");
      }
      Type type = pt.getActualTypeArguments()[0];
      String typeAsString = type.getTypeName();
      return (Class<T>) Class.forName(typeAsString);

    } catch (Exception e){
      throw new IllegalStateException("Could not identify type", e);
    }

  }
}

এখানে ব্যবহারের উদাহরণ দেওয়া হল। @ লার্স বোহাল সম্প্রসারনের মাধ্যমে পুনরায় সংশোধিত জেনেরিক পাওয়ার জন্য কেবলমাত্র একটি সহজ উপায় দেখিয়েছে। @ নোহ শুধুমাত্র সাথে উদাহরণ তৈরি করার মাধ্যমে {}। উভয় ক্ষেত্রেই প্রদর্শন করার জন্য এখানে পরীক্ষা দেওয়া হচ্ছে:

import java.lang.reflect.Constructor;

public class TypeReferenceTest {

  private static final String NAME = "Peter";

  private static class Person{
    final String name;

    Person(String name) {
      this.name = name;
    }
  }

  @Test
  public void erased() {
    TypeReference<Person> p = new TypeReference<>();
    Assert.assertNotNull(p);
    try {
      p.type();
      Assert.fail();
    } catch (Exception e){
      Assert.assertEquals("Could not identify type", e.getMessage());
    }
  }

  @Test
  public void reified() throws Exception {
    TypeReference<Person> p = new TypeReference<Person>(){};
    Assert.assertNotNull(p);
    Assert.assertEquals(Person.class.getName(), p.type().getName());
    Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
    Assert.assertNotNull(ctor);
    Person person = (Person) ctor.newInstance(NAME);
    Assert.assertEquals(NAME, person.name);
  }

  static class TypeReferencePerson extends TypeReference<Person>{}

  @Test
  public void reifiedExtenension() throws Exception {
    TypeReference<Person> p = new TypeReferencePerson();
    Assert.assertNotNull(p);
    Assert.assertEquals(Person.class.getName(), p.type().getName());
    Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
    Assert.assertNotNull(ctor);
    Person person = (Person) ctor.newInstance(NAME);
    Assert.assertEquals(NAME, person.name);
  }
}

নোট: তোমাদের মধ্যে ক্লায়েন্টদের জোর করতে পারেন TypeReferenceসবসময় ব্যবহার {}যখন উদাহরণস্বরূপ এই শ্রেণীর বিমূর্ত করে নির্মিত হয়: public abstract class TypeReference<T>। আমি এটি করিনি, কেবল মুছে যাওয়া পরীক্ষার কেসটি দেখানোর জন্য।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.