[英]Make Java consider the most specific type when choosing method among overloaded methods
我想基於對象的類型執行幾個操作,而不使用instanceof
。 起初我正在考慮基於類型重載方法(如下所示),並認為Java可能會適當地選擇方法(基於最具體的對象類)。
import java.util.ArrayList;
import java.util.List;
public class TestA {
public static void main(String[] args)
{
List<Object> list = new ArrayList();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Object());
TestA tester = new TestA();
for(Object o: list)
{
tester.print(o);
}
}
private void print(A o)
{
System.out.println("A");
}
private void print(B o)
{
System.out.println("B");
}
private void print(C o)
{
System.out.println("C");
}
private void print(Object o)
{
System.out.println("Object");
}
}
class A {
}
class B extends A {
}
class C {
}
輸出是:
Object
Object
Object
Object
然而,我所追求的輸出是:
A
B
C
Object
instanceof
的幫助下看到這些功能的替代方案 visitor.accept(this)
在class A
導致函數visitor.accept(A o)
被調用。 instanceof
因為我讀過它是不好的做法; 在這種情況下,它仍然是不好的做法? 我的答案是讓A,B和C類實現一個通用接口。
然后他們每個人都可以擁有自己的特定接口。
這樣,您可以為所有對象調用相同的方法 (從而避免重載方法),並且還可以根據對象的類型(即實例化它的類) 確保自定義功能 。
這個答案認為修改給定的類及其關系不是一種選擇。
有沒有辦法讓Java根據參數對象的最具體類型選擇方法?
Java編譯器不能為你強制轉換,因為這可能不是你想要的(在你的情況下,這是你想要的,但也許其他人不想要這種行為,他們將無法解決它們)。 由於您將Object
引用傳遞給print()
,編譯器將調用print(Object)
。
如果沒有,我可以在沒有instanceof的幫助下看到這些功能的替代方案
您可以將Object
的類型包裝在包裝類中,例如:
public class ObjectWrapper {
private final Object object;
private final int type;
}
這樣,您可以安全地轉換為Object
的類型,而無需使用instanceof
。 雖然這個恕我直言比簡單地使用instanceof
更復雜,實際上它只創建自己的instanceof
...
我老實說反對instanceof因為我讀過它是不好的做法; 在這種情況下,它仍然是不好的做法?
在編程中, 沒有什么是不好的做法 。 一切都取決於具體情況。 在這種情況下,我認為您可以使用instanceof
並進行不安全的轉換,因為設計需要這樣做。 無論如何,如果instanceof
運算符存在於該語言中,那是因為它被使用了。 如果instanceof
總是一個不好的做法,它就不會作為語言的一部分存在。 看到這個和這個 。
我實際上是試圖模擬訪問者模式,但看起來,訪問者模式工作的原因是因為雙重調度,這使得參數在函數調用期間被“接受”的類型正確,特別是visitor.accept(this)在類A中導致函數visitor.accept(A o)被調用。
使用訪客模式檢查我的第二個鏈接是否有缺點。
方法重載是一個編譯時多態,在你的for
循環中,你已經將o
聲明為Object
,因此總是會調用print(Object o)。
解決方案:使用動態多態性:
class A{
void print(){
System.out.println('in A');
}
}
class B{
void print(){
System.out.println('in B');
}
}
和for循環
for(Object o: list){
o.print();
}
考慮訪客設計模式http://en.wikipedia.org/wiki/Visitor_pattern 。 雖然它需要更改A,B,C,否則沒有其他辦法。
我會在這里使用instanceof
。 它簡單明了。
這並不像沒有使用instanceof
的硬規則 。 沒有硬規則:)很多使用instanceof
可能是一個跡象,你可以改變一些東西,讓編譯器為你做更多的工作。 這是否真的值得做,需要逐個查看。 在你的情況下,你提到你無法改變有問題的類,所以它甚至不是一個選項。
package com.ank.says;
import java.util.ArrayList;
import java.util.List;
class Base{
public void print(){
System.out.println("Base");
}
}
class A extends Base{
@Override
public void print() {
System.out.println("A");
}
}
class B extends Base{
@Override
public void print(){
System.out.println("B");
}
}
class C extends Base{
@Override
public void print(){
System.out.println("C");
}
}
public class TestPlayGround {
public static void main(String[] args) throws ParseException {
List<Base> list = new ArrayList<Base>();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Base());
TestPlayGround tester = new TestPlayGround();
for(Base o: list)
{
o.print();
}
}
}
輸出: - ABC Base
在沒有使用instanceof的情況下突然出現的是:
碼:
public interface YourInterface {
public void doStuff();
}
public class A implements YourInterface {
@Override
public doStuff() {
System.out.print("A");
}
}
public class B implements YourInterface {
@Override
public doStuff() {
System.out.print("A");
}
}
List<YourInterface> list = new ArrayList<YourInterface>();
list.add(new A());
list.add(new B());
for(YourInterface e: list)
{
e.doStuff();
}
碼:
public enum YourEnum {
TYPE1 {
@Override
public void doStuff() {
System.out.print("Type 1");
},
TYPE2 {
@Override
public void doStuff() {
System.out.print("Type 2");
};
public abstract void doStuff();
}
List<YourEnum> list = new ArrayList<YourEnum>();
list.add(YourEnum.TYPE1);
list.add(YourEnum.TYPE2);
for(YourEnum e: list)
{
e.doStuff();
}
看完上面的答案
我可以建議的一個解決方案是使用o.getClass
和continue來檢查對象類型
然而,發布了許多更好的解決方 我完全同意@krisna kishor shetty說的話
從我的觀點來看,這不是使用instanceof的問題。 問題是如何最大限度地減少這種情況所帶來的影響。 所以我會推薦實例適配器,以防有多個操作需要處理。 這樣你至少可以避免在整個系統中傳播這種復雜性:
public abstract class Adapter {
public abstract void print();
public static Adapter wrap(Object o) {
if (o instanceof A) {
return new AAdapter();
}
if (o instanceof B) {
return new BAdapter();
}
return new ObjectAdapter():
}
public class AAdapter {
public void print() {
System.out.printLn("A");
}
}
然后循環:
for (Object o: things) {
Adapter.wrap(o).print();
}
當然,我們的Adapter將引用包裝對象,如方法名稱所示。 這樣,您就可以獲得接近直接修改這些類的編碼模型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.