――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)
--Premise) When Dog extends Animal
--Array is covariant) Dog [] is a subtype of Animal [](= assignable)
--Generic type is immutable) List \
--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 \
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 \
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 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 \
――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
――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
--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 \
public void selectOne(Box<? extends T> box) {
history.add(box.get());
box.set(someValue); //Compile error
}
--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
――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
Recommended Posts