Подтипирование является инвариантом для параметризованных типов. Даже жесткий класс Dog
является подтипом Animal
, параметризованный тип List
не является подтипом List
. Напротив, подтипирование covariant используется массивами, поэтому тип массива Dog[]
является подтипом Animal[]
.
Инвариантный подтипирование гарантирует, что ограничения типа, принудительно выполняемые Java, не нарушены. Рассмотрим следующий код, приведенный @Jon Skeet:
List dogs = new ArrayList(1);
List animals = dogs;
animals.add(new Cat()); // compile-time error
Dog dog = dogs.get(0);
Как указано в @Jon Skeet, этот код является незаконным, поскольку в противном случае он будет нарушать ограничения типа, возвращая кошку, когда ожидается собака.
Поучительно сравнить приведенное выше с аналогичным кодом для массивов.
Dog[] dogs = new Dog[1];
Object[] animals = dogs;
animals[0] = new Cat(); // run-time error
Dog dog = dogs[0];
Код является законным. Тем не менее, выбрасывает исключение хранилища . Массив носит свой тип во время выполнения таким образом, JVM может обеспечить безопасность типов ковариантного подтипирования.
Чтобы понять это далее, давайте посмотрим на байт-код, сгенерированный javap
класса ниже:
import java.util.ArrayList;
import java.util.List;
public class Demonstration {
public void normal() {
List normal = new ArrayList(1);
normal.add("lorem ipsum");
}
public void parameterized() {
List parameterized = new ArrayList<>(1);
parameterized.add("lorem ipsum");
}
}
Используя команду javap -c Demonstration
, это показывает следующий байт-код Java:
Compiled from "Demonstration.java"
public class Demonstration {
public Demonstration();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public void normal();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
public void parameterized();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
}
Обратите внимание, что переведенный код тел метода идентичен. Компилятор заменил каждый параметризованный тип на erasure . Это свойство имеет решающее значение, поскольку оно не нарушает совместимость в обратном направлении.
В заключение, безопасность во время выполнения невозможна для параметризованных типов, поскольку компилятор заменяет каждый параметризованный тип его стиранием. Это делает параметризованные типы не более чем синтаксическим сахаром.
Да, вы можете. MySQL поддерживает regex ( http://dev.mysql.com/doc/refman/5.6/en/regexp.html ), и для проверки данных вы должны использовать триггер, поскольку MySQL не поддерживает ограничение CHECK (вы всегда можете перейти на PostgreSQL в качестве альтернативы :). NB! Имейте в виду, что хотя MySQL имеет конструкцию ограничения CHECK, к сожалению, MySQL (до сих пор 5.6) не проверяет данные на контрольные ограничения. Согласно http://dev.mysql.com/doc/refman/5.6/en/create-table.html : «Предложение CHECK анализируется, но игнорируется всеми механизмами хранения».
Вы можете добавить контрольное ограничение для телефона столбца:
CREATE TABLE data (
phone varchar(100)
);
DELIMITER $$
CREATE TRIGGER trig_phone_check BEFORE INSERT ON data
FOR EACH ROW
BEGIN
IF (NEW.phone REGEXP '^(\\+?[0-9]{1,4}-)?[0-9]{3,10}$' ) = 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Wroooong!!!';
END IF;
END$$
DELIMITER ;
INSERT INTO data VALUES ('+64-221221442'); -- should be OK
INSERT INTO data VALUES ('+64-22122 WRONG 1442'); -- will fail with the error: #1644 - Wroooong!!!
Однако вы не должны полагаться только на MySQL (уровень данных в вашем случае) для проверки данных. Данные должны быть проверены на всех уровнях вашего приложения.