本文介紹了工廠方法如何返回接口和抽象類的實例?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
ExecutorService和Service是接口,因此只有抽象方法,這意味著它們的方法沒有實現。那么,我們如何在接口類型的引用上調用future.get()
、es.submit()
和es.shutdown()
方法呢?例如,為什么我們可以做以下事情?
Future f = ...
f.get();
這里有一個更具體的例子:
import java.util.concurrent.*;
class Factorial implements Callable<Long> {
long n;
public Factorial(long n) {
this.n = n;
}
public Long call() throws Exception {
if (n <= 0) {
throw new Exception("for finding factorial, N should be > 0");
}
long fact = 1;
for(long longVal = 1; longVal <= n; longVal++) {
fact *= longVal;
}
return fact;
}
}
class CallableTest {
public static void main(String []args) throws Exception {
long N = 20;
Callable<Long> task = new Factorial(N);
ExecutorService es = Executors.newSingleThreadExecutor();
Future<Long> future = es.submit(task);
System.out.printf("factorial of %d is %d", N, future.get());
es.shutdown();
}
}
推薦答案
這個問題投了一些反對票,因為從某種意義上說,它是一種基本的問題,但我認為它實際上是一種有趣的問題。畢竟,像您的示例中的Executors
這樣的工廠類可以指定它返回Executor
s。但是,正如您所指出的,這只是一個接口,如果您要能夠調用這些方法,您實際上需要一個實現Executor
的東西的實例。為什么工廠不必告訴我們退貨的實際類型?
如果您以前沒有見過這一點,可能不清楚您是如何做到這一點的。需要記住的重要一點是,如果您有一個實現接口的類,則聲明為返回接口類型的方法也可以返回該類的實例。也就是說,您可以:
interface Foo { /* ... */ }
class Bar implements Foo { /* ... */ }
class Factory {
Foo makeFoo() {
return new Bar( /*... */ );
}
}
makeFoo
被聲明為返回Foo
,但Foo
是一個接口;您不能實際擁有它的實例。您只能擁有實現Foo
的類的實例。Bar
實現了Foo
,所以您可以返回Bar
的實例。
之所以可以這樣做,是因為當調用對象上的方法時,該方法的實現可以在我們引用的實際對象中找到。查找方法的方式實際上有點復雜。不過,從概念上講,您可能會這樣想:如果您告訴我您是Foo
,那么我可以要求您運行Foo
中聲明的任何方法,但您將決定為該方法做什么。我只能使用您的Foo
類型來確定我可以要求您執行哪些方法。這一點非常重要,這也是為什么我們可以重寫子類中的方法。這些被稱為virtual methods。這很重要的原因之一是,它使我們能夠使用接口,在這些接口中,我們可以透露有關實現的最少量信息(我們可以選擇說”我實現了Foo
,但這就是我告訴您的關于我自己的所有內容),但仍然遵守合同(即,我被保證實際實現Foo
中聲明的所有方法)。
下面的示例更深入一些,并且捕獲了您在Executors
中看到的更多工廠模式。
代碼
public class InterfacesExample {
/**
* An interface with one method.
*/
interface Frobber {
/**
* Frob the object.
* @param object the object
*/
void frob( Object object );
}
/**
* A factory class with one method for creating printing frobber.
*/
public static class Frobbers {
/**
* Returns a Frobber whose {@link Frobber#frob(Object)} method
* prints its argument
* @return a printing Frobber
*/
public static Frobber newPrintingFrobber() {
// This returns an instance of an anonymous class
// that implements the Frobber interface. It has
// to provide an implementation of frob(Object),
// though.
return new Frobber() {
@Override
public void frob( final Object object ) {
System.out.println( "Frobbing "+object+"..." );
}
};
}
/**
* Returns a Frobber whose {@link Frobber#frob(Object)} method
* prints the prefix and its argument
* @param prefix an object
* @return a prefixing printing Frobber
*/
public static Frobber newPrefixingPrintingFrobber( final Object prefix ) {
return new PrefixingPrintingFrobber( prefix );
}
/**
* A private, but not anonymous class. Instances shouldn't be
* made with its constructor, but rather through the factory
* method {@link Frobbers#newPrefixingPrintingFrobber(Object)}.
*/
private static class PrefixingPrintingFrobber implements Frobber {
final Object prefix;
public PrefixingPrintingFrobber( Object prefix ) {
this.prefix = prefix;
}
@Override
public void frob( final Object object ) {
System.out.println( "Frobbing "+prefix+":"+object+"..." );
}
}
}
/**
* Create some frobbers with the factory and test them out.
*/
public static void main( final String[] args ) {
final Frobber f1 = Frobbers.newPrintingFrobber();
f1.frob( 42 );
final Frobber f2 = Frobbers.newPrefixingPrintingFrobber( "boing" );
f2.frob( 36 );
}
}
輸出
Frobbing 42...
Frobbing boing:36...
這篇關于工廠方法如何返回接口和抽象類的實例?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,