Ограничения обобщений

Последнее обновление: 23.04.2018

Когда мы указываем универсальный параметр у обобщений, то по умолчанию он может представлять любой тип. Однако иногда необходимо, чтобы параметр соответствовал только некоторому ограниченному набору типов. В этом случае применяются ограничения, которые позволяют указать базовый класс, которому должен соответствовать параметр.

Для установки ограничения после универсального параметра ставится слово extends, после которого указывается базовый класс ограничения:

class Account{ }
class Transaction<T extends Account>{ }

К примеру, в данном случае для параметра T в Transaction ограничением является класс Account. То есть на место параметра T мы можем передать либо класс Account, либо один из его классов-наследников.

Например, рассмотрим следующую программу:

public class Program{
     
	public static void main(String[] args) {
         
		Account acc1 = new Account("1876", 4500);
        Account acc2 = new Account("3476", 1500);
             
        Transaction<Account> tran1 = new Transaction<Account>(acc1,acc2, 4000);
        tran1.execute();
		tran1 = new Transaction<Account>(acc1,acc2, 4000);
		tran1.execute();
	}
}
class Transaction<T extends Account>{
	
    private T from;  	// с какого счета перевод
    private T to;    	// на какой счет перевод
    private int sum;	// сумма перевода
	
	Transaction(T from, T to, int sum){
		this.from = from;
		this.to = to;
		this.sum = sum;
	}
    public void execute(){
		
        if (from.getSum() > sum)
        {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n", 
				from.getId(), from.getSum(),to.getId(), to.getSum());
        }
        else{
            System.out.printf("Operation is invalid");
        }
    }
}
class Account{
	
    private String id;
	private int sum;
	
	Account(String id, int sum){
		this.id = id;
		this.sum = sum;
	}
	
    public String getId() { return id; }
	public int getSum() { return sum; }
	public void setSum(int sum) { this.sum = sum; }
}

В данном случае класс Transaction, который представляет операцию перевода средств между двумя счетами, типизирован параметром T, у которого в качестве ограничения установлен класс Account. При создании объекта Transaction в его конструктор передаются два объекта Account - два счета, между которыми надо осуществить перевод, и сумма перевода.

При этом важно понимать, что поскольку мы установили подобное ограничение, то компилятор будет распознавать объекты типа T как объекты типа Account. И в этом случае мы можем вызывать у объектов типа T методы класса Account. И мы бы не смогли бы это сделать, если бы мы не задали подобного ограничения:

class Transaction<T>{
	// остальное содержимое
}

В этом случае была бы ошибка.

Обобщенные типы в качестве ограничений

В качестве ограничений могут выступать и другие обобщения, которые сами могут иметь ограничения:

public class Program{
     
	public static void main(String[] args) {
         
		Account<String> acc1 = new Account<String>("1876", 4500);
        Account<String> acc2 = new Account<String>("3476", 1500);
             
        Transaction<Account<String>> tran1 = new Transaction<Account<String>>(acc1,acc2, 4000);
        tran1.execute();
		tran1 = new Transaction<Account<String>>(acc1,acc2, 4000);
		tran1.execute();
	}
}
class Transaction<T extends Account<String>>{
	
    private T from;  	// с какого счета перевод
    private T to;    	// на какой счет перевод
    private int sum;	// сумма перевода
	
	Transaction(T from, T to, int sum){
		this.from = from;
		this.to = to;
		this.sum = sum;
	}
    public void execute(){
		
        if (from.getSum() > sum)
        {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n", 
				from.getId(), from.getSum(),to.getId(), to.getSum());
        }
        else{
            System.out.printf("Operation is invalid");
        }
    }
}
class Account<T>{
	
    private T id;
	private int sum;
	
	Account(T id, int sum){
		this.id = id;
		this.sum = sum;
	}
	
    public T getId() { return id; }
	public int getSum() { return sum; }
	public void setSum(int sum) { this.sum = sum; }
}

В данном случае ограничением для Transaction является тип Account, который типизирован типом String.

Интерфейсы в качестве ограничений

В качестве ограничений могут выступать также интерфейсы. В этом случае передаваемый на место универсального параметра тип должен реализовать данный интерфейс:

public class Program{
     
	public static void main(String[] args) {
         
		Account acc1 = new Account("1235rwr", 5000);
		Account acc2 = new Account("2373", 4300);
		Transaction<Account> tran1 = new Transaction<Account>(acc1, acc2, 1560);
		tran1.execute();
	}
}
interface Accountable{
	String getId();
	int getSum();
	void setSum(int sum);
}
class Account implements Accountable{
	
    private String id;
	private int sum;
	
	Account(String id, int sum){
		this.id = id;
		this.sum = sum;
	}
	
    public String getId() { return id; }
	public int getSum() { return sum; }
	public void setSum(int sum) { this.sum = sum; }
}
class Transaction<T extends Accountable>{
	
    private T from;  	// с какого счета перевод
    private T to;    	// на какой счет перевод
    private int sum;	// сумма перевода
	
	Transaction(T from, T to, int sum){
		this.from = from;
		this.to = to;
		this.sum = sum;
	}
    public void execute(){
		
        if (from.getSum() > sum)
        {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n", 
				from.getId(), from.getSum(),to.getId(), to.getSum());
        }
        else{
            System.out.printf("Operation is invalid");
        }
    }
}

Множественные ограничения

Также можно установить сразу несколько ограничений. Например, пусть класс Transaction может работать только с объектами, которые одновременно реализуют интерфейс Accountable и являются наследниками класса Person:

class Person{}
interface Accountable{}

class Transaction<T extends Person & Accountable>{}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850