সুপার ক্লাস থেকে সাবক্লাসে সুস্পষ্ট কাস্টিং


161
public class Animal {
    public void eat() {}
}

public class Dog extends Animal {
    public void eat() {}

    public void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = (Dog) animal;
    }
}

অ্যাসাইনমেন্টটি Dog dog = (Dog) animal;একটি সংকলন ত্রুটি উত্পন্ন করে না, তবে রানটাইমে এটি একটি উত্পন্ন করে ClassCastException। সংকলক কেন এই ত্রুটিটি সনাক্ত করতে পারে না?


51
আপনি ত্রুটিটি সনাক্ত করতে সংকলককে বলছেন।
মৌরিসিও

উত্তর:


326

একটি কাস্ট ব্যবহার করে আপনি মূলত সংকলককে বলছেন "আমার উপর আস্থা রাখুন। আমি একজন পেশাদার, আমি কী করছি তা আমি জানি এবং আমি জানি যে আপনি এটির গ্যারান্টি দিতে না পারলেও, আমি আপনাকে বলছি যে এটি animal পরিবর্তনশীলটি অবশ্যই একটি কুকুর হতে যাচ্ছে। "

যেহেতু প্রাণীটি আসলে কুকুর নয় (এটি একটি প্রাণী, তাই আপনি করতে পারেন) Animal animal = new Dog(); এবং এটি একটি কুকুর হতে চাই) ভিএম রানটাইমের সময় একটি ব্যতিক্রম ছুঁড়েছে কারণ আপনি সেই বিশ্বাস লঙ্ঘন করেছেন (আপনি কম্পাইলারকে বলেছিলেন যে সবকিছু ঠিক আছে এবং এটি না!)

সংকলকটি সবকিছু অন্ধভাবে গ্রহণ করার চেয়ে কিছুটা স্মার্ট,

যেহেতু আপনি মূলত কেবল কম্পাইলারকে অভিযোগ করা থেকে বিরত করছেন, প্রতিবার আপনি যখন কাস্ট করেছিলেন এটি পরীক্ষা করা গুরুত্বপূর্ণ যে আপনি যদি একটি বিবৃতিতে (বা সেই প্রভাবটির কোনও কিছু) ClassCastExceptionব্যবহার instanceofকরে কোনও কারণ তৈরি করেন না check


ধন্যবাদ কিন্তু আপনি কুকুর প্রয়োজন যদি না হয়, কাজ না :) প্রাণী থেকে প্রসারিত
delive

66
আপনি এটি যেভাবে নাটকীয় করেছেন তা আমি পছন্দ করি
হেন্দ্র অ্যাংগ্রিয়ান

3
অবশ্যই আপনি করবেন @delive কিন্তু প্রশ্ন অনুযায়ী, Dog নেই থেকে প্রসারিত Animal!
মাইকেল বেরি

52

কারণ তাত্ত্বিক Animal animal করতে একটি কুকুর হতে:

Animal animal = new Dog();

সাধারণত, ডাউন কাস্টিং কোনও ভাল ধারণা নয়। আপনি এটি এড়ানো উচিত। আপনি যদি এটি ব্যবহার করেন তবে আপনি আরও ভালভাবে একটি চেক অন্তর্ভুক্ত করুন:

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
}

তবে নিম্নলিখিত কোডটি সংকলনের ত্রুটি উত্পন্ন করে কুকুর কুকুর = নতুন প্রাণী (); (বেমানান প্রকারের) .কিন্তু এই পরিস্থিতিতে সংকলক প্রাণীকে সনাক্ত করে একটি সুপার ক্লাস এবং কুকুরটি একটি সাবক্লাস so সুতরাং কাজটি ভুল। এটি গ্রহণ করে। দয়া করে আমাকে এই সম্পর্কে ব্যাখ্যা করুন
সরওয়ান

3
হ্যাঁ, কারণ প্রাণী সুপারক্লাস। প্রতিটি প্রাণীই কুকুর নয়, তাই না? আপনি ক্লাসগুলি কেবল তাদের ধরণের বা তাদের সুপার টাইপ দ্বারা উল্লেখ করতে পারেন। তাদের উপপ্রকার নয়।
বোজহো

43

এই ধরণের ClassCastException এড়াতে আপনার যদি থাকে:

class A
class B extends A

আপনি বি তে এমন একটি কনস্ট্রাক্টর সংজ্ঞায়িত করতে পারেন যা এ এর ​​একটি অবজেক্ট নেয় আমরা এভাবে "কাস্ট" করতে পারি যেমন:

public B(A a) {
    super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
    // If B class has more attributes, then you would initilize them here
}

24

মাইকেল বেরির দেওয়া উত্তরটি বিশদভাবে বর্ণনা করা।

Dog d = (Dog)Animal; //Compiles but fails at runtime

এখানে আপনি সংকলককে বলছেন "আমাকে বিশ্বাস করুন। আমি জানি dসত্যিকার অর্থে কোনও Dogবস্তুর উল্লেখ করা হচ্ছে " যদিও তা না। মনে রাখবেন সঙ্কলনকারী যখন আমরা একটি ডাউনকাস্ট করি তখন আমাদের বিশ্বাস করতে বাধ্য হয়

সংকলক কেবল ঘোষিত রেফারেন্স প্রকারের সম্পর্কেই জানে। রানটাইমের সময়ে জেভিএম জানে যে বস্তুটি আসলে what

সুতরাং যখন রানটাইমে জেভিএম পরিসংখ্যান করে যে Dog dপ্রকৃতপক্ষে Animalকোনও Dogবস্তুর উল্লেখ করছে যা এটি বলে না। আরে ... আপনি কম্পাইলারের কাছে মিথ্যা বলেছেন এবং একটি বড় ফ্যাট নিক্ষেপ করেছেন ClassCastException

সুতরাং আপনি যদি ডাউন কাস্টিং instanceofহন তবে স্ক্রু আপ এড়াতে আপনার পরীক্ষা করা উচিত ।

if (animal instanceof Dog) { Dog dog = (Dog) animal; }

এখন আমাদের মনে একটি প্রশ্ন আসে। নরক সংকলক কেন অবশেষে এটি নিক্ষেপ করতে চলেছে হতাশাকে অনুমতি দিচ্ছেjava.lang.ClassCastException ?

উত্তরটি যে সমস্ত সংকলক করতে পারে তা যাচাই করা হয় যে দুটি animalপ্রকারটি একই উত্তরাধিকার গাছে রয়েছে, সুতরাং ডাউন কোডের আগে যে কোনও কোড আসতে পারে তার উপর নির্ভর করে এটি টাইপ হওয়ার সম্ভাবনা রয়েছে dog

সংকলকটিকে অবশ্যই এমন জিনিসগুলিকে মঞ্জুরি দিতে হবে যা রানটাইমের সময় সম্ভব কাজ করে।

নিম্নলিখিত কোড স্নিপেট বিবেচনা করুন:

public static void main(String[] args) 
{   
    Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
    Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
    d.eat();

}

private static Animal getMeAnAnimal()
{
    Animal animal = new Dog();
    return animal;
}

তবে, সংকলকটি যদি নিশ্চিত হন যে castালাই কাজ করতে পারবেন না, সংকলন ব্যর্থ হবে। IE যদি আপনি বিভিন্ন উত্তরাধিকারের শ্রেণিবিন্যাসে বস্তুগুলি কাস্ট করার চেষ্টা করেন

String s = (String)d; // ERROR : cannot cast for Dog to String

ডাউনকাস্টিংয়ের বিপরীতে, উজানবিশেষ সুস্পষ্টভাবে কাজ করে কারণ আপনি যখন আপকেনশন করেন তখন আপনি সংক্ষিপ্তভাবে আপনি যে পদ্ধতিতে প্রার্থনা করতে পারবেন তা সীমাবদ্ধ করে দিচ্ছেন, ডাউনকাস্টিংয়ের বিপরীতে, যা পরবর্তীকালে ইঙ্গিত দেয় যে আপনি আরও নির্দিষ্ট কোনও পদ্ধতিতে প্রার্থনা করতে চাইতে পারেন।

Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast

উপরের উজানগুলি উভয়ই ব্যতিক্রম ছাড়াই দুর্দান্ত কাজ করবে কারণ একটি কুকুর আইএস-এ অ্যানিমাল, অ্যানিথিং অ্যানিমেল করতে পারে, একটি কুকুরও করতে পারে। তবে এটি সত্য ভাসা-বিপরীত নয়।


1

কোডটি একটি সংকলন ত্রুটি তৈরি করে কারণ আপনার উদাহরণের ধরণটি একটি প্রাণী:

Animal animal=new Animal();

বিভিন্ন কারণে জাভাতে ডাউন কাস্টিং অনুমোদিত নয়। বিশদ জন্য এখানে দেখুন ।


5
কোনও সংকলনের ত্রুটি নেই, এটিই তাঁর প্রশ্নের কারণ
ক্লারেন্স লিউ

1

যেমনটি ব্যাখ্যা করা হয়েছে, এটি সম্ভব নয়। আপনি যদি সাবক্লাসের কোনও পদ্ধতি ব্যবহার করতে চান তবে সুপারক্লাসে পদ্ধতিটি যুক্ত করার সম্ভাবনাটি মূল্যায়ন করুন (শূন্য হতে পারে) এবং পলিমারফিজমের জন্য সাবস্ক্লাস থেকে আপনার আচরণ (সাবক্লাস) চান এমন আচরণ পাওয়ার আহ্বান জানান। সুতরাং আপনি যখন ড.মোথডো () কল করবেন তখন কলটি কাস্টিং সহ সফল হবে, তবে যদি বস্তুটি কুকুর নাও থাকে, সমস্যা হবে না


0

@ ক্যামনসের উত্তর বিকাশ করতে:

কল্পনা করুন যে একটি পিতা শ্রেণীর অনেক শিশু রয়েছে এবং সেই শ্রেণিতে একটি সাধারণ ক্ষেত্র যুক্ত করার প্রয়োজন রয়েছে। যদি আপনি উল্লিখিত পদ্ধতির বিষয়টি বিবেচনা করেন তবে আপনার প্রতিটি শিশু ক্লাসে এক এক করে যাওয়া উচিত এবং নতুন ক্ষেত্রের জন্য তাদের নির্মাতাদের রিফ্যাক্টর করা উচিত। সুতরাং যে সমাধান এই পরিস্থিতিতে একটি আশাব্যঞ্জক সমাধান নয়

এখন এই সমাধানটি দেখুন।

একজন বাবা প্রতিটি সন্তানের কাছ থেকে একটি স্ব বস্তু গ্রহণ করতে পারেন। এখানে একটি পিতা ক্লাস:

public class Father {

    protected String fatherField;

    public Father(Father a){
        fatherField = a.fatherField;
    }

    //Second constructor
    public Father(String fatherField){
        this.fatherField = fatherField;
    }

    //.... Other constructors + Getters and Setters for the Fields
}

এখানে আমাদের শিশু শ্রেণিটি রয়েছে যার একটিতে তার বাবা কনস্ট্রাক্টরের বাস্তবায়ন করা উচিত, এক্ষেত্রে পূর্বোক্ত নির্মাতা:

public class Child extends Father {

    protected String childField;

    public Child(Father father, String childField ) {
        super(father);
        this.childField = childField;
    }

    //.... Other constructors + Getters and Setters for the Fields

    @Override
    public String toString() {
        return String.format("Father Field is: %s\nChild Field is: %s", fatherField, childField);
    }
}

এখন আমরা অ্যাপ্লিকেশন পরীক্ষা করছি:

public class Test {
    public static void main(String[] args) {
        Father fatherObj = new Father("Father String");
        Child child = new Child(fatherObj, "Child String");
        System.out.println(child);
    }
}

এবং ফলাফল এখানে:

ফাদার ফিল্ড হলেন: ফাদার স্ট্রিং

শিশু ক্ষেত্রটি: শিশু স্ট্রিং

আপনার বাচ্চাদের কোডগুলি ভঙ্গ করার কোড সম্পর্কে উদ্বিগ্ন না হয়ে এখন আপনি সহজেই ফাদার ক্লাসে নতুন ক্ষেত্র যুক্ত করতে পারেন;

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