4

It is an example in the book Core Java

Two class Employee and Manager. Manager extends Employee. The code below

Manager[] mans ={new Manager("Adam"),new Manager("Ben")};              
Employee[] emps =mans ;   
emps[0] = new Employee ("Charlie");//throws ArrayStoreException in runtime actually;

The author said that in this situation the elements in arrays SHOULD REMAIN THE SAME TYPE or it throws ArrayStoreException. In my mind emps[0] is just a reference to instance 'new Employee ("Charlie")' and type of emps[0] is Employee declared before.So why it throws exception.Is there something wrong with my basics?

Anubian Noob
  • 13,426
  • 6
  • 53
  • 75
Mr.Sky
  • 91
  • 6

3 Answers3

4

When array is created it remembers what type of data it is meant to store. So if you have classes

class Employee { .. }
class Manager extends Employee { .. }

and you will create array

Manager[] arrM = new Manager[10];

array will remember that it need to store only instances of Manager class or its derived types. But such array can't store super type of Manager since super type may not have all methods or fields of Manager class so something like

arrM[0] = new Manager();

is OK, but

arrM[0] = new Employee();

throws java.lang.ArrayStoreException: Employee pointing that Employee is not correct argument here.

So in your case you are

  • creating array for Managers

    Manager[] mans ={new Manager("Adam"),new Manager("Ben")};
    
  • creating reference to this array using its super-type Employee

    Employee[] emps =mans;
    

    (but this reference it still pointing to array which can hold only Menagers)

  • and trying to place into array new Employee

    emps[0] = new Employee("Charlie");
    

but as I mentioned this can't be allowed because it is possible that Employee do not have same members as Manager. Lets say Menager can hire(...) someone, while Employee can't (doesn't have this method). What would happen if you would call

    mans[0].hire(new Employee("Tom");

and emps[0] = new Employee ("Charlie"); would not throw exception but would let you place Employee in emps[0]? Since mans and emps are using same array it would mean that mans[0].hire(new Employee("Tom") would be called from Employee("Charlie") which can't hire anyone because Employee don't have hire method.

That is why you can't place instance of super-type (Employee) in array of Managers.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Very detailly.Thank you very much!It's interesting that if the code like Manager man = new Manager("Tom"); Employee emp = man; emp=new Employee("Alex"); at the end man.getName() is still Tom. – Mr.Sky Jun 13 '14 at 15:35
  • Actually in `Employee emp = man;` you are creating new reference which will hold same object as `man`. When you do `emp=new Employee("Alex");` you are just assigning different value to this new reference, so you are not affecting `man` reference. – Pshemo Jun 13 '14 at 15:39
  • Is it different refer mechanism between normal object and elements in arrays?The normal reference can change refered object but the arrays reference can't change refered object casually after original assignment.The arrays is more strict i think – Mr.Sky Jun 13 '14 at 15:54
  • I am not sure what you mean by different. If you want `man` to print `Alex` then you shouldn't use `emp=new Employee("Alex");` but `emp.setName("Alex");` because you want to affect object which was storing `"Tom"`, as I said earlier by `emp=new Employee("Alex");` you are affecting only `emp` reference and make it store new Employee with name Alex. This approach just points `emp` to new employee, it doesn't make `men` to also point to Alex. – Pshemo Jun 13 '14 at 15:54
  • "*normal reference can change refered object but the arrays reference can't change refered object*" no, you can change refereed object in array, it just has to be object that array expects. – Pshemo Jun 13 '14 at 15:56
  • "it just has to be object that array expects".Yes.I mean in these two examples, after original assignment-> emp[0]'refer to 'mans[0]'and'emp' refer to 'man'. They all refer to their subclass object.But'emp[0]= new Employee ("Charlie")' is incorrect but 'emp=new Employee("Alex")' is correct at last – Mr.Sky Jun 13 '14 at 16:16
  • In `emp[0]` `[0]` means to do something with element number `0` inside array held by `emp` reference, so `emp[0] = new Employee ("Charlie")` mean set element `0` of array from `emp` to `new Employee ("Charlie")`, notice you don't change value of `emp` itself, but value *inside* that array. It is hard to answer your question better in comment. Maybe consider creating separate question for it so people could write more then ~600 characters in their answers. Anyway `array[0]=123` is similar to `array.set(0,123)` not `array = new arrayWithElement123`. – Pshemo Jun 13 '14 at 19:34
  • I noticed this issue. `emp[0]` is just the element of `emp`.I confused it with `emp` which is the actual reference.Something mistake with my conception.Thank you very much and I appreciate your help.:) – Mr.Sky Jun 13 '14 at 21:50
0

On second line you can assign an array of subclass (Manager [] mans) to a reference to an array of superclass (Employee[] emps). No problems on that... but after this line the real type of emps is

Manager[]

The real type of the array is determined at run-time and it is worth nothing it is referenced by a reference to Employee[], it sitll is an array of Manager.

So emps[0] is expected to be of type Manager.

Paolo
  • 2,461
  • 5
  • 31
  • 45
  • It's know at compile time, so why there is runtime exception ? – Kasper Ziemianek Jun 13 '14 at 14:22
  • Compilers doesn't know as much as it could know... if(false){ System.out.println("a"); } will give a wrning, if(1==2+2){ System.out.println("a"); } will not... – Paolo Jun 13 '14 at 14:44
  • Moreover this is a trivial example, it will not possible to tell in this case: Employee[] emps = someFucntionReturningArray() – Paolo Jun 13 '14 at 14:47
0

It throws an exception because, like the book says, the types are different. Employee[] emps = mans; means that emps has two elements in it with type Manager. So if you add a new element or replace an existing element, it must be the same type.

I wonder if you made an array mans with size 1 (don't know what you would do this, maybe an ArrayList if you're planning to expand it later) and then followed the rest of your code, what would happen. I bet it would still not let you insert an Employee into the array.

jhobbie
  • 1,016
  • 9
  • 18
  • i dont understand what you mean with making arrays size 1 by `ArrayList`. But it's ok without exception if using `ArrayList` to declare `mans` . – Mr.Sky Jun 13 '14 at 21:32
  • I don't mean you have to use an ArrayList to make it size 1, just that an array of size 1 is pointless because it's a fixed size, so it's really just a single object or primitive data type. An ArrayList however will let you add things to it, so making a size 1 ArrayList is not pointless. – jhobbie Jun 13 '14 at 21:35
  • in this case the exception still exist. – Mr.Sky Jun 13 '14 at 21:38