জাভা Class.cast () বনাম কাস্ট অপারেটর


107

সি-স্টাইলের কাস্ট অপারেটরের দুষ্টতা সম্পর্কে আমার সি ++ দিন পড়ানোর পরে আমি প্রথমে সন্তুষ্ট হয়ে জানতে পেরেছিলাম যে জাভা 5 তে java.lang.Classএকটি castপদ্ধতি অর্জন করেছে ।

আমি ভেবেছিলাম অবশেষে weালাইয়ের সাথে আমাদের আচরণ করার একটি ওও উপায় আছে।

দেখা যাচ্ছে Class.castযে static_castসি ++ এর মতো নয়। এটা আরও ভালো লেগেছে reinterpret_cast। এটি সংকলন ত্রুটি তৈরি করবে না যেখানে এটি প্রত্যাশিত এবং পরিবর্তে রানটাইম স্থগিত করবে। বিভিন্ন আচরণের প্রদর্শনের জন্য এখানে একটি সাধারণ পরীক্ষার কেস।

package test;

import static org.junit.Assert.assertTrue;

import org.junit.Test;


public class TestCast
{
    static final class Foo
    {
    }

    static class Bar
    {
    }

    static final class BarSubclass
        extends Bar
    {
    }

    @Test
    public void test ( )
    {
        final Foo foo = new Foo( );
        final Bar bar = new Bar( );
        final BarSubclass bar_subclass = new BarSubclass( );

        {
            final Bar bar_ref = bar;
        }

        {
            // Compilation error
            final Bar bar_ref = foo;
        }
        {
            // Compilation error
            final Bar bar_ref = (Bar) foo;
        }

        try
        {
            // !!! Compiles fine, runtime exception
            Bar.class.cast( foo );
        }
        catch ( final ClassCastException ex )
        {
            assertTrue( true );
        }

        {
            final Bar bar_ref = bar_subclass;
        }

        try
        {
            // Compiles fine, runtime exception, equivalent of C++ dynamic_cast
            final BarSubclass bar_subclass_ref = (BarSubclass) bar;
        }
        catch ( final ClassCastException ex )
        {
            assertTrue( true );
        }
    }
}

সুতরাং, এই আমার প্রশ্ন।

  1. Class.cast()জেনারিক্সের জমিতে নিষিদ্ধ করা উচিত ? সেখানে এটির বেশ কয়েকটি বৈধ ব্যবহার রয়েছে।
  2. সংকলকগণ যখন Class.cast()ব্যবহৃত হয় তখন সংকলন ত্রুটিগুলি উত্পন্ন করা উচিত এবং সংকলনের সময় অবৈধ পরিস্থিতি নির্ধারণ করা যেতে পারে?
  3. জাভা কি সি ++ এর অনুরূপ ভাষা নির্মাণের জন্য একটি কাস্ট অপারেটর সরবরাহ করতে পারে?

4
সরল উত্তর: (1) "জেনারিক্স ল্যান্ড" কোথায়? কাস্ট অপারেটর এখন কীভাবে ব্যবহার করা হয় তার থেকে এটি কীভাবে আলাদা? (2) সম্ভবত। কিন্তু কখনও লিখিত সমস্ত Java কোড 99%, এটা অত্যন্ত যে কেউ ব্যবহার করতে পারে অসম্ভাব্য Class.cast()যখন অবৈধ অবস্থার কম্পাইল সময়ে নির্ধারিত করা যেতে পারে। সেক্ষেত্রে প্রত্যেকে কিন্তু আপনি কেবল স্ট্যান্ডার্ড কাস্ট অপারেটর ব্যবহার করেন। (3) জাভাতে ভাষা নির্মাণ হিসাবে কাস্ট অপারেটর থাকে। এটি সি ++ এর মতো নয়। এর কারণ জাভার অনেকগুলি ভাষা নির্মান সি ++ এর মতো নয়। অতিমাত্রায় মিল থাকলেও জাভা এবং সি ++ একেবারেই আলাদা।
ড্যানিয়েল প্রাইডেন

উত্তর:


117

আমি কেবল কখনও Class.cast(Object)"জেনেরিকস ল্যান্ড" এর সতর্কতা এড়াতে ব্যবহার করেছি । আমি প্রায়শই পদ্ধতিগুলি এ জাতীয় জিনিসগুলি করতে দেখি:

@SuppressWarnings("unchecked")
<T> T doSomething() {
    Object o;
    // snip
    return (T) o;
}

এটিকে প্রতিস্থাপন করা প্রায়শই সেরা:

<T> T doSomething(Class<T> cls) {
    Object o;
    // snip
    return cls.cast(o);
}

Class.cast(Object)আমি কখনও এসেছি জন্য এটি একমাত্র ব্যবহারের কেস ।

সংকলক সতর্কতা সম্পর্কিত: আমার সন্দেহ যে Class.cast(Object)এটি সংকলকটির পক্ষে বিশেষ নয়। স্থিতিশীলভাবে ব্যবহার করার সময় এটি অপ্টিমাইজ করা যেতে পারে (এর Foo.class.cast(o)চেয়ে বরং cls.cast(o)) তবে আমি কখনই এটি ব্যবহার করে দেখিনি - যা এই অপটিমাইজেশনটি সংযোজকটিতে কিছুটা নিরর্থক করার চেষ্টা করে।


8
আমি মনে করি এই ক্ষেত্রে সঠিক উপায়টি হ'ল প্রথমে এর মতো চেকের উদাহরণ করা: যদি (cls.isInstance (o)) {cls.cast (o); You're আপনি যদি নিশ্চিত হন তবে প্রকারটি অবশ্যই সঠিক হবে।
পুস

1
দ্বিতীয় রূপটি কেন ভাল? প্রথম ভেরিয়েন্টটি আরও কার্যকর নয় কারণ কলারের কোড যাইহোক গতিশীল doালাই করবে?
ব্যবহারকারী 1944408

1
@ ব্যবহারকারী1944408 যতক্ষণ আপনি কঠোরভাবে পারফরম্যান্স সম্পর্কে কথা বলছেন এটি হতে পারে, যদিও এটি যথেষ্ট তুচ্ছ। ক্লাসকাস্টএক্সেপশন পাওয়ার ধারণাটি আমি পছন্দ করব না যেখানে যেখানে সুস্পষ্ট কেস নেই। অতিরিক্তভাবে, দ্বিতীয়টি আরও ভাল কাজ করে যেখানে সংকলক টি অনুমান করতে পারে না, উদাহরণস্বরূপ list.add (এটি। <স্ট্রিং> doSomething ()) বনাম list.add (doSomething (স্ট্রিংক্লাস))
sfussnegger

2
আপনি যখন ক্লাইস.কাস্ট (ও) কল করবেন তখন আপনি ক্লাসকাস্টএক্সেপশন পেতে পারেন যখন আপনি সংকলনের সময় কোনও সতর্কতা পাচ্ছেন না। আমি প্রথম বৈকল্পিক পছন্দ করি তবে আমি কাস্টিং না করতে পারলে নাল ফেরার জন্য যখন আমার প্রয়োজন হয় তখন আমি দ্বিতীয় বৈকল্পটি ব্যবহার করব। সেক্ষেত্রে আমি ক্লাইস কাস্ট (ও) কে একটি ট্রাই ধরার ব্লকে আবদ্ধ করব। আমি আপনার সাথেও একমত যে সংকলক টি অনুমান করতে না পারলে এটি আরও ভাল the উত্তরের জন্য ধন্যবাদ।
ব্যবহারকারী 1944408

1
যখন আমার ক্লাসটি প্রয়োজন তখন আমি দ্বিতীয় বৈকল্পটিও ব্যবহার করি <T> ক্লিস্টগুলি গতিশীল হওয়ার জন্য, উদাহরণস্বরূপ যদি আমি প্রতিবিম্ব ব্যবহার করি তবে অন্য সমস্ত ক্ষেত্রে আমি প্রথমটিকে পছন্দ করি। আমি অনুমান করি যে এটি কেবল একটি ব্যক্তিগত স্বাদ।
ব্যবহারকারী 1944408

20

প্রথমত, আপনি প্রায় কোনও কাস্ট করতে কঠোরভাবে নিরুৎসাহিত হন, তাই আপনার এটি যতটা সম্ভব সীমাবদ্ধ করা উচিত! আপনি জাভার সংকলন-সময় দৃ strongly়-টাইপযুক্ত বৈশিষ্ট্যগুলির সুবিধা হারাবেন।

যে কোনও ক্ষেত্রে, Class.cast()প্রধানত আপনি যখন Classপ্রতিফলনের মাধ্যমে টোকেনটি পুনরুদ্ধার করেন তখন ব্যবহার করা উচিত । এটি লিখতে আরও বুদ্ধিমানের

MyObject myObject = (MyObject) object

বরং

MyObject myObject = MyObject.class.cast(object)

সম্পাদনা: সংকলনের সময় ত্রুটি

সর্বোপরি, জাভা কেবল রান সময়ে কাস্ট চেকগুলি সম্পাদন করে। যাইহোক, সংকলক একটি ত্রুটি জারি করতে পারে যদি এটি প্রমাণ করতে পারে যে এই জাতীয় কাস্টগুলি কখনই সফল হতে পারে না (উদাহরণস্বরূপ, অন্য শ্রেণীর জন্য একটি শ্রেণি নিক্ষেপ করুন যা সুপারটাইপ নয় এবং শ্রেণি / ইন্টারফেসে একটি চূড়ান্ত শ্রেণীর ধরণ ফেলে যা এটি ধরণের শ্রেণিবদ্ধ নয়) not এখানে যেহেতু Fooএবং Barএমন ক্লাস যা একে অপরের শ্রেণিবিন্যাসে নেই, theালাই কখনও সফল হতে পারে না।


আমি পুরোপুরি সম্মত হই যে কাস্টগুলি অল্প পরিমাণে ব্যবহার করা উচিত, এজন্য সহজেই অনুসন্ধান করা যায় এমন কিছু থাকা কোড রিফ্যাক্টরিং / রক্ষণাবেক্ষণের জন্য খুব উপকারী হবে। তবে সমস্যাটি হ'ল যদিও প্রথম নজরে Class.castএটি বিলটি ফিট করে বলে মনে হচ্ছে এটি সমাধানের চেয়ে আরও বেশি সমস্যা তৈরি করে।
আলেকজান্ডার পোগ্রেবন্যাক

16

এটি সবসময় সমস্যাযুক্ত এবং প্রায়শই ভাষাগুলির মধ্যে রচনাগুলি এবং ধারণাগুলি অনুবাদ এবং অনুবাদ করার চেষ্টা করে বিভ্রান্তিমূলক। Ingালাই ব্যতিক্রম নয়। বিশেষত জাভা একটি গতিশীল ভাষা এবং সি ++ কিছুটা আলাদা বলে কারণ।

জাভাতে সমস্ত কাস্টিং, আপনি এটি কীভাবেই করেন না কেন রানটাইমে করা হয়। টাইপ তথ্য রানটাইম এ অনুষ্ঠিত হয়। সি ++ হ'ল কিছুটা মিশ্রণ। আপনি অন্যটিতে সি ++ তে একটি কাঠামো নিক্ষেপ করতে পারেন এবং এটি কেবল সেই স্ট্রোকগুলি উপস্থাপন করে এমন বাইটগুলির একটি পুনরায় ব্যাখ্যা। জাভা সেভাবে কাজ করে না।

এছাড়াও জাভা এবং সি ++ এর জেনেরিকগুলি সম্পূর্ণ আলাদা। আপনি জাভাতে কীভাবে সি ++ জিনিস করেন সে বিষয়ে নিজেকে অতিরিক্ত চিন্তা করবেন না। আপনার জাভা উপায়ে কীভাবে কাজ করতে হয় তা শিখতে হবে।


সমস্ত তথ্য রানটাইমে রাখা হয় না। আপনি আমার উদাহরণ থেকে দেখতে পারেন যে (Bar) fooসংকলন সময়ে একটি ত্রুটি উত্পন্ন, কিন্তু Bar.class.cast(foo)না। আমার মতে এটি যদি এই পদ্ধতিতে ব্যবহার করা হয় তবে এটি করা উচিত।
আলেকজান্ডার পোগ্রেবন্যাক

5
@ আলেকজান্ডার পোগ্রেবন্যাক: তা হলে আর করবেন না! Bar.class.cast(foo)স্পষ্টভাবে সংকলককে বলে যে আপনি রানটাইমে কাস্ট করতে চান। আপনি যদি কাস্টের বৈধতার উপর একটি সংকলন-সময় পরীক্ষা করতে চান তবে আপনার একমাত্র পছন্দ (Bar) fooস্টাইল কাস্ট করা।
ড্যানিয়েল প্রাইডেন

আপনি কি মনে করেন একইভাবে করার উপায় কী? যেহেতু জাভা একাধিক শ্রেণীর উত্তরাধিকার সমর্থন করে না।
ইয়ামুর

13

Class.cast()জাভা কোডে খুব কমই ব্যবহৃত হয়। যদি এটি ব্যবহৃত হয় তবে সাধারণত রান টাইমে (যেমন স্ব স্ব Classবস্তুগুলির মাধ্যমে এবং কোনও প্রকারের প্যারামিটার দ্বারা পরিচিত) টাইপগুলি ব্যবহার করা হয়। এটি জেনেরিকগুলি ব্যবহার করে এমন কোডটিতে এটি কেবলমাত্র কার্যকর (এটি কারণ এটি আগে প্রবর্তিত হয়নি)।

এটা না অনুরূপ reinterpret_castকারণ এটি করবে না আপনি কোন একটি স্বাভাবিক ঢালাই করে চেয়ে রানটাইম এ ধরনের ব্যবস্থা ভেঙ্গে করার অনুমতি দেয় (যেমন আপনি পারেন বিরতি জেনেরিক টাইপ পরামিতি, কিন্তু না করতে পারেন বিরতি "বাস্তব" ধরনের)।

সি-স্টাইলের কাস্ট অপারেটরের কুফলগুলি সাধারণত জাভাতে প্রয়োগ হয় না। সি-স্টাইলের কাস্টের মতো দেখতে থাকা জাভা কোড জাভাতে dynamic_cast<>()একটি রেফারেন্স টাইপের সাথে সাদৃশ্যপূর্ণ (মনে রাখবেন: জাভাতে রানটাইম টাইপের তথ্য রয়েছে)।

সাধারণত জাভা castালাইয়ের সাথে সি ++ ingালাই অপারেটরগুলির তুলনা করা বেশ শক্ত কারণ জাভাতে আপনি কেবল কখনও রেফারেন্স দিতে পারেন এবং কখনও কোনও বস্তুর সাথে কোনও রূপান্তর ঘটে না (কেবলমাত্র প্রাথমিক মানগুলি এই সিনট্যাক্সটি ব্যবহার করে রূপান্তর করা যেতে পারে)।


dynamic_cast<>()একটি রেফারেন্স টাইপ সহ।
টম হাটিন -

@ টম: এডিটটি কি সঠিক? আমার সি ++ খুব মরিচা, আমাকে এটির অনেকগুলি পুনরায় গুগল করতে হয়েছিল ;-)
জোচিম সাউর

+1 এর জন্য: "সি-স্টাইলের কাস্ট অপারেটরের দুষ্টতা সাধারণত জাভাতে প্রয়োগ হয় না।" কিছুটা সত্য. আমি প্রশ্নটিতে একটি মন্তব্য হিসাবে ঠিক এই শব্দগুলি পোস্ট করতে চলেছিলাম।
ড্যানিয়েল প্রাইডেন

4

সাধারণত কাস্ট অপারেটরটি ক্লাস # কাস্ট পদ্ধতির চেয়ে বেশি পছন্দ করা হয় কারণ এটি আরও সংক্ষিপ্ত এবং কোডটি সহ অস্পষ্ট সমস্যাগুলি ছড়িয়ে দেওয়ার জন্য সংকলক দ্বারা বিশ্লেষণ করা যেতে পারে।

ক্লাস # কাস্ট সংকলনের সময় রান-টাইমে টাইপ চেক করার দায়িত্ব নেয়।

ক্লাস # কাস্টের জন্য অবশ্যই ব্যবহারের কেস রয়েছে, বিশেষত এটি যখন প্রতিফলিত অপারেশনের ক্ষেত্রে আসে।

যেহেতু ল্যাম্বদা জাভাতে এসেছে আমি ব্যক্তিগতভাবে ক্লাস # কাস্ট ব্যবহার / সংগ্রহ স্ট্রিম এপিআই দিয়ে পছন্দ করি যদি আমি বিমূর্ত প্রকারের সাথে কাজ করি, উদাহরণস্বরূপ।

Dog findMyDog(String name, Breed breed) {
    return lostAnimals.stream()
                      .filter(Dog.class::isInstance)
                      .map(Dog.class::cast)
                      .filter(dog -> dog.getName().equalsIgnoreCase(name))
                      .filter(dog -> dog.getBreed() == breed)
                      .findFirst()
                      .orElse(null);
}

3

সি ++ এবং জাভা বিভিন্ন ভাষা।

জাভা সি-স্টাইলের কাস্ট অপারেটর সি / সি ++ সংস্করণের চেয়ে অনেক বেশি সীমাবদ্ধ। কার্যকরভাবে জাভা কাস্ট হ'ল সি ++ ডায়নামিক_কাস্টের মতো যদি আপনার অবজেক্টটি নতুন ক্লাসে কাস্ট করা যায় না তবে আপনি রান সময় পাবেন (বা কোডটিতে একটি সংকলনের সময় যথেষ্ট তথ্য রয়েছে) ব্যতিক্রম পাবেন। সুতরাং সি টাইপ ক্যাসেট না ব্যবহারের সি ++ ধারণা জাভাতে ভাল ধারণা নয়


0

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

উদাহরণস্বরূপ পরিষেবাদি বস্তুগুলি তৈরি করার সময় এই কৌশলটি ব্যবহার করুন, এস পি = সার্ভিস.কাস্ট (সিএনইউইনস্ট্যান্স ()) দেখুন; SP = (S) c.newInstance () এ যখন এটি একটি শ্রেণীর কাস্ট ব্যতিক্রম ছুঁড়ে ফেলবে; ' সতর্কতা টাইপ করুন: অবজেক্ট থেকে এস-তে চেক করা কাস্ট করা' (অবজেক্ট পি = (অবজেক্ট) c.newInstance ();) এর মতোই কোনও সতর্কতা দেখাবে না এবং দেখাতে পারে না

-সামান্য এটি পরীক্ষা করে যে কাস্ট করা বস্তুটি ingালাই ক্লাসের উদাহরণ, তবে এটি কাস্টার অপারেটরটিকে চাপ দিয়ে সতর্কতাটি কাস্ট করতে এবং আড়াল করতে ব্যবহার করবে।

গতিশীল কাস্টের জন্য জাভা বাস্তবায়ন:

@SuppressWarnings("unchecked")
public T cast(Object obj) {
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}




    private S nextService() {
        if (!hasNextService())
            throw new NoSuchElementException();
        String cn = nextName;
        nextName = null;
        Class<?> c = null;
        try {
            c = Class.forName(cn, false, loader);
        } catch (ClassNotFoundException x) {
            fail(service,
                 "Provider " + cn + " not found");
        }
        if (!service.isAssignableFrom(c)) {
            fail(service,
                 "Provider " + cn  + " not a subtype");
        }
        try {
            S p = service.cast(c.newInstance());
            providers.put(cn, p);
            return p;
        } catch (Throwable x) {
            fail(service,
                 "Provider " + cn + " could not be instantiated",
                 x);
        }
        throw new Error();          // This cannot happen
    }

0

ব্যক্তিগতভাবে, আমি POJO রূপান্তরকারীকে JSON তৈরি করার আগে এটি ব্যবহার করেছি। ফাংশনটির সাথে প্রক্রিয়াকৃত জেএসওনঅবজেক্টে একটি অ্যারে বা নেস্টেড জেএসওনোবজেক্টস রয়েছে (বোঝা যাচ্ছে যে এখানে ডেটা কোনও আদিম ধরণের নয় বা String), আমি class.cast()এই ফ্যাশনটি ব্যবহার করে সেটার পদ্ধতিটি আহ্বান করার চেষ্টা করি :

public static Object convertResponse(Class<?> clazz, JSONObject readResultObject) {
    ...
    for(Method m : clazz.getMethods()) {
        if(!m.isAnnotationPresent(convertResultIgnore.class) && 
            m.getName().toLowerCase().startsWith("set")) {
        ...
        m.invoke(returnObject,  m.getParameters()[0].getClass().cast(convertResponse(m.getParameters()[0].getType(), readResultObject.getJSONObject(key))));
    }
    ...
}

এটি চূড়ান্তভাবে সহায়ক কিনা তা নিশ্চিত না, তবে যেমনটি আগে এখানে বলেছি, প্রতিফলন হ'ল class.cast()আমি যে কয়েকটি বৈধ ব্যবহারের ক্ষেত্রে ভাবতে পারি তার মধ্যে একটি, কমপক্ষে আপনার এখন অন্য একটি উদাহরণ রয়েছে।

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