Find out how Java protects type integrity

what

――As a result of doing PHP for several years, my knowledge of Java has diminished, so I will recall and summarize it (mainly about complicated parts of types)

What was it that was immutable and co-changed?

--Premise) When Dog extends Animal --Array is covariant) Dog [] is a subtype of Animal [](= assignable) --Generic type is immutable) List \ and List \ are different types (= non-substitutable) ――Because it doesn't come to a pin, think about the meaning of these rules

What was the mark, T, extends, etc. that appeared in the class or method declaration?

--A class that declares a type parameter (such as T) is called a generic class. --By having a type parameter, you do not have to create a class for each type (If you create Stack \ , you do not need to create IntStack class, StringStack class ...) --In Box \ , T can be any class, so don't code using the type of T. When you want to write, limit it to Box \ etc.

class Animal {
    public int getAge() {
        return 3;
    }
}

class Dog extends Animal {
    @Override
    public int getAge() {
        return 33;
    }
    //Methods only available in the Dog class
    public String getName() {
        return "john";
    }
}

class AnimalBox<T extends Animal> {
    T someAnimal;
    
    public AnimalBox(T animal) {
        someAnimal = animal;
    }
    
    public int getAge() {
        return someAnimal.getAge();
    }
}

―― ~~ However, in this case, if you simply make it Animal type, you can insert Dogs and do the same, so I do not know how to use it properly (this is an issue) ~~ ――For the above problem, if you implement public T get (), the generic type can be returned by Dog, but AnimalBox2 can only return Animal. In the comment, I explained an example of the difference.

//This is fine
class AnimalBox2 {
    Animal someAnimal;
    
    public AnimalBox2(Animal animal) {
        someAnimal = animal;
    }
    
    public int getAge() {
        return someAnimal.getAge();
    }
}

--The <? Extends Animal> and <? Super Animal> that appear in the method declaration are different from the above generic type restrictions and are called boundary wildcard types. --Those that alleviate the invariance of the generic type. Even if it is said ... so it will be described later

class Box<T> {
    T someValue;
    List<T> history = new ArrayList<>();
    
    public Box(T v) {
        someValue = v;
    }
    
    public T get() {
        return someValue;
    }
    
    public void selectOne(Box<? extends T> box) {
        history.add(box.get());
    }
}

--The class declaration cannot be class Box \ <? Extends T>, class Box \ <? Extends Animal>, or class Box \ . You can't explain what you want to do with it.

What does it mean to forget a generic type and assign it to a subclass?

    Dog d = new Dog();
    Animal a = d; //It's a different type, but it's a subclass, so it can be assigned
        
    System.out.println(a.getClass().getName()); //Dog
    System.out.println(a.getAge()); //33
    System.out.println(d.getName()); //john
    System.out.println(a.getName()); //error: cannot find symbol

--From above) --Don't forget that the entity referenced by the Animal type variable a is Dog. --The getName method specific to Dog type cannot be used from the variable a of Animal type. -*** There is a possibility that an entity (in this case, the generated Dog) will be used as various classes above the inheritance relationship (in this case, Object, Animal, Dog) *** --Do not refer to it as a lower class. (You cannot substitute a dog for a space dog as SpaceDog extends Dog) ――Why can't you? Space dogs have a function that progresses to the one with more dark matter, but dogs do not have it, so it will be a problem at runtime.

SpaceDog sd = new Dog(); //Dog cannot be converted to SpaceDog

What does generic type invariance mean?

――What if the generic type is covariant?

        List<SpaceDog> spaceDogList = new ArrayList<>();
        List<Dog> dogList = spaceDogList; //(If it was a co-change)It's a different type, but it's a subclass, so it can be assigned
        dogList.add(new Dog());

--Dog has entered List \ via the dogList variable. This is a problem when using spaceDogList. It is immutable to prevent this. --Actually compile error: List \ cannot be converted to List \

Why are arrays covariant?

――It hasn't become. It does not result in a compile error, but it does result in a run-time error.

        SpaceDog[] spaceDogArray = new SpaceDog[1];
        Dog[] dogArray = spaceDogArray;
        dogArray[0] = new Dog(); //Run-time error:java.lang.ArrayStoreException: Dog

--* *** Arrays are run-time type safe. Generic types are compile-time type-safe *** --It's better to avoid arrays that also include subclasses

Isn't it the same for ordinary classes that are not generic types that the variable has a reference to the entity and its interpretation in class inheritance differs depending on the situation?

――You may not understand what you are saying ―― ↓ In such a case, can the variable a be used to destroy the type composition?

        Dog d = new Dog();
        Animal a = d;
        //I want to somehow use the variable a so that the variable d is in trouble for the convenience of type interpretation.

――I can only think of creating and overwriting, but d is not a problem because it is not overwritten and is created in another location.

        Dog d = new Dog();
        Animal a = d;
        System.out.println(d); //Dog@77468bd9 
        System.out.println(a); //Dog@77468bd9
        a = new Animal();
        System.out.println(a); //Animal@12bb4df8

Organizing the relationship between generic types and type parameters

--You can do this (Dog and SpaceDog itself are not generic types, so you can use SpaceDog wherever you use Dog)

        List<Dog> dogList = new ArrayList<>();
        dogList.add(new Dog());
        dogList.add(new SpaceDog());

――I can't do this

class Box<T> {
    T someValue;
    List<T> history = new ArrayList<>();
    
    public Box(T v) {
        someValue = v;
    }

    public void set(T v) {
        someValue = v;
    }
    
    public T get() {
        return someValue;
    }
    
    public void selectOne(Box<T> box) {
        history.add(box.get());
    }
}

Box<Dog> dogBox = new Box<>(new Dog());
Box<SpaceDog> spaceDogBox = new Box<>(new SpaceDog());
dogBox.selectOne(spaceDogBox); //Compile error:Box<Dog>And Box<SpaceDog>Is another type

――You can do it this way

    public void selectOne(Box<? extends T> box) {
        history.add(box.get());
    }

――Why is the type consistent? --It is prohibited to pass a value other than null to the set method (if Dog can be set, someValue of Box \ will become Dog)


    public void selectOne(Box<? extends T> box) {
        history.add(box.get());
        box.set(someValue); //Compile error
    }

What is \ <? Super T>?

--If you think that the above \ <? Extends T> "mitigates (covariantly) the invariance of the generic type by limiting the function of the variable to retrieve the value", --The super one is "relaxing (invariantly) the invariance of the generic type by limiting the function of giving a variable to a value". (Cannot be taken out) ――When and what should I use? → Put / Get principle

Summary

――If a normal class is a collection of specific target attributes and behaviors (animals, dogs, etc.), the generic type is imaged as something that wraps the summary *** in a different context. To do --There are two worlds, one is the world of normal classes (Animal, Dog, SpaceDog) that are type parameters, and the other is the world of contexts (List, Queue, Box, Optional ...) that generic types are trying to express. --The actions of "giving a value to the context" and "retrieving the value from the context" occur, but if it remains unchanged, the inheritance relationship of type parameters cannot be used, so there are large restrictions. --Relax with borderline parameters

Pattern diagram

java.png

Recommended Posts

Find out how Java protects type integrity
How to find Java prime numbers
How to use Java enum type
How to find out the Java version of a compiled class file
Java type conversion
[JAVA] Stream type
[Java] Enumeration type
Java Optional type
Java double type
java: How to write a generic type list [Note]
[Java] How to cut out a character string character by character
I tried to find out what changed in Java 9
[Java] Data type ①-Basic type
Find out about Docker
[Java, Kotlin] Type Variance
Java class type field
Type determination in Java
Java study # 1 (typical type)
[Java] About enum type
How to type backslash \
[Java] Date type conversion
Find the address class and address type from the IP address with Java
Difference between Java and JavaScript (how to find the average)
[Java] How to convert a character string from String type to byte type
Find out all timezone IDs supported by the Java TimeZone class
[Java] How to use substring to cut out a character string