Site icon Java blog

Java #46: ograniczenia typów generycznych

java generic type

Ponieważ każda klasa w Javie. która nie jest finalna, może być dziedziczona lubi sama dziedziczyć. To pojawia się problem, w jaki sposób taka klasa miałaby być typem generycznym. Wiesz ze wcześniejszych lekcji, że polimorfizm umożliwia sprytne 'przeskakiwanie’ pomiędzy implementacjami danej klasy. Istnieje, jednak sposób, w jaki można podczas programowania Twojego generyka, 'pokazać’ Javie jakiej instancji oczekujemy, używając do tego ostrych nawiasów. Taka praktyka nazywa się ograniczeniem typu (ang. type bound).

Ograniczenia typów generycznych poprzez extends

Do zademonstrowania jak można łatwo ograniczać generyka, użyję swoich interfejsów: Payable i Orderable.

public interface Orderable {
	void orderToGo();
}
public interface Payable {
	void payByCard();
}

Teraz jeden z nich, Orderable, zaimplementuje w klasie z poprzedniej lekcji, Italian. Drugi za to (Payable) w klasie FastFood.

public class Italian implements Orderable{
	@Override
	public void orderToGo() {
		System.out.println("Na wynos");
	}
}
public class FastFood implements Payable{
	@Override
	public void payByCard() {
		System.out.print("Paid by card.");
	}
	
}

Teraz mogę zobaczyć jak takie ograniczenie wpłynie na moją klasę generyczną.

public class Restaurant<T extends Orderable, U> {
	T category;
	U id;
	
	public T getCategory() {
		return category;
	}
	public void setCategory(T category) {
		this.category = category;
	}
	public U getId() {
		return id;
	}
	
	public void setId(U id) {
		this.id = id;
	}
	
}

Używając słowa extends ograniczyłem typ 'T’. Teraz za każdym razem ja będę chciał zaimplementować nową restaurację, musi mieć ona zaimplementowane jedzenie na wynos.

public class RestaurantsMain {
	public static void main(String[] args) {
		Restaurant<Italian, Long> pizzaNapoli = new Restaurant<>();
		Restaurant<FastFood, Long> kfc  = new Restaurant<>(); // <- błąd, nie zadziała
	}
}

Ograniczenia typów generycznych przez dwa interfejsy

Podobnie jak we wcześniejszej lekcji przetestowałem możliwość więcej niż jednego typu generycznego w mojej klasie, tutaj także ograniczenie może dotyczyć więcej niż jednego elementu. Przydaje się to, gdy klasy implementują więcej niż dwa interfejsy, a ja chciałbym ograniczyć użycie ich w generykach tylko do konkretnych dwóch. Wtedy zamiast T extends Orderable napiszę:

public class Restaurant<T extends Orderable & Payable, U>

Za pomocą znaku ampersand (&) dodałem kolejny warunek ograniczenia klasy Restaurant. Teraz klasa będzie mogła być restauracją tylko i wyłącznie, gdy spełnia warunki: możliwość płatnością karty oraz zamawiania na wynos. Możesz też dokonać ograniczenia typów generycznych z 'drugiej strony’ poprzez zastąpienie extends słowem kluczowym super*.

Ta lekcja bardzo mocno bazuje na wcześniejszej. Jeśli jeszcze jej nie przerobiłeś, to radzę Ci przejrzeć ją przed zaprogramowaniem nowego kodu.

Link do kodu: https://github.com/developeronthego/java-advanced/tree/master/src/main/java/advanced/lesson2

*Tzw. dolne ograniczenia typów generycznych (ang. lower bounded wildcard): https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html

Exit mobile version