目录
3.静态内部类(除了套在一个类的内部以外和其他类没任何区别)
一、泛型
<>钻石操作符,表示泛型
<T>T称为类型参数,可以用任意字符来表示,一般用单个的大写字母来表示。
1.区分泛型方法。
泛型方法始终以自己的类型参数为准,与类中的泛型无关,
一般如果声明泛型方法,我们使用不同的类型参数来区分
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);
}
2.泛型接口
在实现接口的时候,有两种选择
<1>继续保留泛型
<2>在实现时规定类型参数
interface IMessage<T>{
void printMsg(T t);
}
//1,继续保留泛型,是一个泛型类
class MessageImpl1<T> implements IMessage<T>{
@Override
public void printMsg(T t) {
System.out.println(t);
System.out.println("仍然是泛型类");
}
}
//2.就是一个普通类,实现接口的时候规定好参数的类型就是整形
class MessageImpl2 implements IMessage<Integer>{
@Override
public void printMsg(Integer integer) {
System.out.println(integer);
System.out.println("类型为Integer的普通类");
}
二、内部类
内部类:将一个类嵌套到另一个类的内部。
内部类属于封装的一种,保护内部类。
发动机和汽车这两个类的关系,发动机就是汽车的内部类
心脏就是人体的内部类
一共有几种内部类呢?
4种 成员、静态、方法、匿名内部类
成员内部类实际上JVM会传入一个隐藏的外部对象Outter.this
1.成员内部类能否拥有静态域?
不能,成员内部类必须有外部类的对象才能产生
2.成员内部类能否访问外部类的成员方法和静态域?
可以,外部类的静态域没有外部类对象都能访问,更何况现在成员内部类已经有一个外部类的对象了。
3.静态内部类(除了套在一个类的内部以外和其他类没任何区别)
静态内部类能拥有成员域
不能访问外部类的成员域(静态内部类不需要依赖外部类的对象,此时没有传入外部类对象,当然无法访问外部类的成员域)
成员内部类 | 静态内部类 | |
是否复用外部类的泛型参数 | 会 | 不会 |
这里规定了类型是String,必须使用相同类型,否则会出现错误。
三、泛型的通配符
1.案例引入
在fun方法中,方法参数中规定了形参的接收类型为Message<String>,,但是msg1提供的是一个Integer类型的变量。
由于泛型的强类型校验,不同的类型完全不能通过校验,要匹配不用类型的Message对象就得冲在很多fun方法。
这样就本末倒置,变得更加复杂了~
<?> :一般用在方法参数,表示可以接受该类所有类型的变量。但是不能用在类的名称上
只能调用对象的get方法来获取属性,不能set(由于此时根本无法确定传入对象的类型,因此无法调用对象的setter来设置值)
此时使用了通配符,就不会报错了,可以接受任意类型的参数。
2.细化通配符
1.设置类型的上限
<? extends类> 表示? 可以指代任意类型,但是该类型必须是后面类的子类
<? extends Number>此时表示? <= Number
此时?可以是Number本身,或者是Number的子类,除此之外的其他类型都不可以
?表示可以接收Number及其子类,但是子类之间是不能互相转换的(比如Int和double)
泛型的上限通配符仍然不能set具体值,只能Getter取得
T可以指代任意Number及其子类的类型,T仅限于Number及其子类的类型
2.设置类型的下限
<? super String>此时?表示必须是String及其父类
此时?只能指代String或者Object
只能用子啊方法参数,不能作用于类的类型参数
public static void fun(Message<? super String> msg){
//设置了通配符下限,可以是String或者Object
//此时就可以使用
msg.setMsg("hehe");
System.out.println(msg.getMsg());
}
下限通配符可以调用对象的setter方法设置一个具体的属性值(下限类型的)
3.类型擦除
泛型典型的“语法糖”(只在编译生效,属于我们为了方便程序开发引入的一种机制)
实际上泛型通过Javac编译之后,泛型就不见了~
所有泛型的类型参数,如果没有设置上限,则编译之后统一擦除为Object
如果设置了泛型上限,则编译之后统一擦除为相应的泛型上限
Message<Integer> msg1 = new Message();
Message<Double> msg2 = new Message<>();
Field field = msg.getClass().getDeclaredField("msg");
Field field1 = msg1.getClass().getDeclaredField("msg");
Field field2 = msg2.getClass().getDeclaredField("msg");
//field使用应该通过对象调用方法,我第一次写代码将name变为msg1,导致编译器无法找出,报错没有这个变量
System.out.println(field.getType());
System.out.println(field1.getType());
System.out.println(field2.getType());
}
public static void fun(Message<? super String> msg){
//设置了通配符下限,可以是String或者Object
//此时就可以使用
msg.setMsg("hehe");
System.out.println(msg.getMsg());
}
这就是上面说的,如果设置了泛型上限,统一擦除为相应的泛型上限
此时有两个变量一个是integer,一个是doublel类型的,都擦除为相应的泛型上限Number。
更多基础在往期的泛型博客中。泛型 -- 学会它,好处多多_mmmenxj的博客-优快云博客