Приветствую Вас ГостьВторник, 14.05.2024, 11:38

Программирование на Java, Android, Delphi


Блог

Главная » 2013 » Февраль » 11 » Обобщения в Java
12:28
Обобщения в Java
Java поддерживает обобщения. Обобщенными бывают классы, методы и интерфейсы. Обобщения нужны для того, чтобы предоставить реализацию не зависящую от типов данных. Например, обобщенный класс может предоставлять обработку разнотипных данных. Обобщения работают только с объектами.

Обобщенные классы

При объявлении класса можно указать в угловых скобках классовые типы данных, которые можно использовать в данном классе при объявлении переменных, а также в методах. При объявлении переменной в угловых скобках указывают реальные типы, которыми будет оперировать данный класс. Например:
class Test <SomeType>{
SomeType obj;

Test(SomeType obj){
this.obj = obj;
}

void ShowClassInfo(){
JOptionPane.showMessageDialog(null, obj.getClass().getName());
}
}

class MyClass {
private int a;
void SomeMethod(){}
}

class ArrayOperation <ItemClass extends Number>{
//переменная - массив для обработки
private ItemClass[] arr;
//конструктор класса
public ArrayOperation(ItemClass[] arr) {
this.arr = arr;
}

public double GetMaxValueDouble(){
double max = Double.MIN_VALUE;

for(int i = 0; i < arr.length; i ++){
if(arr[i].doubleValue() > max) {
max = arr[i].doubleValue();
}
}

return max;
}

public Integer GetMaxValueInteger(){
Integer max = Integer.MIN_VALUE;

for(int i = 0; i < arr.length; i ++){
if(arr[i].intValue() > max) {
max = arr[i].intValue();
}
}

return max;
}

}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

//в качестве параметра <SomeType> может быть только объект
Test<Integer> t = new Test <Integer> (100);
t.ShowClassInfo();

//сокращенная форма записи
Test<String> t1 = new Test <> ("100");
t1.ShowClassInfo();

Object o = new Object();
Test<Object> t2 = new Test <Object> (o);
t2.ShowClassInfo();

MyClass mc = new MyClass();
Test <MyClass> t3 = new Test <MyClass>(mc);
t3.ShowClassInfo();

//присвоение двух переменных одного типа <Integer>
Test<Integer> obj1 = new Test <Integer> (100);
Test<Integer> obj2;
obj2 = obj1;
obj2.ShowClassInfo();

// переменные разных типов - присваивать нельзя
// Test<Integer> obj3 = new Test <Integer> (100);
// Test<String> obj4;
// obj4 = obj3;

Integer[] arr1 = {1, 34, 567, 43, 122, 654, 1, 45};
ArrayOperation <Integer> ao1 = new ArrayOperation<Integer>(arr1);
jTextArea1.append(ao1.GetMaxValueDouble() + "\n");
jTextArea1.append(ao1.GetMaxValueInteger() + "\n");

Double[] arr2 = {23.34, 12.0, 34.0, 245.56, 244.12};
ArrayOperation <Double> ao2 = new ArrayOperation<Double>(arr2);
jTextArea1.append(ao2.GetMaxValueDouble() + "\n");
jTextArea1.append(ao2.GetMaxValueInteger() + "\n");


}
Для примера создадим иерархию классов - классы прямоугольники и круги и напишем обобщенный класс, которые работает с массивом фигур и выдает статистику — вычисляет максимальную, минимальну площадь фигуры и сумму площадей всех фигур. Класс статистики один а работает с разными классами  за счет обобщений. Пример:
//абстрактный класс фигура
abstract class Figure{
abstract public double getArea();
}
//класс с описанием фигуры прямоугольника
class Rectangle extends Figure{

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

public Rectangle() {
this.width = 0;
this.height = 0;
}

private double width, height;
@Override public double getArea(){
return width * height;
}
}

//класс с описанием фигуры круга
class Circle extends Figure{

public Circle(double radius) {
this.radius = radius;
}


private double radius;
@Override public double getArea(){
return 3.14 * radius * radius;
}
}

//класс с обобщенными параметрами для реализации подсчета сумм площадей фигур и
//определения статистики по фигурам

class FigureStats <FigureType extends Figure>{

FigureType[] arr;

//в конструкторе - передаем массив фигур
FigureStats(FigureType[] arr){
this.arr = arr;
}
//подсчитываем сумму площадей всех фигур
public double getSumArea(){
double result = 0;

for(int i = 0; i < arr.length; i ++){
result = result + arr[i].getArea();
}
return result;
}
//подсчитываем максимальную площадь фигуры
public double getMaxArea(){
double maxarea = Double.MIN_VALUE;

for(int i = 0; i < arr.length; i ++){
if(maxarea < arr[i].getArea())
maxarea = arr[i].getArea();
}
return maxarea;
}
//рассчитываем минимальную площадь фигуры
public double getMinArea(){
double minarea = Double.MAX_VALUE;

for(int i = 0; i < arr.length; i ++){
if(minarea > arr[i].getArea())
minarea = arr[i].getArea();
}
return minarea;
}
}


private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

Rectangle[] arr1 = new Rectangle[3];
arr1[0] = new Rectangle(1, 1);
arr1[1] = new Rectangle(10, 10);
arr1[2] = new Rectangle(5, 5);

//используем параметр типа Rectangle
FigureStats <Rectangle> rs = new FigureStats <Rectangle>(arr1);
jTextArea1.append("Суммарная площадь: " + rs.getSumArea() + " Максимальная площадь: "+ rs.getMaxArea()+ " Минимальная площадь: " + rs.getMinArea() + "\n");

Circle[] arr2 = new Circle[5];
arr2[0] = new Circle(1);
arr2[1] = new Circle(10);
arr2[2] = new Circle(4);
arr2[3] = new Circle(100);
arr2[4] = new Circle(0.1);

//используем параметр типа Circle
FigureStats <Circle> cs = new FigureStats<>(arr2);
jTextArea1.append("Суммарная площадь: " + cs.getSumArea() + " Максимальная площадь: "+ cs.getMaxArea()+ " Минимальная площадь: " + cs.getMinArea() + "\n");
}

Использование шаблонов аргументов

Если мы хотим передать в метод переменную типа обобщенного класса, то возможны два варианта:
class FigureStats <FigureType extends Figure>{

FigureType[] arr;

//в конструкторе - передаем массив фигур
FigureStats(FigureType[] arr){
this.arr = arr;
}

//сравнение элементов массива. в метод мы можем передать только объект того типа,
//который был передан при создании объекта. Этот способ не совсем гибок -
//мы не можем передовать объекты другого типа.
public boolean FirstisEqual(FigureStats <FigureType> another){
//если размеры массивов различны - массивы различны
if(arr.length != another.arr.length){
return false;
}
else{
boolean found = false;
int i = 0;

//пытаемся найти различные площади
while(!found && i < another.arr.length){
if(arr[i].getArea() != another.arr[i].getArea()){
found = true;
}
i ++;
}
//если нашли различия - массивы различны
if(found)
return false;
//иначе массивы равны
else
return true;

}

}

//этот метод имеет обобщенный параметр - мы можем передавать в него параметр
//любого типа в отличие от предыдущего метода
public boolean SecondisEqual(FigureStats <?> another){
//если размеры массивов различны - массивы различны
if(arr.length != another.arr.length){
return false;
}
else{
boolean found = false;
int i = 0;

//пытаемся найти различные площади
while(!found && i < another.arr.length){
if(arr[i].getArea() != another.arr[i].getArea()){
found = true;
}
i ++;
}
//если нашли различия - массивы различны
if(found)
return false;
//иначе массивы равны
else
return true;

}

}


}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {



Rectangle[] arr1 = new Rectangle[3];
arr1[0] = new Rectangle(1, 1);
arr1[1] = new Rectangle(10, 10);
arr1[2] = new Rectangle(5, 5);

//создаем два объекта и передаем им одинаковые массивы
FigureStats <Rectangle> fs1 = new FigureStats<Rectangle>(arr1);
FigureStats <Rectangle> fs2 = new FigureStats<Rectangle>(arr1);
//первый метод сравнения работает
jTextArea1.append(Boolean.toString(fs1.FirstisEqual(fs2)) + "\n");
//второй метод сравнения работает
jTextArea1.append(Boolean.toString(fs1.SecondisEqual(fs2)) + "\n");

Circle[] arr2 = new Circle[3];
arr2[0] = new Circle(1);
arr2[1] = new Circle(2);
arr2[2] = new Circle(3);

FigureStats <Circle> fs3 = new FigureStats<Circle>(arr2);
//первый метод сравнения НЕ РАБОТАЕТ
//jTextArea1.append(Boolean.toString(fs1.FirstisEqual(fs3)) + "\n");
//второй метод сравнения работает
jTextArea1.append(Boolean.toString(fs1.SecondisEqual(fs3)) + "\n");
}

Обобщенные методы

Методы также могут быть обобщенными. Обобщенные методы принимают параметры или возвращают параметр обобщенного типа. Метод с обобщенными параметрами может содержаться в любом классе — обобщенном или не обобщенном. Пример:
class ObMethod{
static <T, V extends T > boolean isIn(T t, V[] v){
for(int i = 0; i < v.length; i ++){
if(t.equals(v[i])) return true;
}
return false;
}

static <T, V extends T > T isIn1(T t, V[] v){
for(int i = 0; i < v.length; i ++){
if(t.equals(v[i])) return v[i];
}
return null;
}
}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

Integer[] arr = {1, 2, 3, 45, 44};
jTextArea1.append(ObMethod.isIn(111, arr) + "\n");
String[] ras = {"Один", "Два" , "Три" , "Четыре" , "Пять"};
jTextArea1.append(ObMethod.isIn("111", ras) + "\n");
jTextArea1.append(ObMethod.isIn1("Три", ras) + "\n");
jTextArea1.append(ObMethod.isIn1("Т_ри", ras) + "\n");
}

Обобщенные интерфейсы

В Java поддерживаются обобщенные интерфейсы.  Классы могут реализовывать обобщенные интерфейсы с указанием конкретных типов которые будут реализованы или также обобщенно. Пример:
//обобщенный интерфейс
interface compare <T extends Number>{
T comp(T op1opitf, T op2);
}

//класс, релизующий обобщенный интерфейс
class TestClass1 implements compare <Integer>{
@Override public Integer comp(Integer op1, Integer op2){
if(op1.doubleValue() > op2.doubleValue())
return op1;
else
return op2;
};
}

//класс, релизующий обобщенный интерфейс
class TestClass2 implements compare <Double>{
@Override public Double comp(Double op1, Double op2){
if(op1.doubleValue() > op2.doubleValue())
return op1;
else
return op2;
};
}


//класс, релизующий обобщенный интерфейс который сам является обобщенным
class TestClass <T extends Number> implements compare <T>{
@Override public T comp(T op1, T op2){
if(op1.doubleValue() > op2.doubleValue())
return op1;
else
return op2;
};
}


private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
TestClass<Integer> t1 = new TestClass<Integer>();
jTextArea1.append(Integer.toString(t1.comp(100, 101)) + "\n");
//это сранение вызовет ошбку, так как работает контроль типов
//jTextArea1.append(Integer.toString(t1.comp(1.1, 1.2)) + "\n");
//а вот так без ошибок:
TestClass<Double> t2 = new TestClass<Double>();
jTextArea1.append(Double.toString(t2.comp(1.1, 1.2)) + "\n");
}
Категория: Java (Общие вопросы) | Просмотров: 3670 | Добавил: alex | Теги: разработка программ, обобщенные классы, методы, Java, программист, обобщения, Рыбинск, интерфейсы | Рейтинг: 5.0/5
Категории раздела
Java (Общие вопросы) [17]
Java (Библиотека, пакеты Java) [17]
Java (Разработка программного обеспечения на Java) [5]
Java (Среда разработки NetBeans) [5]
JSF + PrimeFaces [21]
Java EE [11]
Разное [3]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Поиск
Календарь
«  Февраль 2013  »
ПнВтСрЧтПтСбВс
    123
45678910
11121314151617
18192021222324
25262728
Архив записей