Miesięczne archiwum: Luty 2012

Zdaj OCPJP – pytanie 47

Co będzie efektem kompilacji i uruchomienia kodu znajdujących się w poniższych dwóch plikach?

package eu.javablog.ocpjp;

import eu.javablog.ocpjp.other.SecondSample;

class SubSample extends SecondSample
{
    public String toString()
    {
        return "SUB: " + i;
    }
}

public class Sample extends SubSample
{
    public void print()
    {
        SubSample sub = new SubSample();
        System.out.println(sub.i);
    }

    public static void main(String... args)
    {
        new Sample().print();
    }
}
package eu.javablog.ocpjp.other;

public class SecondSample
{
    protected Integer i = 100;

    public String toString()
    {
        return "SECOND:" + i;
    }
}

 

  1. Wydrukowane zostanie 100.
  2. Kod nie skompiluje się.
  3. Wydrukowane zostanie null.
  4. Wydrukowane zostanie 0.
  5. Kod uruchomi się, ale w trakcie działania zostanie rzucony wyjątek.

 

Pokaż odpowiedź »

Prawidłowa jest odpowiedź nr 2.

Udzielenie poprawnej odpowiedzi wymaga znajomości niuansów poziomu dostępu protected. Daje on dostęp innym klasom w obrębie pakietu, a także spoza niego poprzez dziedziczenie. Jeśli jednak klasa dziedzicząca znajduje się w innym pakiecie, odziedziczona zmienna zachowuje się dalej jak prywatna.

Zdaj OCPJP – pytanie 46

Jaki będzie efekt kompilacji i uruchomienia poniższego kodu?
Należy założyć, że niezbędne importy znajdują się na swoim miejscu.

class A implements Serializable
{
    private static final long serialVersionUID = 1L;

    public String text;

    public static String staticText;

    public String toString()
    {
        return text + " " + staticText;
    }
}

public class Sample
{
    public static void main(String... args) throws Exception
    {
        A a = new A();
        a.text = "TEXT";
        a.staticText = "STEXT";
        System.out.println(a);

        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bytesOut);

        out.writeObject(a);
        byte[] bytes = bytesOut.toByteArray();
        ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytes);
        ObjectInputStream in = new ObjectInputStream(bytesIn);

        a.staticText = "CHSTEXT";

        A deserialized = (A) in.readObject();
        System.out.println(deserialized);
    }
}

 

  1. Kod nie skompiluje się.
  2. Wydrukowane zostanie odpowiednio TEXT STEXT i TEXT STEXT.
  3. Kod skompiluje się, ale w trakcie działania rzucony zostanie wyjątek.
  4. Wydrukowane zostanie odpowiednio TEXT STEXT i TEXT CHSTEXT
  5. Wydrukowane zostanie odpowiednio TEXT STEXT i TEXT null.

 

Pokaż odpowiedź »

Poprawna jest odpowiedź nr 4.

Należy bezwzględnie pamiętać o tym, iż w procesie serializacji serializowane są instancje klasy, a nie sama klasa. Zmienne statyczne przynależą do klasy, nie zaś do poszczególnych obiektów. Ich wartości nie będą więc ani zapisywane, ani odczytywane podczas serializowania.

Zdaj OCPJP – co dalej?

Nasz kurs przygotowujący do egzaminu Oracle Certified Professional Java Programmer zbliża się ku końcowi. Postanowiliśmy zakończyć pierwszą edycję kursu na 50 pytaniach. Po dodaniu ostatniego pytania opublikujemy dokument PDF zawierający wszystkie dotychczasowe wpisy wraz z wyjaśnieniami. Co więcej, postanowiliśmy oddać w Wasze ręce interaktywny quiz, rozszerzony o szereg informacji przydatnych w czasie przygotowań do egzaminu. Będzie on dostępny dla posiadaczy tabletów z logo nadgryzionego jabłka bezpośrednio z poziomu iBookstore. Oczywiście tytuł ten będzie w pełni darmowy.

Co dalej? Rozpoczniemy kursy przygotowujące do dwóch kolejnych egzaminów – Oracle Certified Professional Enterprise JavaBeans Developer oraz Oracle Certified Professional Java Persistence API Developer. Zapoczątkujemy także serię wpisów spod szyldu „Java Hadcore”, traktującą o specyficznych mechanizmach spotykanych w Javowym ekosystemie. Idealny materiał dla ludzi znudzonych OCPJP.

A czy wspominaliśmy już, że zbliża się JARCamp? :)

Zdaj OCPJP – pytanie 45

Jaki będzie efekt uruchomienia poniższego kawałka kodu?

package eu.javablog.arrayaslist;

import java.util.Arrays;
import java.util.List;

public class AsListTest {

	public static void main(String[] args) {
		String[] testArray = {"test1", "test2", "test3"};
		List<String> testListFromArray = Arrays.asList(testArray);
		testListFromArray.add("test4");
		System.out.println(testArray[3]);
	}
}

 

  1. Kod się nie skompiluje.
  2. Zostanie rzucony wyjątek ArrayIndexOutOfBoundsException w linii 10.
  3. Zostanie rzucony wyjątek ArrayIndexOutOfBoundsException w linii 12.
  4. Wyświetlone zostanie ‚test4′.
  5. Żadna z odpowiedzi nie jest poprawna.

 

Pokaż odpowiedź »

Poprawna jest odpowiedź nr 5.
Podczas uruchomienia programu zostanie rzucony wyjątek typu UnsupportedOperationException w linii 11. Lista zwracana przez Arrays.asList(…) nie może być modyfikowana więc powyższy wyjątek zostanie rzucony przy okazji wykonania dowolnej z poniższych operacji:

  • add
  • remove
  • clear

Jeżeli przyjrzymy się dokładnie liście zwracanej przez wywołanie Arrays.asList():

public static void main(String[] args) {
	String[] testArray = {"test1", "test2", "test3"};
	List<String> testListFromArray = Arrays.asList(testArray);
	System.out.println(testListFromArray.getClass().getName());
}

to zobaczymy, że lista jest instancją wewnętrznej klasy java.util.Arrays$ArrayList a nie jednej z dobrze znanych i popularnych kolekcji.

Jeżeli chcemy stworzyć edytowalną listę to możemy przekazać rezultat wywołania Arrays.asList() do konstruktora np. ArrayListy:

String[] testArray = {"test1", "test2", "test3"};
List<String> testListFromArray = Arrays.asList(testArray);
List<String> editableList = new ArrayList<String>(testListFromArray);

Pytanie inspirowane wpisem Marka Needhama.

Zdaj OCPJP – pytanie 44

Poniżej przedstawiony jest kod źródłowy.

package eu.javablog.ocpjp;

public class Sample
{
    public static void main(String[] args)
    {
        for(String arg : args)
        {
            System.out.println(arg.toUpperCase());
        }
    }
}

Co będzie efektem kompilacji i uruchomienia go następującym poleceniem?

java eu.javablog.ocpjp.Sample

 

  1. Kod nie skompiluje się.
  2. W trakcie wykonania rzucony zostanie NullPointerException w linii 7.
  3. W trakcie wykonania rzucony zostanie NullPointerException w linii 9.
  4. Program zakończy się prawidłowo i nic nie zostanie wydrukowane.
  5. Wydrukowany zostanie tekst EU.JAVABLOG.OCPJP.SAMPLE.

 

Pokaż odpowiedź »

Poprawna jest odpowiedź nr 4.

Nie zostanie wydrukowane nic. Warto pamiętać o tym, że jeśli nie podamy żadnych parametrów przy uruchomieniu programu, do metody main przekazana zostanie pusta tablica, a nie null. Pierwszym elementem tejże tablicy będzie zawsze pierwszy przekazany argument, nie nazwa uruchamianej klasy.

Zdaj OCPJP – pytanie 43

Jaki będzie efekt skompilowania i uruchomienia przedstawionego poniżej kodu?

public class Sample
{
    public static void main(String[] args)
    {
        Runnable task = new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    wait();
                    System.out.println("THREAD");
                }
                catch (InterruptedException e)
                {
                    // thread was interrupted
                }
            }
        };

        Thread t = new Thread(task);
        t.start();
        task.notify();
    }
}

 

  1. Kod nie skompiluje się.
  2. W trakcie działania aplikacji rzucony zostanie więcej niż jeden wyjątek.
  3. Wydrukowane zostanie THREAD.
  4. Nic nie zostanie wydrukowane.
  5. W trakcie działania aplikacji rzucony zostanie wyjątek.

 

Pokaż odpowiedź »

Prawidłowa jest odpowiedź nr 2.

W każdym z dwóch wątków powyższej aplikacji rzucony zostanie IllegalMonitorStateException. Powodem takiego zachowania jest fakt, iż metody wait() i notify() nie są wywoływane w synchronizowanym kontekście. Problem rozwiązać można np. przez umieszczenie wspomnianych wywołań w bloku synchronizowanym względem obiektu, na którym metody te są wykonywane. Alternatywnie, jeśli używany jest obiekt this, zsynchronizować można całą metodę. Poniżej znajduje się kompletny, poprawiony przykład:

public class Sample
{
    public static void main(String[] args)
    {
        Runnable task = new Runnable()
        {
            @Override
            public synchronized void run()
            {
                try
                {
                    wait();
                    System.out.println("THREAD");
                }
                catch (InterruptedException e)
                {
                    // thread was interrupted
                }
            }
        };

        Thread t = new Thread(task);
        t.start();

        synchronized (task)
        {
            task.notify();
        }
    }
}

Uwaga!

Poprzez rozwiązanie problemu rozumiane jest poprawne użycie metod wait i notify w synchronizowanym bloku, co zapobiega rzucaniu wyjątków. Poprawiony w ten sposób przykład może powodować wystąpienie zakleszczenia.

Zdaj OCPJP – pytanie 42

Co można powiedzieć o wydruku wygenerowanym przez poniższy program?

class Task extends Thread
{
    private static int i, j;

    @Override
    public void run()
    {
        while(true)
        {
            print();
        }
    }

    private synchronized void print()
    {
        i++;
        j++;
        System.out.println(i + " " + j);
    }
}

public class Sample
{
    public static void main(String[] args)
    {
        new Thread(new Task()).start();
        new Thread(new Task()).start();
    }
}

 

  1. Drukowane będą zawsze pary takich samych liczb.
  2. Kod skompiluje się, ale w trakcie działania rzucony zostanie wyjątek.
  3. Drukowane będą zawsze pary różnych liczb.
  4. Kod nie skompiluje się.
  5. Nie ma pewnych informacji odnośnie wydruków.

 

Pokaż odpowiedź »

Poprawna jest odpowiedź nr 5.

Pierwszym zabiegiem, który może wydać się niepoprawny, jest użycie klasy Thread tam, gdzie standardowo stosuje się interfejs Runnable. Trzeba jednak pamiętać, że klasa Thread implementuje rzeczony interfejs – nic nie stoi więc na przeszkodzie, by manewr taki zastosować. Drugą rzeczą jest synchronizowana metoda print, która sugeruje, że drukowane powinny być zawsze pary takich samych liczb. Po głębszej analizie widać jednak, iż dwa utworzone wątki mają zupełnie osobne instancje klasy Task. W każdej z nich metoda print synchronizowana wyłącznie w ramach obiektu, czego skutkiem jest brak możliwości podania pewnej informacji odnośnie wydruków aplikacji.

Zdaj OCPJP – pytanie 41

Co zostanie wyświetlone na ekranie po uruchomieniu poniższego kodu?

package eu.javablog.mapfun2;

import java.util.SortedMap;
import java.util.TreeMap;

public class MapPart {
	public static void main(String[] args) {
		TreeMap<Integer, String> fullMap = new TreeMap<Integer, String>();
		fullMap.put(1, "obj1");
		fullMap.put(3, "obj3");
		fullMap.put(2, "obj2");
		fullMap.put(5, "obj5");
		fullMap.put(4, "obj4");	
		SortedMap<Integer, String> part = fullMap.headMap(3);
		SortedMap<Integer, String> subpart = part.headMap(2);
		subpart.put(1, "newobj");
		System.out.println(fullMap.get(1) + " " + subpart.get(1));
	}
}

 

  1. Zostanie wyświetlone ‚obj1 newobj’
  2. Zostanie wyświetlone ‚newobj newobj’
  3. Zostanie rzucony wyjątek w linii 14
  4. Zostanie rzucony wyjątek w linii 15
  5. Program się nie skompiluje

 

Pokaż odpowiedź »

Poprawna odpowiedź: 2
Pracując z obiektami typu TreeMap warto zwrócić uwagę na kilka ciekawych metod, zdefiniowanych w interfejsie SortedMap:

  • SortedMap subMap(K fromKey, K toKey)
  • SortedMap headMap(K toKey)
  • SortedMap tailMap(K fromKey)

oraz jego interfejsie pochodnym – NavigableMap:

  • NavigableMap headMap(K toKey, boolean inclusive)
  • NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
  • NavigableMap tailMap(K fromKey, boolean inclusive)

Wszystkie te metody zwracają wycinki mapy. Zmiany dokonywane na mapach uzyskanych za pomocą powyższych metod są również aplikowane do mapy bazowej. Tłumaczy to wynik jaki uzyskujemy po uruchomieniu przykładowego programu. Instrukcja fullMap.headMap(3) zwraca mapę składającą się z dwóch elementów {1:”obj1″, 2:”obj2″} (pamiętajmy, że elementy TreeMap posortowane są zgodnie z tzw. naturalną kolejnością). Następna instrukcja (part.headMap(2)) tworzy kolejną mapę, w skład której wchodzi jeden element {1:”obj1″}. Modyfikacja tego elementu powoduje zmiany w mapach part oraz subpart.

Zdaj OCPJP – pytanie 40

Jaki będzie efekt uruchomienia poniższego fragmentu kodu?

package eu.javablog.q40;

import java.util.Map.Entry;
import java.util.TreeMap;

public class MapFun {
	public static void main(String[] args) {
		TreeMap<Key, String> testMap = new TreeMap<Key, String>();
		testMap.put(new Key(1), "obj1");
		testMap.put(new Key(2), "obj2");
		testMap.put(new Key(3), "obj3");
		Entry<Key, String> entry = testMap.floorEntry(new Key(5));
		System.out.println(entry.getValue());
	}
}

class Key {
	private long id; 

	public Key(long id) {
		this.id = id;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}
}

 

  1. Zostanie wyświetlone ‚obj1′
  2. Zostanie wyświetlone ‚obj3′
  3. Zostanie rzucony wyjątek w linii 10
  4. Zostanie rzucony wyjątek w linii 12
  5. Zostanie rzucony wyjątek w linii 13
  6. Program się nie skompiluje

 

Pokaż odpowiedź »

Poprawna odpowiedź: 3
Kluczami mapy typu TreeMap tworzonej za pomocą domyślnego konstruktora mogą być jedynie obiekty, których klasy implementują interfejs Comparable. W przeciwnym razie, przy próbie dodania drugiego elementu do mapy zostanie rzucony wyjątek ClassCastException.
Możemy ominąć to ograniczenie tworząc mapę za pomocą konstruktora przyjmującego obiekt typu Comparator. Przykładowy kod znajduje się poniżej. Wykorzystanie zewnętrznego Comparatora pozwala na uzyskanie spodziewanego wyniku – na ekranie zostanie wyświetlony napis ‚obj3′.

package eu.javablog.q40;

import java.util.Comparator;
import java.util.Map.Entry;
import java.util.TreeMap;

public class MapFun {
	public static void main(String[] args) {
		TreeMap<Key, String> testMap = new TreeMap<Key, String>(new KeyComparator());
		testMap.put(new Key(1), "obj1");
		testMap.put(new Key(2), "obj2");
		testMap.put(new Key(3), "obj3");
		Entry<Key, String> entry = testMap.floorEntry(new Key(5));
		System.out.println(entry.getValue());
	}
}

class Key {
	private long id; 

	public Key(long id) {
		this.id = id;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}
}

class KeyComparator implements Comparator<Key> {

	@Override
	public int compare(Key key1, Key key2) {
		// simple, dirty implementation
		return key1.getId() < key2.getId() ? -1 : key2.getId() < key1.getId() ? 1 : 0;
	}
}

GeeCON 2012 – rejestracja rozpoczęta

Rejestracja na tegoroczną edycję konferencji GeeCON została oficjalnie rozpoczęta. Konferencja odbędzie się w dniach 16-18 maja w Poznaniu. Biorąc pod uwagę wstępną listę prelegentów, impreza zapowiada się niezwykle ciekawie. Na GeeCONie będziemy też my, zdając Wam pełną relację z przebiegu konferencji. Jeżeli jesteście zainteresowaniu uczestnictwem, to do 1 marca obowiązują niższe ceny wejściówek (ich ilość jest jednak ograniczona). Zapowiada się całkiem ciekawa pierwsza połowa roku – najpierw 33rd Degree, potem GeeCON…