1. 通配符的引出
在程序中追加了泛型之后,可以避免ClassCastException
的问题,但是又会产生新的情况:参数的统一的问题。
举例:方法中的参数类型与接收到的参数类型不匹配
public class TestMessage{
public static void main(String[] args) {
Message<Integer> message = new Message<>();
message.setMessage(20);
//fun(message); 与fun()方法中的类型不匹配,报红
}
//此处方法参数的Message泛型类型是String
private static void fun(Message<String> message) {
System.out.println(message.getMessage());
}
}
class Message<T> {
private T message;
public void setMessage(T message){
this.message = message;
}
public T getMessage(){
return this.message;
}
@Override
public String toString() {
return "TestMessage{" +
"message=" + message +
'}';
}
}
那么为了解决上述问题,可以接受所有的泛型类型,又不能让用户随意修改,这种情况下就要使用 通配符 来处理
举例:使用通配符
public class TestMessage{
public static void main(String[] args) {
Message<Integer> message = new Message<>();
message.setMessage(20);
fun(message);
Message<String> message1 = new Message<>();
message1.setMessage("hello");
fun(message1);
}
//其中?可以表示任意类型,但是因为不确定类型,所以无法进行修改
private static void fun(Message<?> message) {
//message.setMessage(100); 无法修改
System.out.println(message.getMessage());
}
}
1.2. 泛型上限
在通配符的基础上,又产生了两子通配符。泛型上限和泛型下限。
- ? extends 类:设置泛型上限
比如:? extends Number :因为存在继承关系,所以?表示子类,而Number就是它的上限。它表示只能够设置Number或者其子类,例如:Integer、Double- 泛型上限既可以使用在类上,又可以使用在方法上
举例1:方法使用泛型上限
public class TestMessage{
public static void main(String[] args) {
Message<String> message1 = new Message<>();
message1.setMessage("hello");
fun(message1);
}
// 因为String类被final修饰,所以没有子类,此处只能放String
private static void fun(Message<? extends String> message) {
System.out.println(message.getMessage());
}
}
举例2:方法使用泛型上限
public class TestMessage{
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMessage("hello");
fun(message);
Message<StringBuffer> message1 = new Message<>();
message1.setMessage(new StringBuffer().append("hello").append("world"));
fun(message1);
}
private static void fun(Message<? extends CharSequence> message) {
System.out.println(message.getMessage());
}
}
以下是CharSequence的已知实现类:
举例:类使用泛型上限
public class Point6 <T extends CharSequence>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public T getX(){
return this.x;
}
public void setY(T y){
this.y = y;
}
public T getY(){
return this.y;
}
@Override
public String toString() {
return "Point6{" +
"x=" + x +
", y=" + y +
'}';
}
public static void main(String[] args) {
Point6<String> p1 = new Point6<>();
p1.setX("hello");
System.out.println(p1);
Point6<StringBuffer> p2 = new Point6<>();
p2.setY(new StringBuffer().append("hello").append(" world"));
System.out.println(p2);
}
}
1.3. 泛型下限
- ? super 类 :设置泛型下限
比如:< ? super Integer >, ? 表示的是Integer , Number , Object
举例:使用泛型下限
public class TestMessage{
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMessage("hello");
fun(message);
}
private static void fun(Message<? super String> message) {
message.setMessage("world"); //此处可以进行修改!!!
System.out.println(message.getMessage());
}
}
总结:
- 上限可以用在声明,不能修改;
- 下限只能用在方法参数中,不能使用在泛型类中,可以修改内容
2. 泛型接口
- 泛型除了定义在类中,也可以定义在接口里面,这种情况成为泛型接口。
- 泛型接口定义和泛型类区别不大
- 泛型接口的实现类:
- 可以继续是接口的泛型类
- 不是泛型类,接口处可以指定具体类型
- 定义一个泛型接口:
interface IMessage<T> { //在接口上定义了泛型
public void print(T t);
}
举例:使用泛型接口
public interface IMessage<T> {
void print(T t);
public static void main(String[] args) {
IMessage<String> qq = new QQMessage();
qq.print("hello");
MsnMessage<Integer> msn = new MsnMessage<>();
msn.print(100);
}
}
//继承原来的类型
class QQMessage implements IMessage<String>{
@Override
public void print(String t) {
}
}
//指定新的类型
class MsnMessage<T> implements IMessage<T>{
@Override
public void print(T t) {
}
}
举例:使用匿名内部类
public interface IMessage<T> {
void print(T t);
public static void main(String[] args) {
new IMessage<String>() {
@Override
public void print(String str) {
System.out.println(str);
}
}.print("hello");
}
}