java.lang.ClassException: A-ге ауысу мүмкін емес

Мен осы кодты енгіздім:

class A {
    //some code
}
class B extends A {
   //some code
}

class C {
    public static void main(String []args)
    {
        B b1 = (B) new A();
        A a1 = (B) new A();
    }
}

Both of these lines, when compiled separately, compile fine,but give runtime error with java.lang.ClassException: A cannot be cast into B.

Неліктен олар жақсы құрастырады, бірақ жұмыс уақыты қатесін береді?

10
Айтарлықтай, бұл негізгі OOP. Бірақ, адамдарға бұл туралы қамқорлық жасамайды және желідегі кеңінен түсіндірілген кезде, жауаптар мен жаңартуларды ұнатады.
қосылды автор Luiggi Mendoza, көзі
Классикалық мысалды қарастырайық: Ит жануар? Иә . Жануарларды иттер ме? Мүмкін . Бірақ әрқашан емес . Шындығында компиляторға сіз қателеспесеңіз деп сенуге сендіресіз. Бірақ, іске қосу кезінде, бағдарламаңыз не істеп жатқаныңызды шынымен білмейтіндіктен, бағдарламаңыз апатқа ұшырайды.
қосылды автор Maroun, көзі
Өйткені A данасы B ешқандай қатысы жоқ. Бұл жұмыс уақытын тексеру.
қосылды автор Brian Roach, көзі

13 жауаптар

Өткізу уақытында орындалмаған себебі - бұл объект емес, B. бұл А, сондықтан some .

Компилятор А объектісімен болған барлық нәрсені талдай алмайды. Мысалға.

A a1 = new B();
A a2 = new A();

B b1 = (B) a1;   //Ok
B b2 = (B) a2;   //Fails

Сонымен, компилятор сіздің А нысанды шынымен B-ге жіберетініне сенімді емес. Жоғарыда айтылғандай, соңғы 2 жол жақсы болды. Бірақ бағдарламаны іске қосқан кезде, a2 - бұл B емес, бұл тек А

7
қосылды

A түріне сілтеме бойынша A сыныптың кез келген нысандарын немесе A код> B .

Мәселен мүмкін

A a = new B();

a сілтемесінің астындағы нысан B сыныбының данасы болғандықтан, оны B b секілді дәл анықтамада сақтауға болады. Міне, осылай көріңіз:

B b = a;//Type mismatch error

Мұндай код, бұл жағдайдың алдын алу үшін уақытты қате сәйкес емес құрастыруға мүмкіндік береді айтуға мүмкіндік береді

  • class B1 extends A and
  • class B2 extends A

және біз A a = new B1() құрдық. Егер B1 b = a үшін Қате сәйкес емес қатесін компилятор қоятын болса, B2 b = a B1 данасы бар, ол B2 дегенмен ешқандай қатысы жоқ.

Компиляторға әлеуетті түрдегі сәйкессіздіктер туралы хабардар болу үшін бізге қажетті сыныпқа ауысуды нақты пайдалану қажет

B b = (B) a;

Сол себепті компиляция уақытында A кеңейтілетін сыныпқа A сілтемесін құю мүмкін.


Сіздің кодыңызда сізде бар

B b1 = (B) new A();
A a1 = (B) new A();

new операторы сол нысанның сілтемесін қайтаратындығын білу қажет, сондықтан new A() түрін A осылай

B b1 = (B) new A();

шын мәнінде сол сияқты

A tmp = new A();
B b1 = (B) tmp;

Мәселе мынада, сіз кейбір сыныптың нысандарын өзіңіздің алынған сыныпқа қатысты сақтай алмайсыз. Неліктен? Алынған сыныпта бұл нысан классы ұнайтын жаңа әдістер болса не болады?

class A {
   //some code
}

class B extends A {
    private int i;
    public void setI(int i){
        this.i=i;
    }
}

және кейін

B b = (B)new A();

b.setI (42) сөзін қолдануға тырысасыз ба? Бұл мүмкін бе? Жоқ, себебі А сыныбында setI әдісі жоқ және тіпті егер идентификатор болса, бұл әдіске қолданылатын int i өрісі жоқ.

Осы себепті (B) жаңа A (); java.lang.ClassCastException .

6
қосылды
Қош келдіңіз :)
қосылды автор Pshemo, көзі
Керемет жауап! Көп рақмет.
қосылды автор Ozil, көзі

компиляторы дегенді білдіретін атау тек expression компиляция уақыты түріне қарайды.

Ол expression орындау уақытының түріне қатысты жорамалдарды жасамайды.

http://docs.oracle .com/javase/specs/jls/se7/html/jls-5.html # jls-5.5.1

Нақты проблемаға көшу

Сіз аға бере алмайсыз Сіз B B аға ауыса аласыз. Сізде манго болса, сізде жеміс бар. Бірақ сізде жеміс бар болса, бұл сізге манго бар.

2
қосылды
A a1 = (B) new A();

Өйткені A NOT B болып табылмайды.

B A жұмыс уақытында сіз сенімді екеніңізге сенімді түрде компиляция жасайтындықтан, уақытты құрастырыңыз.

2
қосылды

B кеңейтілсе, А-ның барлық әдістері мен қасиеттері В-да бар.

Сондықтан сіз B-ға A,

бірақ А-дан А шығаруға болмайды.

Сіз өзіңіздің өтініміңізде құптау туралы қамқорлық жасауыңыз керек.

2
қосылды

B айтатын болсаңыз, A, A B болады енді техникалық B барлық A және өз меншікті сипаттамалары бар ал А-ның ерекшеліктері бар

if you say convert A into B and assign to B, that is ok but if you say cast A into B and assign to A, thats not possible as A here does not know extra charecteristics present in B.

және бұл әрекеттер орындау уақытында орын алады, сондықтан ол сізге жұмыс уақытының қатесін береді.

2
қосылды

Төменде комплектменттің құйылуы -

A a = new B();

Мұндай статикалық қыстырғыштар компилятормен жасырын түрде орындалады, себебі компилятор B-ның А-дан а.

Мынадай компиляция жасалмайды -

B b = new A();

Мұнда компилятор мәжбүрлемейді, себебі компилятор А екенін білмейді.

Компиляциядан кейін -

B b = (B) new A();

Бұл динамикалық құю. (B) арқылы сіз компиляторға нақты уақыт ішінде құсбелгісінің орын алуы керектігін айтасыз. Сіз CCE-ді орындау уақытында, орындау уақыты тастауды жасауға тырысады, бірақ оны жасай алмайтындығын және CCE-ні лақтырады.

Осындай нәрсені жасаған кезде (немесе жасау керек), жауапкершілік сізде (компиляторға емес) CCE-тің орындалу уақытында пайда болмайтындығына көз жеткізу үшін түседі.

1
қосылды

Кастинг кезінде жасалуы керек. Сіз компиляторға: «Эй, бұл туралы алаңдатпа, бұл менің ойымша, бұл сізде, егер сізде проблема болса, оны менімен бірге іске асырыңыз».

Негізінен, компилятор сіздің ісіңізді жасауға мүмкіндік береді. Бір нәрсені нақты анықтаған кезде, компилятор тексеру жүргізбейді. Сіз жүгіріп, бағдарлама түсіруге тырысады, бірақ сәтсіздікке ұшырайды, қатені көргенде.

1
қосылды

Мен компиляция бөлігіне сенімді емеспін, бірақ орындау уақытының қателігін түсіндіре аламын.

B кеңейтеді, яғни B сыныбының әрбір нысаны А типті объект болып табылады.

«Сүтқоректілермен» және «Си» дегенмен салыстыру. Сиыр әрқашан Сүтқоректілер, бірақ әрбір сүтқоректің - Сиыр.

1
қосылды

B кеңейтеді A дегеніміз B A дегенді білдіреді, яғни B ұқсас, бірақ мүмкін заттар.

Керісінше емес. A B емес. Сондықтан сіз A дегенді B түрінде шығара алмайсыз.

Осылай ойлап көрші. A - бұл Animal . B - бұл Bee . Bee жануарлар? Иә ол сондай. Кез-келген жануар Bee? Олай емес. Мысалы, ит - жануар, бірақ, әрине, аралар емес.

0
қосылды

It's simple. Think that when you are extending you have to use is a

B `is a` A
A `is not` B

Неғұрлым нақты мысал

class Animal{
}

class Dog extends Animal{
}

class Cat extends Animal{
}

DOG IS A Жануарлар AN ANIMAL IS NOT қажет емес DOG (Мысалы: мысық ит емес, ал мысық - жануар)

Сіз runtime exception себебін алып жатырсыз, себебі бұл жануар иттің емес, бұл кодекс downcasting дегенді білдіреді және сіз не істеуге тырысасыз.

0
қосылды

A - B элементінің басты элементі болғандықтан. B кеңейтеді функционалдығы A , бірақ A бастапқы жұмысын сақтайды. Сондықтан B шын мәнінде A түрінде жіберілуі мүмкін, бірақ керісінше емес.

Егер B жаңа әдіс қосса, newMethodInB() деп бөлісіңіз. Егер сіз бұл әдісті айнымалы B арқылы A үлгісінде шақыруға тырыссаңыз (бұл құсбелгі қойылғанын елестетіңіз) не күткен болар едіңіз? Енді қате пайда болады, себебі бұл әдіс A ішінде жоқ.

0
қосылды

Өйткені, барлық компиляторлар А-ның В-ға құйылғанын көреді, себебі А-ның нақты болуы мүмкін, бұл А-ға жұмыс істей алады. Ашық пішінді жаза отырып, сіз осы А-ның шынымен жарамды екеніне көз жеткізесіз. Бірақ бұлай емес.

A justA = new A();
A anAThatIsAlsoAValidB = new B();//implicit cast to supertype

B b1 = (A) anAThatIsAlsoAValidB ;//Cast an A into a B. At runtime, this will work fine! Compiler allows casting A into B.
B b2 = (A) justA;//Cast an A into a B. At runtime, this won't work. Compiler has/uses no more info than above.

Міне, компилятор түрін білмейді:

com.example.ThridPartyType obj = new com.example.ThridPartyType();
B b = (B) obj.getSomeA(); 
// getSomeA() returns A and that is all the compiler knows.
// Depeding on the implementation of "ThridPartyType::getSomeA()" the A returned may or may not actually also be a valid B. 
// Hence, if the cast works or not will only be known at runtime. If it doesn't, the Exception is thrown.
0
қосылды