Integer i7 = 7;
long l7 = 7L;
System.out.println(i7.equals(l7));
The output will be false. Be careful while comparing digits with ‘equals’ method.
Method ‘equals’ in Integer class is defined as:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Variable l7 is unboxed to Long so false is returned.
Bardzo przydatną funkcją w Javie jest Arrays.asList(). Posiada jednak pewny kontrakt – zmiany w tablicy są widoczne w liście i na odwrót. Wynika to z faktu, że tworzona lista jest jedynie “widokiem” na tablicę – odwołuje się do tego samego miejsca na stercie. Obrazuje to poniższy przykład:
String[] tablica = new String[] {"1", "2", "3", "4", "5"};
List<String> list = Arrays.asList(tablica);
// zmiana elementu
list.set(0, "a");
for (String tab : tablica) {
System.out.print(tab + " ");
}
// dodanie nowego elementu
list.add("6");
for (String tab : tablica) {
System.out.print(tab + " ");
}
Wynikiem powyższych instrukcji jest:
a 2 3 4 5
UnsupportedOperationException
Jak widać zmiana elementu listy została odwzorowana również w tablicy, natomiast dodanie elementu do tablicy zakończyło się wyjątkiem. Jest to spowodowane faktem, że lista faktycznie odwołuje się do tablicy, która zaalokowana jest na stercie i jej powiększenie, bez utworzenia nowej tablicy jest niemożliwe.
Często w Javie operuje się na strumieniach danych. Operacje na nich są analogiczne do poniższej metody:
public static void checkedException() throws IOException {
try {
System.out.println("1");
throw new IOException("Exception 1");
} catch (FileNotFoundException e) {
System.out.println("2");
throw new IOException("Exception 2");
} catch (IOException e) {
System.out.println("3");
throw e;
} finally {
System.out.println("4");
throw new IOException("Exception 4");
}
}
W bloku finally strumienie są zamykane, lecz metoda close() może wyrzucić wyjątek IOException. Wywołanie poniższej metody:
try {
checkedException();
} catch (IOException e) {
System.out.println(e.getMessage());
}
wypisze na konsoli:
Można by przypuszczać, że wypisany zostanie “Exception 1″, jednak jako ostatni wyrzucony zostaje wyjątek w bloku finally i to on jest przekazywany dalej. Podobna sytuacja dotyczy zwracania wartości w bloku finally.
Bezpieczeństwo typów dla kolekcji i tablic w Javie.
public class A {
public String getName() { return "A"; }
public static void main(String[] args) {
Set<B> bSet = new LinkedHashSet<B>();
Set<A> aSet = bSet; // THIS WILL NOT COMPILE
aSet.add(new C());
B[] bTable = new B[2];
A[] aTable = bTable;
aTable[0] = new B();
aTable[1] = new C(); //ArrayStoreException
}
}
public class B extends A {
@Override
public String getName() { return "B"; }
}
public class C extends A {
@Override
public String getName() { return "C"; }
}
Załóżmy, że istnieje możliwość przypisania obiektu LinkedHashSet<B> do zmiennej referencyjnej Set<A>. Na nowej referencji można wywołać metodę aSet.add(new C()), czego skutkiem tego jest dodanie obiektu C (podtypu klasy A) do trzymanego na stercie obiektu LinkedHashSet<B>, co jest błędne. Należy jednocześnie pamiętać, że typy genetyczne są zapominane podczas kompilacji i w rzeczywistości w pamięci istnieje obiekt Map. W związku z powyższym przy próbie rzutowania obiektu LinkedHashSet<B> na Set<A> otrzymujemy błąd kompilacji.
Mając analogiczną sytuację dla tablic nie otrzymujemy żadnego powiadomienia o błędzie od kompilatora podczas rzutowania. Dopiero po uruchomieniu dostajemy wyjątek: ArrayStoreException. Jest on związany z próbą dodania do tablicy niezgodnego typu obiektu. Należy pamiętać, że w momencie tworzenia tablic zapamiętują one swój typ.
Z powyższego przykładu widać, że korzystanie z kolekcji jest bezpieczniejsze niż z tablic.