@(工作笔记)
generic-record
[TOC]
泛型(Generics)
- 泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可能。
- 在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型
泛型之前
- 类别定义时的逻辑完全一样,只是里面成员变量的类型不同
- 如果需要多个相似的类,需要定义多个文件,不同的只是变量的类别,而逻辑是完全一样的
所谓泛型:就是变量类型的参数化。
类中使用
class Person<T, K, A, V> {
private String username;
private T friend;
private K country;
private A[] address;
private Object[] versions;
static {}
{}
public void getSimpleAddress() {
// 没有办法消除警告,只能强转
address = (A[]) new Objects[10];
}
public V getSimpleVersions(int index) {
// 没有办法消除警告,只能强转,ArrayList也是这么实现的,参考get方法
return (V) versions[index];
}
Person() {}
public Person(String username, T friend) {
this.username = username;
this.friend = friend;
}
@Override
public String toString() {
return new StringJoiner(", ", Person.class.getSimpleName() + "[", "]")
.add("username='" + username + "'")
.add("friend=" + friend)
.add("country=" + country)
.add("address=" + Arrays.toString(address))
.toString();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public T getFriend() {
return friend;
}
public void setFriend(T friend) {
this.friend = friend;
}
public K getCountry() {
return country;
}
public void setCountry(K country) {
this.country = country;
}
public A[] getAddress() {
return address;
}
public void setAddress(A[] address) {
this.address = address;
}
}
限制泛型可用类型
- 在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型
必须是继承某个类,或者实现某个接口
· - 当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入
class Human {
}
class Person<F extends Human> {
private F friend;
public F getFriend() {
return friend;
}
public void setFriend(F friend) {
this.friend = friend;
}
}
- 使用<?>或是<? extends SomeClass>的声明方式,意味着你只能通过该名称来取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的事SomeClass的子类,但不确定是什么类的实例,编译器不让你加入信息,理由是,如果可以键入信息的话,那么你就得记得取回的实例是什么类型,然后转换为原来的类型方可进行操作,这就失去了使用泛型的意义。
java 泛型中 T 和 问号(通配符)的区别
https://blog.csdn.net/jianghuxiaojin/article/details/51457773
通配符(?)
当在赋值
的时候,上面一节说赋值的都是为具体类型,当赋值的类型不确定的时候,我们用通配符(?)代替了:
List<?> unknownList;
List<? extends Number> unknownNumberList;
List<? super Integer> unknownBaseLineIntgerList;
在Java集合框架中,对于参数值是未知类型的容器类,只能读取其中元素,不能向其中添加元素, 因为,其类型是未知,所以编译器无法识别添加元素的类型和容器的类型是否兼容,唯一的例外是NULL
Java 泛型 <? super T> 中 super 怎么 理解?与 extends 有何不同?
https://www.zhihu.com/question/20400700
Plate<? extends Fruit>
翻译成人话就是:一个能放水果以及一切是水果派生类的盘子。再直白点就是:啥水果都能放的盘子。这和我们人类的逻辑就比较接近了。Plate<? extends Fruit>和Plate
在这个体系中,上界通配符 “Plate<? extends Fruit>” 覆盖下图中蓝色的区域。
什么是下界?
相对应的,“下界通配符(Lower Bounds Wildcards)**”**:
Plate<? super Fruit>
表达的就是相反的概念:一个能放水果以及一切是水果基类的盘子。Plate<? super Fruit>是Plate
下界<? super T>不影响往里存,但往外取只能放在Object对象里
使用下界<? super Fruit>会使从盘子里取东西的get( )方法部分失效,只能存放到Object对象里。set( )方法正常。
Plate<? super Fruit> p=new Plate<Fruit>(new Fruit());
//存入元素正常
p.set(new Fruit());
p.set(new Apple());
//读取出来的东西只能存放在Object类里。
Apple newFruit3=p.get(); //Error
Fruit newFruit1=p.get(); //Error
Object newFruit2=p.get();
因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是Fruit的基类,那往里存粒度比Fruit小的都可以。但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失。
定义含有泛型的方法
泛型定义在方法的修饰符和返回值类型之间
格式
修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)) {
方法体
}
含有泛型的方法,在调用方法的时候确定泛型的数据类型,传递什么类型参数,泛型就是什么类型
public static <T> void foo(T t) {
dlog(t.getClass(), new Info("t.getClass()"));
}
// public static <T> 是声明该方法是泛型函数