【问题标题】:Exact need of Method Overloading in Java [duplicate]Java中方法重载的确切需要[重复]
【发布时间】:2016-12-22 09:24:08
【问题描述】:

因为我发现了很多关于方法重载的例子和结论,但我仍然对我们如何使用它感到困惑。

首先,方法重载是类级别的活动,这意味着在该类中,我们正在重载具有相同名称但参数不同的方法,例如

void sum(int a,int b){System.out.println(a+b);}  
void sum(double a,double b){System.out.println(a+b);} 

在我们像

这样调用这个方法之后
public static void main(String args[]){  
ClassName obj=new ClassName ();  
obj.sum(10.5,10.5);  
obj.sum(20,20);  
}  

假设我将采用两个单独的方法来代替这个,例如

void method1(int a,int b){System.out.println(a+b);}  
void method2(double a,double b){System.out.println(a+b);} 

我将这两种方法称为与上面相同的方法

public static void main(String args[]){  
ClassName obj=new ClassName (); 
obj.method1(20,20);   
obj.method2(10.5,10.5);  
} 

在这两种方法的情况下,活动都是相同的,那么在这种情况下重载/多态的确切需求是什么。

在某处我发现方法重载增加了程序的可读性任何人都可以指定仅因为这一行我们正在使用方法重载。

谢谢。

【问题讨论】:

  • 必须添加这样的数字后缀会破坏抽象。您希望方法名称描述该方法的作用,而不是由于技术限制而命名。

标签: java overloading


【解决方案1】:

假设我们在 Java 中没有方法重载。

而不是:

System.out.println("String");
System.out.println(5);
System.out.println('c');
...

我们会:

System.out.printlnString("String");
System.out.printlnInt(5);
System.out.printlnChar('c');
...

甚至更糟:

System.out.println1("String");
System.out.println2(5);
System.out.println3('c');
...

这两种选择都会降低代码的可读性。

【讨论】:

  • 更不用说制作伪“可选”参数之类的东西了,例如foo(Bar) 和 foo(Bar, Baz)
  • 好的,但是它是一个 API 级别的设计,但是就像在我们使用方法重载的 web 应用程序中一样实时。
  • @ranjan 当您声明自己的方法时,同样的参数也适用。如果您的方法执行类似的操作但采用不同的参数(不同类型的参数或不同数量的参数),有时给它们起相同的名称是有意义的。
【解决方案2】:

您可以查看现有的 Java API,例如 Math、Arrays,以了解 Overload 的威力。

您想记住每个方法名称取决于您的数据类型还是只使用 Arrays.sort() 并让语言本身根据参数决定应该使用哪个实现?

Arrays.sortByte(byte[] abyte)

Arrays.sortChar(char[] ac)

Arrays.sortFloat(float[] af)

Arrays.sortDouble(double[] ad)

Arrays.sortShort(short[] as)

Arrays.sortInt(int[] ai)

Arrays.sortLong(long[] al)

对于其他一些场景,你可能有几十个方法具有相同的功能,但根据几十个参数的组合,实现只是略有不同,如果不使用 Overload,情况会变得更糟。

这个话题中已经讨论过同样的讨论。

Why should I ever overload methods?

【讨论】:

    【解决方案3】:

    方法重载还可以帮助 API 设计人员提供不同级别的抽象。

    例如,她可以选择提供初学者版本,其中大多数参数被赋予在大多数情况下运行良好的默认值,同时提供专家版本,用户可以微调参数以满足他们的特定需求:

    /*
     * A beginner version that just works.
     */
    public void foo() {
        foo(1, 2);
    }
    
    /*
     * An expert version where the user has more control over the
     * parameters, requiring more knowledge about the API.
     */
    public void foo(int a, int b) {
    }
    

    来自HashMap.java的真实示例:

    /**
     * Constructs an empty <tt>HashMap</tt> with the specified initial
     * capacity and load factor.
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
    
    /**
     * Constructs an empty <tt>HashMap</tt> with the specified initial
     * capacity and the default load factor (0.75).
     *
     * @param  initialCapacity the initial capacity.
     * @throws IllegalArgumentException if the initial capacity is negative.
     */
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    
    /**
     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
     * (16) and the default load factor (0.75).
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
    

    通常用户不需要使用initialCapacity 和loadFactor 参数,但如果需要,它们可以。

    【讨论】:

      【解决方案4】:

      下面是一个示例,说明为什么需要方法重载才能让像我们这样的开发人员能够有效地使用它们:

      在 java 的 Graphics2D 类中有一个叫做 drawImage 的方法,虽然它有一个重载,如下所示: 抽象无效drawImage(BufferedImage img,BufferedImageOp op,int x,int y) abstract void drawImage(Image img, AffineTransform xform, ImageObserver obs)

      假设它们不是按如下所示进行组织,而是标记为 drawImage1 和 drawImage2,这将使任何版本的 drawImage 都有一个完全不同的名称供您记住,这意味着您可能最终不得不记住许多每个 drawImage 方法的名称,而不是简单地知道哪些参数是可接受的。 因此,方法重载为开发人员提供了具有不同功能但名称相同的不同方法,因为它们本质上做同样的事情,但需要不同的参数来完成,就像 drawImage 重载一样。

      【讨论】:

        【解决方案5】:

        您可以在 oracle 文档页面中找到有关 overloading 方法的更多详细信息。

        假设您有一个类可以使用书法来绘制各种类型的数据(字符串、整数等),并且包含用于绘制每种数据类型的方法。

        为每个方法使用新名称很麻烦,例如 drawString、drawInteger、drawFloat 等。

        在 Java 编程语言中,您可以对所有绘图方法使用相同的名称,但将不同的参数列表传递给每个方法。 Thus, the data drawing class might declare four methods named draw, each of which has a different parameter list.

        文档页面中提供的说明与您的声明完全相反(重载增加了代码可读性)

        注意:应谨慎使用重载方法,因为它们会使代码的可读性大大降低。

        看一个例子。

        Assume that you have to shift a Shape by its parameters : length, width and height.
        

        Square 将其长度作为参数传递。

        Rectangle 将它的长度和宽度作为参数传递。

        One more 3D shape 传递它的长度、宽度和高度。

            public void shiftPosition(int length){
                shiftPosition(length,0,0);
            }
            public void shiftPosition(int length,int width){
                shiftPosition(length,width,0);
            }
            public void shiftPosition(int length, int width, int height){
                System.out.println("Shfit Position by length:width:height:"+
                length+":"+width+":"+height);
            }
        

        sifhtPosition 是具有三个不同签名的重载方法。

        假设一个场景,你有 8 个不同版本的相同方法。 如果您尝试跨项目类查找每个单独方法的引用以进行代码重构,您会发现这是一团糟。

        这篇javaworld 文章解释了方法重载的成本和缺点。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-25
          • 1970-01-01
          • 2015-12-01
          • 1970-01-01
          相关资源
          最近更新 更多