In short, I have a class named NoiseMaker which stores objects who implements the interface Beep. NoiseMaker has a method where it prints out the beep sound of the specific object. In this case, I only have objects of type Car and Phone which have the beep method. However when I try to run my code I get this error
Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [LBeepable; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [LBeepable; is in unnamed module of loader 'app')
at NoiseMaker.<init>(NoiseMaker.java:7)
at Main.main(Main.java:5)
I don't know how to fix this because I need the arary to be able to store any object which has the method beep().How can I use generic paramaters to be able to do this task. This is the main method that calls the classes and produces the error :
public class Main {
public static void main(String[] args) {
NoiseMaker m;
m = new NoiseMaker<>(5);
m.addItem(new Phone());
m.addItem(new Car());
m.addItem(new Car());
m.addItem(new Phone());
m.addItem(new Phone());
m.addItem(new Car());
m.makeNoise();
}
}
Here are the other relevenat classes :
public class NoiseMaker<T extends Beepable> {
private int numberOfItems;
private T [] items;
public NoiseMaker(int capacity){
this.numberOfItems = 0;
items = (T[]) new Object[capacity];
}
public void addItem(T item){
if (this.numberOfItems== capacity) {
System.out.println("The NoiseMakes is full");
} else if (item == null) {
System.out.println("null is not a valid value");
} else {
items[this.numberOfItems++] = item;
}
}
public void makeNoise() {
for(T item : items) {
item.beep();
}
}
}
public interface Beepable {
void beep();
}
PS : instead of using T , can I just Beepable instead. since essentialy, I want objects who implement the interface beepable? and if so why can I do that since Beepable is an interface and cant be instatiated.
As indicated by compilation error, we can not case Object which is loaded by bootstrap classloader to Beepable which is loaded by app class loader.
You can get more information about class loader here.
Thanks for @Slaw correcting. Class loader is not the real issue here. We cannot cast an object to another object which has no inheritance relationship.
We can try to solve this by constructing a Beepable array, or using List.
public class NoiseMaker<T extends Beepable> {
...
private int capacity;
public NoiseMaker(int capacity){
this.numberOfItems = 0;
this.capacity = capacity;
items = (T[]) new Beepable[capacity];
}
...
public class NoiseMaker<T extends Beepable> {
...
private List<T> items;
public NoiseMaker(int capacity){
this.numberOfItems = 0;
this.capacity = capacity;
items = new ArrayList<>(capacity);
}
...