Московский государственный университет имени М.В.Ломоносова
Опубликован: 18.09.2006 | Доступ: свободный | Студентов: 1868 / 118 | Оценка: 4.32 / 3.36 | Длительность: 27:14:00
ISBN: 978-5-9556-0067-3
Лекция 11:

Основные конструкции языков Java и C# (продолжение)

Шаблонные типы и операции

В последних версиях обоих языков введены шаблонные, т.е. имеющие типовые параметры, типы и операции.

Ниже приводятся примеры декларации шаблонного метода и его использования в Java и C#. В последнем вызове в обоих примерах явное указание типового аргумента у метода getTypeName() необязательно, поскольку он вычисляется из контекста вызова. Если вычислить типовые аргументы вызова метода нельзя, их нужно указывать явно.

public class A
{
  public static <T> String getTypeName
    (T a)
  {
    if(a == null) return "NullType";
    else return 
      a.getClass().getName();
  }

  public static void main(String[] args)
  {
    String  y = "ABCDEFG";
    
    System.out.println( getTypeName(y) );
    System.out.println
      ( getTypeName(y.length()) );
    System.out.println
      ( A.<Character>getTypeName
          (y.charAt(1)) );
  }
}
using System;

public class A
{
  public static string getTypeName<T>
    (T a)
  {
    if(a == null) return "NullType";
    else return
      a.GetType().FullName;
  }

  public static void Main()
  {
    string y = "ABCDEFG";
    
    Console.WriteLine( getTypeName(y) );
    Console.WriteLine
      ( getTypeName(y.Length) );
    Console.WriteLine
      ( getTypeName<char>(y[1]) );
  }
}

В Java в качестве типовых аргументов могут использоваться только ссылочные типы.

Примитивный тип не может быть аргументом шаблона — вместо него нужно использовать соответствующий класс-обертку.

В C# любой тип может быть аргументом шаблона.

В Java типовые аргументы являются элементами конкретного объекта — они фактически представляют собой набор дополнительных параметров конструктора объекта или метода, если речь идет о шаблонном методе. Поэтому статические элементы шаблонного типа являются общими для всех экземпляров этого типа с разными типовыми аргументами.

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

public class A<T>
{
  public static int c = 0;
  public T t;
}

public class B
{
  public static void main
    (String[] args)
  {
    A.c = 7;

    System.out.println( A.c );
  }
}
using System;

public class A<T>
{
  public static int c = 0;
  public T t;
}

public class B
{
  public static void Main()
  {
    A<string>.c = 7;

    Console.WriteLine( A<int>.c );
    Console.WriteLine( A<string>.c );
  }
}

В C# можно определить и использовать шаблонные делегатные типы.

public delegate bool Predicate<T>
  (T value);

public class I
{
  public bool m(int i)
  { return i == 0; }

  public void f()
  {
    Predicate<int> pi = m;
    Predicate<string> ps =
      delegate(string s)
      { return s == null; };
  }
}

В обоих языках имеются конструкции для указания ограничений на типовые параметры шаблонных типов и операций. Такие ограничения позволяют избежать ошибок, связанных с использованием операций типа-параметра, точнее, позволяют компилятору обнаруживать такие ошибки.

Ограничения, требующие от типа-параметра наследовать некоторому другому типу, позволяют использовать операции и данные типа-параметра в коде шаблона.

В Java можно указать, что тип-параметр данного шаблона должен быть наследником некоторого класса и/или реализовывать определенные интерфейсы.

В приведенном ниже примере параметр T должен наследовать классу A и реализовывать интерфейс B.

В C# можно указать, что тип-параметр должен быть ссылочным, типом значения, наследовать определенному классу и/или определенным интерфейсам, а также иметь конструкторы с заданной сигнатурой.

В приведенном ниже примере параметр T должен быть ссылочным типом, параметр V — типом значений, а параметр U — наследовать классу A, реализовывать интерфейс IList<T> и иметь конструктор без параметров.

public class A
{

  public int m() { ... }
}

public interface B 
{
  public String n();
}

public class C<T extends A & B>
{
  T f;
  
  public String k()
  {
    return f.n() + (f.m()*2);
  }
}
public class A { ... }


public class B<T, U, V>
  where T : class
  where U : A, IList<T>, new()
  where V : struct
{ ... }

Кроме того, в Java можно использовать неопределенные типовые параметры (wildcards) при описании типов. Неопределенный типовой параметр может быть ограничен требованием наследовать определенному типу или, наоборот, быть предком определенного типа.

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

В приведенном ниже примере первый метод работает с коллекцией произвольных объектов, второй — с коллекцией объектов, имеющих (не обязательно точный) тип T, третий — с такой коллекцией, в которую можно добавить элемент типа T.

public class A
{
  public void addAll
    (Collection<?> c)
  { ... }

  public <T> void addAll
    (Collection<? extends T> c)
  { ... }

  public <T> void addToCollection
    (T e, Collection<? super T> c)
  { ... }
}
Владислав Нагорный
Владислав Нагорный

Подскажите, пожалуйста, планируете ли вы возобновление программ высшего образования? Если да, есть ли какие-то примерные сроки?

Спасибо!

Лариса Парфенова
Лариса Парфенова

1) Можно ли экстерном получить второе высшее образование "Программная инженерия" ?

2) Трудоустраиваете ли Вы выпускников?

3) Можно ли с Вашим дипломом поступить в аспирантуру?