簡體   English   中英

有沒有辦法在Java中傳遞方法引用?

[英]Is there a way to pass a method reference in Java?

首先,盡管它們具有相同的標題,但這不是該問題的重復。 這個問題指的是與C函數本質上相同的傳遞方法:它們不必屬於特定的對象。 在這種情況下,您可以傳遞RunnableCallable對象。

相反,我在問以下問題:是否可以將引用傳遞給類中的特定方法,並讓該方法調用特定對象?

舉例來說,我在Swing中查看FlowLayout的代碼,並注意到preferredLayoutSizeminimumLayoutSize實現完全相同,只是一行不同:

public Dimension preferredLayoutSize(Container target) {
  synchronized (target.getTreeLock()) {
    Dimension dim = new Dimension(0, 0);
    int nmembers = target.getComponentCount();
    boolean firstVisibleComponent = true;
    boolean useBaseline = getAlignOnBaseline();
    int maxAscent = 0;
    int maxDescent = 0;

    for (int i = 0 ; i < nmembers ; i++) {
        Component m = target.getComponent(i);
        if (m.isVisible()) {
            Dimension d = m.getPreferredSize();
            dim.height = Math.max(dim.height, d.height);
            if (firstVisibleComponent) {
                firstVisibleComponent = false;
            } else {
                dim.width += hgap;
            }
            dim.width += d.width;
            if (useBaseline) {
                int baseline = m.getBaseline(d.width, d.height);
                if (baseline >= 0) {
                    maxAscent = Math.max(maxAscent, baseline);
                    maxDescent = Math.max(maxDescent, d.height - baseline);
                }
            }
        }
    }
    if (useBaseline) {
        dim.height = Math.max(maxAscent + maxDescent, dim.height);
    }
    Insets insets = target.getInsets();
    dim.width += insets.left + insets.right + hgap*2;
    dim.height += insets.top + insets.bottom + vgap*2;
    return dim;
  }
}

public Dimension minimumLayoutSize(Container target) {
  synchronized (target.getTreeLock()) {
    boolean useBaseline = getAlignOnBaseline();
    Dimension dim = new Dimension(0, 0);
    int nmembers = target.getComponentCount();
    int maxAscent = 0;
    int maxDescent = 0;
    boolean firstVisibleComponent = true;

    for (int i = 0 ; i < nmembers ; i++) {
        Component m = target.getComponent(i);
        if (m.visible) {
            Dimension d = m.getMinimumSize();
            dim.height = Math.max(dim.height, d.height);
            if (firstVisibleComponent) {
                firstVisibleComponent = false;
            } else {
                dim.width += hgap;
            }
            dim.width += d.width;
            if (useBaseline) {
                int baseline = m.getBaseline(d.width, d.height);
                if (baseline >= 0) {
                    maxAscent = Math.max(maxAscent, baseline);
                    maxDescent = Math.max(maxDescent,
                                          dim.height - baseline);
                }
            }
        }
    }

    if (useBaseline) {
        dim.height = Math.max(maxAscent + maxDescent, dim.height);
    }

    Insets insets = target.getInsets();
    dim.width += insets.left + insets.right + hgap*2;
    dim.height += insets.top + insets.bottom + vgap*2;
    return dim;
  }
}

preferredLayoutSize方法調用mpreferredLayoutSize方法(第i個組件),而minimumLayoutSize調用mminimumLayoutSize方法。 據我所知,這兩種方法在其他方面是相同的。

正如任何程序員都會告訴您的那樣,代碼重復是一件壞事。 但是,在這種情況下,如何消除重復的代碼並不明顯。 顯然,應該有一個私有方法,其中包含兩個公共方法都調用的代碼,並傳遞對Component類的preferredLayoutSizeminimumLayoutSize方法的引用。 在CI中,可以使用函數指針來做到這一點,因此在Java中應該有某種方式可以做到這一點。 傳遞RunnableCallable幾乎可行,但都不返回值。 編輯:這是錯誤的。 Callable 的重寫方法確實返回一個值,並且對其作用的對象可以作為參數傳遞。

現在,我已經輸入了所有內容,我想到了一個解決方案:您可以使用名為Dimension layoutSize(Component comp)的方法編寫一個interface ,並編寫兩個實現,其中一個返回comp.preferredLayoutSize() ,而另一個返回comp.minimumLayoutSize() 然后,您可以編寫一個私有方法,將該接口的實例作為參數,然后使用該私有方法在代碼的正確位置運行單獨的方法。 您甚至可以使用匿名內部類,因此不必為每種類型的布局大小編寫新的類。 但是,對於一個相當簡單的問題,似乎仍然有很多麻煩。 有更容易的方法嗎?

您可以將一個方法包裝在LayoutSizing類(可能是一個本地類)中,並使用一個抽象方法在m上進行計算(以m為參數),然后在這兩個方法中使用以下方法實例化new LayoutSizing() { @Override ... }實現的方法。

希望在Java 8中看起來會更好。

您可以使用一個接口:

interface DimensionReturningThingy {
    public Dimension getDim (Component c);
}

public Dimension preferredLayoutSize(Container target) {
    commonCode (target, new DimensionReturningThingy () {
        public Dimension getDim (Component m) {
            return m.getPreferredSize ();
        });
}

// and similarly for minimumLayoutSize

public Dimension commonCode (Container target, DimensionReturningThingy drt) {

// now repeat code above, except that replace

        Dimension d = m.getPreferredSize();

// with

        Dimension d = drt.getDim (m);

我不太擅長命名,所以我敢肯定您可以為其中的一些名字起更好的名字。

編輯:在您編輯原始文章以提及界面解決方案之前,我想我正在回答這個問題。

對於這種特殊情況,最簡單的解決方案是將這兩種方法重構為三種:

private Dimension layoutSize(Container target, boolean prederred) {
    ...
    Dimension d = prederred?m.getPreferredSize():m.minimumLayoutSize();
    ...
}

public Dimension preferredLayoutSize(Container target) {
    return layoutSize(target, true);
}

public Dimension minimumLayoutSize(Container target) {
    return layoutSize(target, false);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM