Java——泛型

本文深入探讨Java中的高级特性,包括可变参数的使用,foreach循环的便利性,静态导入的注意事项,以及泛型的全面解析,涵盖泛型的引入、基本使用、泛型方法、通配符、泛型接口和泛型擦除等关键概念。

目录

1.可变参数

2.foreach循环

3.静态导入

4.泛型

4.1 引入

4.2 基本使用

4.3 泛型方法

4.4 通配符

4.5 泛型接口

4.6 泛型擦除(语法糖)


1.可变参数

可变参数的本质是数组

public [static] [final] 返回值 方法名称([参数类型 参数名称][参数类型 ... 参数名称]){}

代码示例:

/**
 * 可变参数
 * Author: qqy
 */

public class Test {
    public static void main(String[] args) {
        System.out.println(add1());
        System.out.println(add1(1));
        System.out.println(add1(1,2));
        System.out.println(add1(1,2,3,4,5));//随意传递内容、个数
        System.out.println(add1(null));
        System.out.println(add1(new int[]{1,2,3}));//可变参数可以接收数组
    }

        //int...data => int[]
    public static int add1(int...data) {
        if(data==null){
            return 0;
        }
        int sum=0;
        for(int i=0;i<data.length;i++){
            sum+=data[i];
        }
        return sum;
    }
}
  • 如果要传递多个参数,一个方法有且只能有一个可变参数,且可变参数一定放在最后(可变参数的个数不确定,因此需要将确定的参数置于前面)
/**
 * 传递多类参数(包含可变参数)
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        print("hello");
        print("hello", " world ");
        String str1 = "C'est";
        String str2 = "la";
        String str3 = "vie!";
        System.out.println(str1 + " " + str2 + " " + str3);
        print(str1, " ", str2, " ", str3);
    }

    //传递多类参数,可变参数一定放在最后,并且只能设置一个可变参数
    public static void print(String message, String... args) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(message);
        for (int i = 0; i < args.length; i++) {
            stringBuilder.append(args[i]);
        }
        System.out.println(stringBuilder.toString());
    }
}

注意:

    //两个方法一样,不是方法重载
    public static void hello(String[] args){
    
    }
    
    public static void hello(String...args){
    
    }

2.foreach循环

用于数组 / 类集的简单输出;如需对类集 / 数组进行修改,仍用for循环。

for(数据类型 临时变量 : 数组(集合)) {
    // 循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量
}
  • 缺点:无法通过下标获取元素
/**
 * foreach循环
 * Author: qqy
 */
public class Test2 {
    public static void main(String[] args) {
        int[] intArray = new int[]{1, 2, 3, 4, 5};
        for (int anIntArray : intArray) {
            //每次循环(intArray)的时候会将数组中的元素赋值给变量(anIntArray)
            System.out.println(anIntArray);
        }
    }
}

3.静态导入

  • Java 支持静态导入 , 但是不建议使用——如果方法重名可能存在二义性;建议通过类名调用

  • 当本类中出现与静态导入方法名相同的方法,则执行本类中的方法

  • 如果代码中同时使用的两个类名相同,包名不同 => 全限定名不同,建议使用类的全限定名调用方法

    eg:java.lang.String      com.qqy.String

package com.qqy.java.util;

public class MyMath {
    public static int add(int x, int y) {
        return x + y;
    }

    public static int sub(int x, int y) {
        return x - y;
    }
}
package com.qqy.java.test;

import static com.qqy.java.util.MyMath.*; // 静态导入

public class TestDemo {
    public static void main(String[] args) {
        System.out.println(add(10, 20));  //静态导入后,使用方法时不用通过类名调用,直接通过方法名使用
        System.out.println(sub(30, 10));
    }
}

4.泛型

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

  • 4.1 引入

为了在运行时,明确数据类型,引入泛型。

/**
 * 引入泛型
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) {
        //将10装箱为Integer,再向上转型为Object
        Point intPoint=new Point(10,20);
        System.out.println(intPoint);
        //强制类型装换——向下转型 Object->int
        int intX = (int) intPoint.getX();
        int intY = (int) intPoint.getY();
        System.out.println("(" + intX + ", " + intY + ")");

        Point doublePoint = new Point(10.2D, 20.2D);
        double doubleX = (double) doublePoint.getX();
        double doubleY = (double) doublePoint.getY();
        System.out.println("(" + doubleX + ", " + doubleY + ")");

        Point stringPoint = new Point("东经80度", "北纬30度");
        String stringX = (String) stringPoint.getX();
        String stringY = (String) stringPoint.getY();
        System.out.println("(" + stringX + ", " + stringY + ")");
    }
}

class Point {

    private Object x;

    private Object y;

    public Point(Object x, Object y) {
        this.x = x;
        this.y = y;
    }

    public Object getX() {
        return x;
    }

    public Object getY() {
        return y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}
  • 4.2 基本使用

  • 基本语法
//T 被称作是类型参数,用于指代任何类型
class MyClass<T> {
     T value1;
}

T 代表一般的任何类

E 代表 Element 的意思,或者 Exception 异常的意思

K 代表 Key 的意思  V 代表 Value 的意思,通常与 K 一起配合使用 —— 键值对,见Map集合

S 代表 Subtype 的意思

  • 泛型只能接受类,所有的基本数据类型必须使用包装类
/**
 * 泛型  x、y数据类型相同
 * Author: qqy
 */
public class Test2 <T>{
    private T x;
    private T y;

    public Test2(T x, T y) {
        this.x = x;
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public T getY() {
        return y;
    }

    public static void main(String[] args) {
        //JDK1.7之后(包含1.7)第二个<>中的内容可以省略

        //Test2 Integer
        Test2<Integer> point=new Test2<>(10,20);
        Integer x=point.getX();
        Integer y=point.getY();
        System.out.println("("+x+","+y+")");

        //Test2 String
        Test2<String> point1=new Test2<>("东经20度","北纬50度");
        String strX=point1.getX();
        String strY=point1.getY();
        System.out.println("("+strX+","+strY+")");
    }
}
/**
 * 泛型  x、y数据类型不同
 * Author: qqy
 */
public class Test1<T,S> {
    private T x;
    private S y;

    public Test1(T x, S y) {
        this.x = x;
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public S getY() {
        return y;
    }

    public String toString(){
        return "Test1{\""+
                "x="+x+
                " y="+y+
                "\"}";
    }

    public static void main(String[] args) {
        Test1<Integer,String> point=new Test1<>(20,"你好");
        Integer x=point.getX();
        String y=point.getY();
        System.out.println("("+x+","+y+")");
    }
}
  • 4.3 泛型方法

  • 泛型方法定义
//<T>中的 T 被称为 类型参数,而方法中的 T 被称为参数化类型,它不是运行时真正的参数。
class MyClass {
    public <T> void testMethod(T t) {
        System.out.println(t);
    }
}
  • 当泛型类与泛型方法共存时,泛型类中的类型参数与泛型方法中的类型参数没有关系,泛型方法始终以自己定义的类型参数为准。
  • 规范:泛型方法类型参数与泛型类的类型参数不同名
/**
 * 泛型方法
 * Author: qqy
 */

//只有方法中有<*>,才是泛型方法
public class Test3 <T>{
    private T msg;

    //构造方法
    public Test3(T msg) {
        this.msg=msg;
    }

    public T getMsg() {
        return msg;
    }

    //普通方法,括号中的T只与类有关
    public void method(T t){
        System.out.println(t);
    }

    //泛型方法
    //泛型方法与泛型类相互独立
    //此时的<T>与泛型类中的<T>无关
    public static <T> void print(T data){
        System.out.println(data);
    }

    public static <T,S> void print(T data,S value){
        System.out.println(data+" "+value);
    }

    //带返回值的泛型方法
    //<T> 声明是泛型方法,T 返回值,括号中的T是泛型参数
    public static <T> T convert(T data){
        return data;
    }

    //成员方法
    public <E> void msgprint(E value){
        System.out.println(value);
    }

    public static void main(String[] args) {
        print("hello");
        print(21);
        print(new Test1<>(22,"你好"));
        print("bonjour",18);

        Test3<String> msg=new Test3<>("c'est la vie");
        System.out.println(msg.getMsg());

        msg.msgprint("Amour");

        System.out.println(convert(33));
        System.out.println(convert("bonjour"));
    }
}
  • 4.4 通配符

解决参数统一问题

  • 方法中的参数应用了通配符,则参数不能修改
  • 通过泛型上限、下限对泛型进行限制
  • 泛型下限可以修改下限类型的内容
  • 4.4.1  ?

用于方法中,表示参数可以接收任意类型的泛型类

  • 在方法中,只能取得类中数据,不能修改数据——类型不确定,无法设置确定类型
/**
 * 通配符——用于方法中
 * Author: qqy
 */
public class Test4 {
    public static void main(String[] args) {
        MyClass<Double> my=new MyClass<>();
        my.setValue(10.2);
        print(my);
    }

    public static void print(MyClass<?> my){
        //通配符不可修改
        //my.setValue(200);
        System.out.println(my.getValue());
    }
}

class MyClass<T>{
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
  • 4.4.2  ? extends 类

设置 / 取得泛型的上限,可用在方法 / 类中

//泛型必须是Number及其子类
? extends Number
  • 用在类上 T  extends 类:T必须为类或者类的子类
  • 用在方法上  ? extends 类:只能接收类或者其子类的泛型类;只能取得类中属性值,不能修改值(发生父类到子类的向下转型,需要强转,由于具体子类不确定,因此无法转型)
/**
 * 泛型上限
 * Author: qqy
 */
public class Test5 {
    public static void main(String[] args) {
        MyClass1<Integer> my1 = new MyClass1<>();
        my1.setValue(123);
        print(my1);
    }

    public static void print(MyClass1<? extends Number> my) {
        System.out.println(my.getValue());
    }
}

//类中设定泛型上限不能用?
class MyClass1<T extends Number> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
  • 4.4.3  ? super 类

设置 / 取得泛型的下限,只能用于方法中

//此方法只能取String及其父类Object
? super String
  • 可以修改属性值(子类到父类时自动的向上转型)
/**
 * 泛型下限
 * Author: qqy
 */
public class Test6 {
    public static void main(String[] args) {
        MyClass<String> my1 = new MyClass<>();
        my1.setValue("bonjour");
        print(my1);
    }

    public static void print(MyClass<? super String> my) {
        System.out.println(my.getValue());
    }
}

class MyClass<T>{
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
  • 4.5 泛型接口

interface IGeneric<T>{
    T test(T t);
}
  • 两种实现:

子类继续保留泛型  /  子类定义时给出具体类型

/**
 * 泛型接口
 * Author: qqy
 */
public class Test7 {
    public static void main(String[] args) {
        IGeneric<Integer> iGeneric=new GenericImpl<Integer>();
        System.out.println(iGeneric.test(25));
        IGeneric iGeneric1=new GenericImpl1();
        System.out.println(iGeneric1.test("bonjour"));
    }
}

interface IGeneric<T>{
    T test(T t);
}

//1.子类继续保留泛型
class GenericImpl<T> implements IGeneric<T>{

    @Override
    public T test(T t) {
        return t;
    }
}

//2.子类定义时给出具体类型
class GenericImpl1 implements IGeneric<String>{

    @Override
    public String test(String s) {
        return s;
    }
}
  • 4.6 泛型擦除(语法糖)

泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉——类型擦除。即:泛型类在JVM中与普通类无异。

  • 验证方式:instanceof、getClass

  • 泛型类进入JVM之前会进行类型擦除,之前泛型类的类型参数若没有指定上限,会被擦除成为Object类型。如果指定上限,则类型参数被替换为相应上限。

/**
 * 泛型擦除
 * Author: qqy
 */
public class Test8 {
    public static void main(String[] args) {
        Message<String> message1 = new Message<>();
        message1.setMessage("hello");

        Message<Integer> message2 = new Message<>();
        message2.setMessage(100);

        System.out.println(message1.getMessage());
        System.out.println(message2.getMessage());

        //利用instanceof验证
        System.out.println(message1 instanceof Message);
        System.out.println(message2 instanceof Message);

        //利用getClass()返回的类型验证
        System.out.println(message1.getClass().getName());
        System.out.println(message2.getClass().getName());
    }
}

class Message<T> {

    private T message;

    public T getMessage() {
        return message;
    }

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值