Rzutowanie na tablice java

0

Mam pewien problem z rzutowaniem, taki kod działa:

ArrayList modifyList = new ArrayList();
modifyList.add(new Integer(1));
modifyList.add(new Integer(2));
modifyList.add(new Integer(3));
Object[] objs = (Object[])modifyList.toArray();
for (int i=0;i<objs.length;i++) {
	System.out.println((Integer)objs[i]);
}

Ale jak chcĘ zrobić coś takiego:

ArrayList modifyList = new ArrayList();
modifyList.add(new Integer(1));
modifyList.add(new Integer(2));
modifyList.add(new Integer(3));
Integer[] objs = (Integer[]) modifyList.toArray();
for (int i = 0; i < objs.length; i++) {
	System.out.println(objs[i]);
}

To rzuca błędem java.lang.ClassCastException, dlaczego nie da się rzutować na tablicę w javie :| Ewentualnie jak to ominąć :>

0

nie wiem po co chcesz to omijać :)
ArrayList to lista obiektów, Integer to też obiekt, ale na liście możesz mieć nie tylko Integery, dlatego zapewne pojawia się ten error.

0

Mozna rzutowac na tablice, ale tablica musi byc danego typu.Metoda toArray wewnetrznie tworzy tablice Object[], i jej nie mozna rzutowac na Integer[]. Mozesz zrobic tak (od Javy 5):

Integer[] arr = list.toArray(new Integer[list.size()]);
0

Można tak

    ArrayList<Integer> modifyList = new ArrayList<Integer>();
    modifyList.add(new Integer(1));
    modifyList.add(new Integer(2));
    modifyList.add(new Integer(3));
    Integer[] objs=new Integer[modifyList.size()];
    objs=modifyList.toArray(objs);
    for (int i = 0; i < objs.length; i++)
        System.out.println(objs[i]);

//edit, @pikseloza, nie zauważyłem że już odpowiedziałeś,

0

Musze skorzystać z javy 1.4. Mój problem wygląda dokładnie tak. Na początku tworzę ArrayListe do której wrzucam obiekty com.novell.ldap.LDAPModification. Poźniej chcĘ przekazać tą ArrayListę do metody modify(String dn, LDAPModification[] lm). Metoda ta jest klasy com.novell.ldap.LDAPConnection i tu pojawia się problem bo nie mogę zrobić coś takiego:

lc.modify(dn, (LDAPModification[]) modifyList.toArray());

Mogę co prawda zrobić coś takiego:

Object[] obj = modifyList.toArray();
LDAPModification[] lm = new LDAPModification[obj.length];
for (int i = 0; i < obj.length; i++) {
	lm[i] = (LDAPModification) obj[i];
}
lc.modify(dn, lm);

Ale powiedzie jak to wygląda :| Czemu nie można zrzutować jedej tablicy na drugą skoro wiem że tam są obiekty tylko jednego typu :|

0

@kaziuuu, nie możesz rzutować, bo nie wiesz tak naprawdę co jest w ArrayList. Metoda add() dodaje Object, a nie Integer. W runtimie otrzymujesz wiec listę obiektów, które straciły informację o typie. Dlatego w javie 1.5 masz już genericsy.
Rozwiązanie. Stwórz własna implementację ArrayList za pomocą wzorca dekorator. Dodatkowo dodaj metodę getIntegerArray:Integer[] w której będziesz konwertował Object na Integer.

0
Koziołek napisał(a)

@kaziuuu, nie możesz rzutować, bo nie wiesz tak naprawdę co jest w ArrayList. Metoda add() dodaje Object, a nie Integer. W runtimie otrzymujesz wiec listę obiektów, które straciły informację o typie. Dlatego w javie 1.5 masz już genericsy.
Rozwiązanie. Stwórz własna implementację ArrayList za pomocą wzorca dekorator. Dodatkowo dodaj metodę getIntegerArray:Integer[] w której będziesz konwertował Object na Integer.

Hmm... jak to niby straciły informacje o typie to jaki był by sens kontenerów w javie 1.4. Skoro mogę zrobić coś takiego:

Object[] obj = modifyList.toArray();
LDAPModification[] lm = new LDAPModification[obj.length];
for (int i = 0; i < obj.length; i++) {
        lm[i] = (LDAPModification) obj[i];
}

I to działa, więc gdzie tu tracenie typów ;-P

0

Ty może wiesz co jest w tablicy, a może się pomylisz. Kompilator wie natomiast na pewno tylko to co napisałeś i nie może nic nadinterpretować. Gdyby Java pozwalała na rzutowanie referencji między zupełnie dowolnymi obiektami, to całą kontrolę typów można by wyrzucić do kosza. A Java zamieniłaby się w C++.

Tablica elementów A nie ma nic wspólnego z tablicą elementów B (bez względu na to czy A i B mają coś wspólnego ze sobą). Nie można więc rzutować referencji tablic między sobą. Można jedynie zrzutować tablicę na pojedynczy Object (nietablicowy) i z powrotem (chyba) bo tablica jest obiektem klasy dziedziczącej bezpośrednio po Object.
Nie możesz mylić rzutowania referencji elementów do rzutowania referencji tablicy.

W Twoim kodzie możesz rzutować z powrotem na LDAPModification ponieważ w obiektach, które obrabiasz jest zapisana informacja o tej klasie. A obiekty możesz rzutować tylko na klasy pomiędzy klasą faktycznie utworzonego potomka, a pierwszym rodzicem (czyli Object). Jeżeli dziedziczą po sobie A => B => C, to jeżeli utworzysz C możesz rzutować go na Object, A i B (Object jest rodzicem każdej klasy). Ale jeżeli utworzysz B, to możesz taki obiekt rzutować tylko na Object i A. Nie będziesz mógł nigdy zrzutować takiego obiektu na C. W obu wypadkach nie możesz zrzutować na D, który jest z zupełnie innej bajki.

Popatrz na taki kod:

import java.util.ArrayList;
import java.util.List;

public class NewClass
{
	public static void main(String[] args)
	{
		List<Integer> modifyList = new ArrayList<Integer>(10);
		for(int i = 0; i < 10; i++)
			modifyList.add(i);

		System.out.print("Lista: ");
		for(Integer liczba:modifyList)
			System.out.print(liczba + ", ");
		System.out.println();
		Thread.yield();
		try { Thread.sleep(2000); } catch(InterruptedException ex) {}

		Object jakaśCholera = modifyList.toArray();

		Double[] lm = new Double[((Object[])jakaśCholera).length];
		for (int i = 0; i < ((Object[])jakaśCholera).length; i++)
		{
			Object[] obj = ((Object[])jakaśCholera);
			lm[i] = (Double) obj[i]; //error runtime z powodu typu elementu
		}

		System.out.print("Tablica: ");
		for(Double liczba :lm)
			System.out.print(liczba + ", ");
	}
/*
Lista:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Exception in thread "main" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.Double
	at SFCmodel.NewClass.main(NewClass.java:24)
Java Result: 1
*/
}

Java bez problemu go kompiluje. Ale błąd wyrzuca dopiero w czasie wykonania i wysypuje się dopiero na
rzutowaniu łamiącym hierarchię klas bo Double oraz Integer są potomkami Object, ale między sobą nie mają nic wspólnego

0

@up. Ja to wszystko wiem, tylko mnie zastanawia czemu nie można rzutować tablic, skoro można normalne referencje ??

0

Przecież można.
To jest rzutowanie w górę: Object jakaśCholera = modifyList.toArray();
A to jest rzutowanie w dół: Object[] obj = ((Object[])jakaśCholera);

Typem obiektu utworzonym przez toArray() jest Object[]. Gdybyś chciał rzutować tę referencję na cokolwiek innego poza Object lub Object[], to wywali wyjątkiem.
Jest tak dlatego, że hierarchia dziedziczenia dowolnej tablicy zaczyna się na Object, a kończy od razu na tablicy o konkretnym typie elementów. Tej zasady nie łamią nawet typy szablonowe bo nie można utworzyć tablicy o typie elementów takim jak parametr (czyli formalnie nieznanym). Inna tablica, to inna hierarchia obiektów zaczynająca się od Object.

0
Olamagato napisał(a)

Przecież można.
To jest rzutowanie w górę: Object jakaśCholera = modifyList.toArray();
A to jest rzutowanie w dół: Object[] obj = ((Object[])jakaśCholera);

Typem obiektu utworzonym przez toArray() jest Object[]. Gdybyś chciał rzutować tę referencję na cokolwiek innego poza Object lub Object[], to wywali wyjątkiem.
Jest tak dlatego, że hierarchia dziedziczenia dowolnej tablicy zaczyna się na Object, a kończy od razu na tablicy o konkretnym typie elementów. Tej zasady nie łamią nawet typy szablonowe bo nie można utworzyć tablicy o typie elementów takim jak parametr (czyli formalnie nieznanym). Inna tablica, to inna hierarchia obiektów zaczynająca się od Object.

Dzięki za objaśnienie teraz już rozumiem. Ma to pewnie związek z zarządzaniem pamięcią dla tablic przez wirtualną maszynę javy :>

0

Errata do wcześniejszego posta:
Jeżeli dziedziczą po sobie A => B => C, to jeżeli utworzysz C, to jego referencję możesz rzutować nieskończenie wiele razy na Object, A, B (Object jest rodzicem każdej klasy) oraz z powrotem na C. Ale jeżeli utworzysz B, to możesz taki obiekt rzutować tylko na Object, A i z powrotem na B. Nie będziesz mógł nigdy zrzutować referencji do takiego obiektu na C bo o ile C wie coś o dostępnej części B, o tyle B nie wie nic o C. W obu wypadkach nie możesz zrzutować na D, który jest z zupełnie innej bajki.

1 użytkowników online, w tym zalogowanych: 0, gości: 1