9

I'm get a ClassCastException whenever I try to cast a BufferedImage (parent) to an AdvancedBufferedImage (child) which I extended myself, I've not overridden any methods and I've implemented all the contractors without modifying them

I'm gettign this exception whenever I try to create an AdvancedBufferedImage out of File using ImageIO.read() method.

File file = new file(path);
AdvancedBufferedImage image = (AdvancedBufferedImage) ImageIO.read(file);

It seems there should not be any problem, What could be the problem?

kosa
  • 65,990
  • 13
  • 130
  • 167
Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67

7 Answers7

15

Downcasting like this is not allowed.

The preferred solution would be to create a constructor of AdvancedBufferedImage, taking a BufferedImage as parameter. With that you could do the following.

File file = new file(path);
AdvancedBufferedImage image = new AdvancedBufferedImage(ImageIO.read(file));

Here the constructor of AdvancedBufferedImage can decide how to properly convert a BufferedImage in an advanced one..

W. Goeman
  • 1,674
  • 2
  • 15
  • 31
  • So you suggest to change AdvancedBufferedImage's relationship to BufferedImage, to be HAS A not IS A? – Kirill Kulakov Aug 03 '12 at 15:50
  • Exactly. This approach allows you to delegate the methods you do not want to implement yourself, and still add extra functionallity. You will just wrap the existing class. – W. Goeman Aug 03 '12 at 15:54
  • 6
    just a notice there is a handy tool for doing just that in eclipse, create a class that has the instance of the class you want to delegate, right click on the member, `delegate methods`. very handy for huge classes – Kirill Kulakov Jun 10 '14 at 09:13
  • 1
    wow, you came back here 2 years after posting for adding teh eclipse comment. Good job remembering this. I dont remember ever writing this answer :P – W. Goeman Jun 10 '14 at 14:53
4

You cannot cast a PARENT class to a CHILD class unless the reference of PARENT class holds an instance of CHILD class or its derived classes.

In your case, ImageIO.read(file) returns an instance of BufferedImage, which is the base class. This will only work, if ImageIO.read(file) returns instance of AdvancedBufferedImage or its sub-classes.

When you extend some class, the derived class inherits some properties from the base class, however, the base class gains nothing. As a result of this, since instance of derived class has all the properties of base class, a reference of base class can hold instance of derived class, i.e. you can cast a DERIVED class to BASE class. Now, derived class may add some new properties and base class is never aware of these properties. So a cast from BASE class to DERIVED is obviously incorrect.

devang
  • 5,376
  • 7
  • 34
  • 49
3

Downcasting in Java

Downcasting is not going to work like this. See the answer in the above post. As an alternative, what about making a static factory method that takes BufferedImage and returns an instance of your class built with the object returned by ImageIO.read() ?

For example:

private AdvancedBufferedImage(BufferedImage bi) {
    //  build your AdvancedBufferedImage from bi
    ...
}

public static AdvancedBufferedImage buildABI(BufferedImage bi) {
    return new AdvancedBufferedImage(bi)
Community
  • 1
  • 1
Carl
  • 905
  • 5
  • 9
  • I see what you are trying to say, but in this case there are parameters in the contractor for which there are not getters, So it makes It too had to implement – Kirill Kulakov Aug 03 '12 at 16:04
  • Then I think composition is a better idea than inheritance in your case. Have your class own an object of BufferedImage instead of extending it? – Carl Aug 03 '12 at 16:08
2

In general, you cannot cast parents classes to children classes. Is like forcing to cast an Animal to a Dog. A Dog is an animal, but the other way is not always true, so Java compiler will not allow you to do that.

See object inheritance.

Christian Vielma
  • 15,263
  • 12
  • 53
  • 60
2

downcast is allowed, but it must a actual instance of the child:

class A {
  String name = "a";
  A(){};
}

class B extends A {
}

public class Main {
  public static void main(String[] args) {
    A a = new B(); // must a b instance
    B b = new B();
    b = (B)a;
    System.out.println(b.name);

  }
}
jamlee
  • 1,234
  • 1
  • 13
  • 26
0

BufferedImage isn't an AdvancedBufferedImage and so the cast fails.

You can extend the functionality of BufferedImage, but the read method still returns only a BufferedImage. Casting doesn't force the reference to become, or behave as, the desired type.

You probably want to wrap a BufferedImage in your AdvancedBufferedImage class, then you can pass around and manipulate your advanced class.

pb2q
  • 58,613
  • 19
  • 146
  • 147
-1

Your downcast will only succeed if the object you're trying to cast actually is an instance of the class you're casting to.

Tom
  • 4,096
  • 2
  • 24
  • 38