1.泛型的基本使用
泛型指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使用时再进行定义。
如果要想进行这种泛型的操作,就必须做一个类型标记的声明。
eg:泛型类的基本语法
class MyClass<T> {
T value1;
}
尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型。
实际上这个T可以任意写,但出于规范的目的,Java 还是建议用单个大写字母来代表类型参数。常见的如:
- T 代表一般的任何类。
- E 代表 Element 的意思,或者 Exception 异常的意思。
- K 代表 Key 的意思 V 代表 Value 的意思,通常与 K 一起配合使用。
- S 代表 Subtype 的意思。
如果一个类被 的形式定义,那么它就被称为是泛型类。
1.1泛型类
eg:使用泛型类
MyClass<String> myClass1 = new MyClass<String>();
MyClass<Integer> myClass2 = new MyClass<Integer>();
注意:泛型只能接受类,所有的基本数据类型必须使用包装类
泛型类可以接收多个类型参数,如下所示:
eg:泛型类引入多个类型参数以及使用
class MyClass<T,E> {
T value1;
E value2;
}
public class Test {
public static void main(String[] args) {
MyClass<String,Integer> myClass1 = new MyClass<String,Integer>();
}
}
1.2泛型方法
泛型不仅可以用于定义类,还可以单独来定义方法。
eg:泛型方法定义
class MyClass{
public <T> void testMethod(T t) {
System.out.println(t);
}
}
中的 T 被称为 类型参数,而方法中的 T 被称为参数化类型,它不是运行时真正的参数。
eg:泛型方法与泛型类共存
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <T> T testMethod2(T t) {
return t;
}
}
public class Test {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.testMethod1("hello 泛型类");
Integer i = myClass.testMethod2(100);
System.out.println(i);
}
}
上面代码中,MyClass 是泛型类,testMethod1 是泛型类中的普通方法,而 testMethod2 是一个泛型方法。 而泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。
泛型类的实际类型参数是 String,而传递给泛型方法的类型参数是 Integer,两者不相干。
但是,为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数好不要同名。比如, MyClass 代码可以更改为这样
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <E> E testMethod2(E e) {
return e;
}
}
2.通配符
eg:使用通配符
public class TestDemo {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
}
// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<?> temp){
System.out.println(temp.getMessage());
}
}
在"?"的基础上又产生了两个子通配符:
- ? extends 类:设置泛型上限
- ? super 类:设置泛型下限
eg:泛型上线
class Message<T extends Number> { // 设置泛型上限
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class TestDemo {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
} // 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<? extends Number> temp){
//temp.setMessage(100); 仍然无法修改!
System.out.println(temp.getMessage());
}
}
eg:设置泛型下限
class Message<T> {
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class TestDemo {
public static void main(String[] args) {
Message<String> message = new Message() ;
message.setMessage("Hello World");
fun(message);
}
public static void fun(Message<? super String> temp){
// 此时可以修改!!
temp.setMessage("hello!");
System.out.println(temp.getMessage());
}
}
注意:上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容!
3.泛型接口
泛型除了可以定义在类中,也可以定义在接口里面。
eg:定义一个泛型接口
interface IMessage<T> {
// 在接口上定义了泛型
public void print(T t) ;
}
对于这个接口的实现子类有两种做法
eg:在子类定义时继续使用泛型
// 在接口上定义了泛型
public void print(T t) ;
}
class MessageImpl<T> implements IMessage<T> {
@Override
public void print(T t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl() ;
msg.print("Hello World");
}
}
在子类实现接口的时候明确给出具体类型
interface IMessage<T> {
interface IMessage<T> {
// 在接口上定义了泛型
public void print(T t);
}
class MessageImpl implements IMessage<String> {
@Override
public void print(String t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("Hello World");
}
}
}
760

被折叠的 条评论
为什么被折叠?



