一.泛型
·定义:守门员,主要用于参数的校验
·<>钻石操作符,表示泛型,在一个类或者方法上看到<>,表示使用了泛型
< T > T为类型参数,可以用任意字符来表示,一般用大写字母表示。例如:K,V E等等
·泛型方法中的<T>和泛型类中<T>是否是一个东西
泛型方法始终以自己的类型参数为基准,和类中的泛型无关,声明泛型方法,一般与类使用不同的类型参数。
public class MyClass <T>{
private T t1;
//返回值为T的普通函数
public T getT1(){
return t1;
}
//参数为T的普通函数
public void setT1(T t1){
this.t1 = t1;
}
//泛型函数
public <T> void fun (T t){
}
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.setT1("123");
myClass.fun(123);
}
}
·泛型接口:
//泛型接口,带一个类型参数
interface Imessage<T>{
void printMsg(T t);
}
//子类实现接口时,要么继续保留泛型,要么规定类型参数
class MessageImp1<T> implements Imessage<T> {
@Override
public void printMsg(T t) {
System.out.println(t);
System.out.println("仍然是泛型类");
}
}
//为普通类
class MessageImp2 implements Imessage<Number>{
@Override
public void printMsg(Number number) {
System.out.println(t);
System.out.println("普通类");
}
·内部类:将一个类嵌套到另一个类的内部;
内部类分为:成员内部类;静态内部类;方法内部类;匿名内部类
成员内部类:直接定义在类的内部,不加static关键字-》成员方法,必须依附外部类的存在,产生对象必须先产生外部类对象;不能拥有静态域,可以访问外部类成员方法和静态域;
静态内部类:直接定义在类的内部,使用关键字static修饰,类比静态方法,和其他类没区别;
能够拥有成员域,不能访问外部类的成员域(没传入外部对象,无法访问)
public class MyOutter<T> {
private class Inner{
public void Test(T t2){
System.out.println(t2);
}
}
public static class Inner2<T>{
public void fun(T t1){
System.out.println(t1);
}
}
public static void main(String[] args) {
MyOutter<String> outter = new MyOutter<>();
//成员内部类创建
MyOutter<String>.Inner inner = outter.new Inner();
inner.Test("123");
//静态内部类的创建
MyOutter.Inner2<Integer> inner2 = new Inner2<>();
inner2.fun(123);
}
}
·非静态内部类回复用外部类型参数,静态内部类不会复用外部类的泛型参数
public class Outter {
public static void main(String[] args) {
Outter outter = new Outter();
outter.fun();
}
private int age = 18;
private static String country = "china";
public void fun(){
Inner1 inner1 = new Inner1();
inner1.test();
}
//内部成员类
public class Inner1{
public void test(){
System.out.println(Outter.this.age);
System.out.println(country);
}
}
//静态内部类
public static class Inner2{
private int a = 10;
private static double hehe = 10.0;
public void fun(){
System.out.println(country);
//error
//System.out.println(age);
}
}
}
二.通配符
由于泛型的强类型校验,不同的类型完全不能通过校验,要匹配不同的类型的对象,就得重载很多的方法,这样就本末倒置,搞复杂
因此采用通配符
<?>一般用在方法参数中,可以接受该类所有类型的泛型变量
public class Message<T> {
private T msg;
public T getMsg(){
return msg;
}
public void setMsg(T msg){
this.msg = msg;
}
public static void main(String[] args) {
Message message = new Message();
message.setMsg("string类型");
fun(message);
Message message1 = new Message();
message1.setMsg(123);
fun(message1);
}
public static void fun(Message <?> msg){
System.out.println(msg.getMsg());
}
<?>只能调用getter方法获取属性,由于根本无法确定传入对象的类型,因此无法调用对象的setter来设置值。
·设置泛型的上限
<? extends 类>
?表示任意类型,但是必须时后面类的子类
<? extends Number> ?可以是Number类本身,也可以是其子类,除此之外都不行。但是子类之间不能够相互转换;
extends 也可以用在泛型类的定义上
·设置泛型的下限
下限通配符
< ? super 类> 此时?可以代表任意后面类的父类,只能够用在方法参数中,不能够用于类的类型参数
public class Message<T extends String> {
private T msg;
public T getMsg(){
return msg;
}
public void setMsg(T msg){
this.msg = msg;
}
public static void main(String[] args) {
Message message = new Message();
message.setMsg("string类型");
fun(message);
Message message1 = new Message();
message1.setMsg(123);
fun(message1);
}
public static void fun(Message <? super String> msg){
System.out.println(msg.getMsg());
}
}
三.泛型擦除
泛型是典型的语法糖(只在编译期有效,属于我们为了方便程序开发引入的一种新的机制,在编译后消失),类似于我们c语言中的宏定义
·所有泛型类型参数,若没有设置泛型上限,则编译之后统一擦除为Object类型,若设置了类型上限,则编译器统一擦除为响应的泛型上限