一、泛型基本概念
1、什么是泛型
泛型就是参数化类型,使用广泛的类型;声明时使用泛型,使用时指定具体类型
2、泛型常见的字母及对应含义
T :Type表示类型
K V:分别表示键值对中的key和value
E:表示Element元素类型
? :表示不确定的类型
3、泛型的优点:省心、安全
(1)安全:在编译时检查类型安全
(2)省心:所有的强制转换都是自动和隐式的,同一套代码可以用于多种数据类型,提高代码的重用率
public class Student<T1,T2> {
private T1 name;
private T2 age;
public T1 getName() {
return name;
}
public void setName(T1 name) {
this.name = name;
}
public T2 getAge() {
return age;
}
public void setAge(T2 age) {
this.age = age;
}
public static void main(String[] args) {
//使用时指定类型
Student<String,Integer> stu = new Student<String,Integer>();
//安全:类型检查
stu.setName("张三");
//stu.setAge("20"); 类型检查报错
//省心:类型转换
String str = stu.getName();
}
}
4、泛型类
泛型类:定义类时使用泛型,使用时确定类型
注意事项:
1、泛型声明时不能使用在静态属性和静态方法上(因为静态方法属性在编译时确定类型)
2、泛型字母只能使用引用类型,不能使用基本类型
package cn.cjy.generics;
/**
* 泛型类:定义类时使用泛型,使用时确定类型
* 1、泛型声明时不能使用在静态属性和静态方法上(因为静态方法属性在编译时确定类型)
* 2、泛型字母只能使用引用类型,不能使用基本类型
*/
public class Student<T1,T2> {
private T1 name;
private T2 age;
public T1 getName() {
return name;
}
public void setName(T1 name) {
this.name = name;
}
public T2 getAge() {
return age;
}
public void setAge(T2 age) {
this.age = age;
}
public static void main(String[] args) {
//使用时指定类型
Student<String,Integer> stu = new Student<String,Integer>();
//安全:类型检查
stu.setName("张三");
//stu.setAge("20"); 类型检查报错
//省心:类型转换
String str = stu.getName();
}
}
5、泛型接口
接口中,泛型字母只能使用在方法中,不能使用在全局常量中
/**
* 泛型接口:接口中,泛型字母只能使用在方法中,不能使用在全局常量中
*
*/
public interface Comparator<T> {
void comparator(T t);
}
6、泛型方法
泛型方法<>:定义在返回类型前面
1、只能访问对象信息,不能修改对象信息
2、extends <=:表示T只能是Closeable及其子类 (…表示可变参数)
package cn.cjy.generics;
import java.io.Closeable;
import java.io.IOException;
/**
* 泛型方法<>:定义在返回类型前面
* 1、只能访问对象信息,不能修改对象信息
* 2、extends <=:表示T只能是Closeable及其子类 (...表示可变参数)
*
*/
public class MethodTest {
public static void main(String[] args) {
test("测试"); // T-->String
}
//泛型方法
public static <T> void test(T t){
System.out.println(t);
}
//extends <=:表示T只能是Closeable及其子类 (...表示可变参数)
public static <T extends Closeable> void test(T... t){
for(T temp:t){
try {
if(null!=temp){
temp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二、泛型的使用
1、父类为泛型类的继承
(1)属性类型:在父类中属性类型随父类定,在子类中属性类型随子类定
(2)重写方法类型:随父类而定
(3)泛型擦除:要么子类、父类同时擦除,要么子类>=父类类型,不能子类擦除父类泛型
a、继承或实现不指定类型
b、使用时不指定类型,统一Object类型对待,但是不完全等同于Object,编译时不会类型检查
package cn.cjy.generics;
/**
* 父类为泛型类
* 1、属性
* 2、方法
*泛型擦除:要么子类、父类同时擦除,要么子类>=父类类型,不能子类擦除父类泛型
*1、属性类型:在父类中属性类型随父类定,在子类中属性类型随子类定
*2、重写方法类型:随父类而定
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t);
}
/**
* 子类声明时指定具体类型
* 1、属性类型为具体类型
* 2、方法类型为具体类型
*/
class child1 extends Father<String,Integer>{
String str;
@Override
public void test(String t) {
}
}
/**
* 子类为泛型类,类型在使用时确定
* 子类的泛型个数大于等于父类,父类有的子类都要要
*
*/
class child2<T,T1,T2> extends Father<T,T1>{
T1 t1;
@Override
public void test(T t) {
}
}
/**
* 泛型的擦除:子类为泛型类,父类不指定类型,重写方法使用Object替换泛型
*
*/
class child3<T,T1> extends Father{
T1 t1;
@Override
public void test(Object t) {
}
}
/**
* 子类与父类泛型同时擦除:子类为泛型类,父类不指定类型,重写方法使用Object替换泛型
*
*/
class child4 extends Father{
String name;
@Override
public void test(Object t) {
}
}
/**
* 子类擦除,父类使用泛型:错误的使用
*
class child4 extends Father{
String name;
@Override
public void test(Object t) {
}
}
*/
2、泛型接口的实现
package cn.cjy.generics;
/**
* 泛型接口
* 重写方法类型随父类而定
*
*/
public interface Comparator01<T> {
void compare(T t);
}
//声明子类指定具体类型
class test implements Comparator01<String>{
@Override
public void compare(String t) {
}
}
//父类子类同事擦除
class test1 implements Comparator01{
@Override
public void compare(Object t) {
}
}
//父类擦除,子类泛型
class test2<T> implements Comparator01{
@Override
public void compare(Object t) {
}
}
//子类泛型>=父类泛型
class test3<T,T1> implements Comparator01<T>{
@Override
public void compare(T t) {
}
}
3、泛型实现多态效果:使用通配符?
(1)多态,泛型没有多态!
package cn.cjy.generics;
/**
* 多态
* 1、形参多态
* 3、返回类型多态
*
*/
public class Fruit {
}
class Apple extends Fruit{
}
class Test{
public static void main(String[] args) {
Fruit f = new Apple();
}
//形参使用多态
public static void test1(Fruit t){
}
//返回类型使用多态
public static Fruit test2(){
return new Apple();
}
}
(2)泛型使用通配符?
a、类型不定,使用时确定类型
b、可以用在声明类型、声明方法参数上,不能用在声明类上或者使用时
c、可以接收泛型的任意类型,只能接收和输出,不能修改
d、? extends 泛型上限 <= 指定类型为自身或子类
e、? super 泛型下限 >= 指定类型为自身或父类
package cn.cjy.generics;
/**
* 通配符?的使用:
* 1、类型不定,使用时确定类型
* 2、可以用在声明类型、声明方法参数上,不能用在声明类上或者使用时
* 3、可以接收泛型的任意类型,只能接收和输出,不能修改
* 4、? extends 泛型上限 <=
* 5、? super 泛型下限 >=
*
*/
public class StudentTest<T> {
T score;
public static void main(String[] args) {
StudentTest<?> stu = new StudentTest<String>();
test(new StudentTest<String>());
test1(new StudentTest<Apple>()); //类似与多态的效果
//test2(new StudentTest()); 报错,泛型没有多态
test3(new StudentTest<Object>());
}
public static void test(StudentTest<?> stu){
}
public static void test1(StudentTest<? extends Fruit> stu){
}
public static void test2(StudentTest<Fruit> stu){
}
public static void test3(StudentTest<? super Fruit> stu){
}
}
4、泛型嵌套
package cn.cjy.generics;
/**
* 泛型嵌套
*
*/
public class TestNest<T> {
T stu;
public static void main(String[] args) {
//泛型的嵌套
TestNest<StudentTest<String>> test = new TestNest<StudentTest<String>>();
//从外到内拆封
test.stu = new StudentTest<String>();
StudentTest<String> stu = test.stu;
String score = stu.score;
System.out.println(score);
}
}
三、注意事项
1、泛型没有多态
2、没有泛型数组,声明可以使用,不能创建泛型数组
四、instanceof用法总结
instanceof用于测试左边的对象是否是右边的类或其子类的实例,返回 boolean 的数据类型
package cn.cjy.generics;
/**
* instanceof的用法
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
public class TestInstanceof {
public static void main(String[] args) {
List list = new ArrayList();
test(list);
}
public static void test(Object o) {
if (o instanceof Vector){
System.out.println("对象是 Vector类的实例");
}
else if (o instanceof ArrayList){
System.out.println("对象是ArrayList类的实例");
}
else{
System.out.println("对象是 " + o.getClass() + " 类的实例");
}
}
}