欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaSE 高级开发之泛型

程序员文章站 2022-06-04 23:16:55
...

JDK1.5新特性—泛型

在JDK1.5中泛型是非常重要的实现技术,泛型可以帮助我们解决程序的参数转换问题

1、泛型类的基本使用

泛型类指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而在类使用时再进行属性类型的定义

泛型类的基本语法:
被的形式定义的类称为泛型类

class Myclass <T>{//T被称为类型参数,用于指代任何类型
    T value;
}

使用泛型类:

    Myclass<String> myclass1 = new Myclass<>();
    Myclass<Integer> myclass2 = new Myclass<>();

注意:泛型只能接受类,所有的基本数据类型必须使用包装类

泛型类接受多个类型参数:

class Myclass <T,E>{
    T value1;
    E value2;
}

public class FanTest {
    public static void main(String[] args) {
        Myclass<String, Integer> myclass1 = new Myclass<>();
        Myclass<Integer, String> myclass2 = new Myclass<>();
    }
}

使用泛型类定义一个坐标类:

class Point <T>{
    private T x;
    private T y;

    public T getX() {
        return x;
    }

    public void setX(T x) {
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }
}

public class FanTest {
    public static void main(String[] args) {
        //设置数据
        //Point<String> p = new Point<>();//JDK1.5 语法
        Point p = new Point();//JDK1.7以后可以使用的语法
        p.setX("东经80度");
        p.setY("北纬60度");
        //取出数据
        String x = p.getX();
        String y = p.getY();
        System.out.println("X = "+ x+", y = "+y);
    }
}

泛型的出现彻底改变了向下转型的需求,在泛型定义时,如果明确设置了类型,则为设置的类型;如果没有设置类型,默认为Object类型

2、泛型方法

泛型不仅可以用于定义类,还可以单独来定义方法

class MyClass{
    public <T> void testMethod(T t){//<T>写在返回值类型前面
        System.out.println(t);
    }
}

泛型方法定义时,中的T被称为类型参数,方法中的T被称为参数化类型,它不是运行时真正的参数

声明的参数类型也可以当做返回值类型

class MyClass{
    public <T> T testMethod(T t){
        return t;
    }
}

泛型类与泛型方法共存:

class MyClass<T>{
    public void testMethod1(T t){//泛型类中的普通方法
        System.out.println(t);
    }
    public <T> T testMethod2(T t){//泛型类中的泛型方法
        return t;
    }
    //泛型方法与泛型类中的类型参数没有任何联系
    // 所以当泛型类中存在泛型方法时,为了避免混淆
    // 泛型方法最好使用如下方式来定义

//    public <E> E testMethod2(E e){
//        return e;
//    }

}

public class FanTest{
    public static void main(String[] args) {
        MyClass<String> myClass = new MyClass<>();
        myClass.testMethod1("泛型类的普通方法");
        Integer i = myClass.testMethod2(20);
        System.out.println(i);
    }
}

3、通配符:?

可以接收所有的泛型类型,但是不能让用户自己修改

class Message<T>{
    private T message;
    public T getMessage(){
        return message;
    }
    public void setMessage(T message){
        this.message = message;
    }
}
public class FanTest {
    public static void main(String[] args) {
        Message<Integer> message = new Message<>();
        message.setMessage(20);
        fun(message);
    }
    public static void fun(Message<?> temp){//使用通配符?
        //temp.setMessage(100);用户非无法修改通配符的类型
        System.out.println(temp.getMessage());
    }
}

通配符 ? 的两个子通配符:
I、?extends类:设置泛型上限:
?extends Number 表示只能够设置Number或者其子类,Integer、Double等
II、?super类:设置泛型下限
?super String 表示只能设置String及其父类Object

泛型上限:

//设置泛型上限
class Message<T extends Number>{//设置泛型上限
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}
public class FanTest {
    public static void main(String[] args) {
        Message<Integer> message = new Message<>();
        message.setMessage(123);
        fun(message);
    }
    //通配符?表示可以接收任意类型
    public static void fun(Message<? extends Number> temp){
        System.out.println(temp.getMessage());
    }
}

泛型下限:

//设置泛型下限
class Message<T>{//设置泛型下限
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}
public class FanTest {
    public static void main(String[] args) {
        Message<String> message = new Message<>();
        message.setMessage("设置泛型下限");
        fun(message);
    }

    public static void fun(Message<? super String> temp){
        temp.setMessage("可以对修改值");
        System.out.println(temp.getMessage());
    }
}

注意:泛型上限可以用在声明时,不能修改;泛型下限只能用于方法参数,可以修改内容

4、泛型接口

泛型除了可以定义在类中,也可以定义在接口里面,此时称为泛型接口

//泛型接口
interface Imessage<T>{//定义一个泛型接口
    public void print(T t);
}
class MessageImpl<T> implements Imessage<T>{//定义泛型类实现泛型接口

    @Override
    public void print(T t) {
        System.out.println(t);
    }
}
public class FanTest {
    public static void main(String[] args) {
        Imessage<String> msg = new MessageImpl<>();
        msg.print("泛型接口");
    }
}

5、类型擦除

泛型信息只存在于代码编译阶段,在进入JVM之前与泛型相关的信息将会被擦除掉,专业术语叫类型擦除,所有泛型代码可以喝之前版本的代码很好的兼容
换句话说,泛型类和普通类在Java虚拟机内没有什么区别

//类型擦除
class MyClass<T>{
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
    public void testMethod(T t){
        System.out.println(t);
    }
}
public class FanTest {
    public static void main(String[] args) {
        MyClass<String> myClass1 = new MyClass<>();
        MyClass<Integer> myClass2 = new MyClass<>();
        System.out.println(myClass1.getClass() == myClass2.getClass());
    }
}

以上代码打印结果为true,因为MyClass和MyClass在jvm中的Class都是MyClass.class

在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,
如 则会被转译成普通的 Object类型;如果指定了上限,如 则类型参数就被替换成类型上限。

class Myclass<T, E>{
    private T message;
    private E text;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }

    public E getText() {
        return text;
    }

    public void setText(E text) {
        this.text = text;
    }
    public void testMethod(T t){
        System.out.println(t);
    }
}
public class FanTest {
    public static void main(String[] args) {
        Myclass<String, Integer> myclass = new Myclass<>();
        Class cls = myclass.getClass();
        Field[] fields = cls.getDeclaredFields();
        for(Field field : fields){
            System.out.println(field.getType());
        }
		//class java.lang.Object
		//class java.lang.Object
    }
}