Java 泛型

java 复制代码
public class MaximumTest
{
   // 比较三个值并返回最大值
   public static <T extends Comparable<T>> T maximum(T x, T y, T z)
   {                     
      T max = x; // 假设x是初始最大值
      if ( y.compareTo( max ) > 0 ){
         max = y; //y 更大
      }
      if ( z.compareTo( max ) > 0 ){
         max = z; // 现在 z 更大           
      }
      return max; // 返回最大对象
   }
   public static void main( String args[] )
   {
      System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
                   3, 4, 5, maximum( 3, 4, 5 ) );
 
      System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
                   6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
 
      System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
         "apple", "orange", maximum( "pear", "apple", "orange" ) );
   }
}

一句话概括这个程序在做什么

这个

程序定义了一个超级通用的"找最大值"方法。这个方法聪明到,无论你给它整数、小数还是字符串,它都能准确地找出最大的那个,而不需要为每种类型都写一遍代码。

第一部分:核心难点 ------ maximum 方法的签名

让我们先盯着这个最复杂的部分看:

java 复制代码
public static <T extends Comparable<T>> T maximum(T x, T y, T z)

别怕,我们把它像剥洋葱一样一层层剥开。

1. public static

这个简单,说明 maximum 是一个公开的、静态的工具方法。我们可以直接用 MaximumTest.maximum(...) 来调用它,不需要先创建 MaximumTest 的对象。

2. <T extends Comparable<T>>

这是整个程序的"大脑",也是最难理解的部分。我们把它拆成两半:

  • <T> : 这是在声明一个**"泛型"。你可以把 T 想象成一个 占位符**,它代表"任何一种类型"。在这次调用中它可能是 Integer,下次调用中它可能是 String
  • extends Comparable<T> : 这是对占位符 T一个限制或要求 。它规定:"T 不能是随便什么类型,它必须 是一个实现了 Comparable 接口的类型。"
    什么是 Comparable 接口?
    一个类如果实现了 Comparable 接口,就说明这个类的对象是"可以互相比较大小 的"。它必须提供一个 compareTo() 方法来告诉别人怎么比。
  • Integer 实现了 Comparable,所以整数可以比大小。
  • Double 实现了 Comparable,所以小数可以比大小。
  • String 实现了 Comparable,所以字符串可以按字典序比大小(比如 "pear" > "apple")。
    所以,<T extends Comparable<T>> 整句话的意思就是:

"我这个 maximum 方法,只接受那些自身可以比较大小 的类型。你传给我一个不能比较的类型,我可不干!"

这个限制是编译时的,也就是说,如果你传错了类型,代码根本编译不过去,这就保证了安全。

3. T maximum(T x, T y, T z)

这部分就简单了:

  • 返回值类型是 T:你传给我什么类型,我就返回什么类型。
  • 参数是 (T x, T y, T z):接受三个 T 类型的参数。

第二部分:maximum 方法的"身体"

java 复制代码
T max = x; // 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
    max = y; //y 更大
}
if ( z.compareTo( max ) > 0 ){
    max = z; // 现在 z 更大           
}
return max; // 返回最大对象

这段代码的逻辑非常清晰,就像我们现实生活中找最大值一样:

  1. T max = x; :先拿出第一个数 x,暂时把它当成"擂主"。
  2. if ( y.compareTo( max ) > 0 ) :让第二个数 y 上来打擂。y.compareTo(max) 的意思是"让 ymax 比较一下"。
    • 如果 ymax 大,compareTo 会返回一个正数(> 0)。
    • 如果 y 更大,就把 y 设为新的"擂主"(max = y;)。
  3. if ( z.compareTo( max ) > 0 ) :让第三个数 z 上来打擂,和当前的"擂主" max 比较。如果 z 更大,它就成为新擂主。
  4. return max; :打擂结束,返回最后的"擂主",也就是三个数中的最大值。
    关键点 :正因为我们在方法签名里限制了 T 必须有 compareTo 方法,所以在这里我们才能放心大胆地调用 y.compareTo(max)z.compareTo(max)

第三部分:main 方法里的"魔法"

现在我们来看 main 方法是怎么调用这个"超级方法"的。

调用 1:比较整数
java 复制代码
System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) );
  1. 当编译器看到 maximum(3, 4, 5) 时,它发现 3, 4, 5 都是 Integer 类型。
  2. 于是,它就把泛型 T 自动推断Integer
  3. 它检查 Integer 是否满足 extends Comparable<Integer> 的要求?满足!
  4. 于是,方法就变成了 Integer maximum(Integer x, Integer y, Integer z),然后执行找最大值的逻辑,最后返回一个 Integer
  5. %d 正好可以打印 Integer,完美!
调用 2:比较小数
java 复制代码
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
  1. 编译器看到 maximum(6.6, 8.8, 7.7),推断出 TDouble 类型。
  2. 检查 Double 是否满足 extends Comparable<Double>?满足!
  3. 方法变成了 Double maximum(Double x, Double y, Double z),执行后返回 Double
  4. %.1f 打印 Double,完美!
调用 3:比较字符串
java 复制代码
System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear", "apple", "orange", maximum( "pear", "apple", "orange" ) );
  1. 编译器看到 maximum("pear", "apple", "orange"),推断出 TString 类型。
  2. 检查 String 是否满足 extends Comparable<String>?满足!
  3. 方法变成了 String maximum(String x, String y, String z),执行后返回 String
  4. %s 打印 String,完美!

总结

这个程序的核心思想就是**"代码复用""类型安全"**。

  • 没有泛型 :你需要写三个不同的方法 maximum(int, int, int), maximum(double, double, double), maximum(String, String, String)。代码重复,很麻烦。
  • 有了泛型 :你只需要写一个 maximum 方法,它像一个万能工具,可以处理所有"可比较"的类型。同时,因为 <T extends Comparable<T>> 的限制,它还很安全,不会让你拿不能比较的东西来比较,从而在编译阶段就避免了错误。
    希望这个从里到外的详细解释能让你彻底看懂这段代码!如果还有不清楚的地方,随时可以再问。

以上内容由AI生成,仅供参考和借鉴

相关推荐
广药门徒4 小时前
Linux(含嵌入式设备如泰山派)VNC 完整配置指南:含开机自启动(适配 Ubuntu/Debian 系)
开发语言·php
简色4 小时前
题库批量(文件)导入的全链路优化实践
java·数据库·mysql·mybatis·java-rabbitmq
不做无法实现的梦~4 小时前
jetson刷系统之后没有浏览器--解决办法
开发语言·javascript·ecmascript
程序员飞哥4 小时前
如何设计多级缓存架构并解决一致性问题?
java·后端·面试
一只小松许️4 小时前
深入理解:Rust 的内存模型
java·开发语言·rust
前端小马5 小时前
前后端Long类型ID精度丢失问题
java·前端·javascript·后端
Lisonseekpan5 小时前
Java Caffeine 高性能缓存库详解与使用案例
java·后端·spring·缓存
eqwaak05 小时前
数据预处理与可视化流水线:Pandas Profiling + Altair 实战指南
开发语言·python·信息可视化·数据挖掘·数据分析·pandas
SXJR6 小时前
Spring前置准备(七)——DefaultListableBeanFactory
java·spring boot·后端·spring·源码·spring源码·java开发