Javaで、2つの異なる可変引数を期待するメソッドを作成する方法はありますか?同じ種類のオブジェクトでは、コンパイラーが開始または終了する場所を知らないため、それは不可能です。しかし、なぜ異なるオブジェクトタイプに対してもそれができないのですか?
例えば:
public void doSomething(String... s, int... i){
//...
//...
}
このようなメソッドを作成する方法はありますか?ありがとうございました!
Varargは1つだけです。申し訳ありません。しかし、asList()を使用すると、ほぼ同じくらい便利になります。
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static Java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
Javaでは、1つのvarargs
引数のみが許可され、それは署名の最後のパラメーターでなければなりません。
しかし、とにかくそれを配列に変換するので、2つのパラメーターを明示的な配列にするだけです。
public void doSomething(String[] s, int[] i){
呼び出しコードが次のようになる可能性のあるAPI設計
_ doSomething("a", "b").with(1,2);
_
「流れるような」API
_public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
_
プログラマがwith(...)
を呼び出すのを忘れた場合、危険です
_ doSomething("a", "b"); // nothing is done
_
多分これは少し良いです
_ with("a", "b").and(1, 2).doSomething();
_
このようなことは時々役立ちますが、通常Javaで制限に達していることがわかった場合、おそらく何かを再設計してはるかに優れたものにすることができます。他に考えられるいくつかの方法があります。それ...
2つのリストがまったく関連している場合は、おそらく2つの異なるリストのラッパークラスを作成し、ラッパーを渡します。コレクションの周りのラッパーは、ほとんどの場合良いアイデアです。それらは、コレクションに関連するコードを追加する場所を提供します。
これがデータを初期化する方法である場合は、文字列から解析します。たとえば、「abc、123:def、456:jhi、789」は、2つの分割ステートメントとループ(2〜3行のコード)を使用して分割するのが非常に簡単です。メソッドにフィードする構造にそのような文字列を解析する小さなカスタムパーサークラスを作成することもできます。
うーん-正直なところ、データを初期化することの他に、なぜこれをしたいのかわからないこともあります。他のケースもあり、2つのコレクションを渡して、varagsにはまったく興味がないと思います。
許可されるvararg
は1つだけです。これは、複数のvararg
引数があいまいなためです。たとえば、同じクラスの2つの可変引数を渡した場合はどうなるでしょうか。
public void doSomething(String...args1, String...args2);
Args1はどこで終わり、args2はどこから始まるのですか?または、ここでさらに混乱するものについてはどうですか。
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClassはSuperClassを拡張するため、args1またはargs2に合法的に存在できます。この混乱により、varargs
が1つだけ許可されます。
varargs
は、メソッド宣言の最後にも指定する必要があります。
代わりに、特定の型を2つの配列として宣言してください。
あなたはこのようなことをすることができ、それからそのメソッドの中に追加のロジックをキャストして追加することができます。
public void doSomething(Object... stringOrIntValues) {
...
...
}
そして、このようにこのメソッドを使用します:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
これは古いスレッドですが、関係なく役立つと思いました。
私が見つけた解決策はあまりきれいではありませんが、うまくいきます。重い作業を処理するために別のクラスを作成しました。必要な2つの変数とそのゲッターのみが含まれています。コンストラクターは独自にsetメソッドを処理します。
方向オブジェクトとそれぞれのデータオブジェクトを渡す必要がありました。これにより、不均一なデータペアの起こり得る問題も解決されますが、それはおそらく私の使用法のニーズにのみ当てはまります。
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* @return the node
*/
public Node getNode() {
return node;
}
/**
* @return the direction
*/
public Directions getDir() {
return dir;
}
}
次に、このクラスをメソッドの可変引数として渡します
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
Java言語仕様にそのように記載されているため、これは不可能です( 8.4.1。仮パラメーター を参照):
メソッドまたはコンストラクターの最後の仮パラメーターは特別です。タイプに続く省略記号で示される変数アリティパラメーターの場合があります。
省略記号(...)はそれ自体に対するトークンであることに注意してください(§3.11)。それとタイプの間に空白を入れることは可能ですが、これはスタイルの問題としてお勧めできません。
最後の仮パラメータが可変アリティパラメータの場合、メソッドは可変アリティメソッドです。それ以外の場合は、固定アリティメソッドです。
なぜ最後のパラメータが1つだけであるかは推測ですが、おそらくそれを許可すると、決定不能またはあいまいな問題が発生する可能性があるため(たとえば、method(String... strings, Object... objects)
で何が発生するかを検討し)、交差しないもののみを許可する型は複雑化(たとえば、以前は交差しなかった型が突然存在するリファクタリングを検討する場合)、機能する場合と機能しない場合の明確さの欠如、およびコンパイラーが適用可能かそうでないかをコンパイラが判断する複雑さをもたらします。
ほとんどの場合、最初の引数に多数の文字列を渡す予定がない場合は、さまざまな数の文字列を取得する一連のオーバーロードを提供し、それらを配列としてラップしてから、配列を最初の引数。
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}
可変引数を配列に変換できます
public void doSomething(String[] s, int[] i) {
...
}
次に、次のように変数引数を配列に変換するいくつかのヘルパーメソッドを使用します。
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
次に、これらのヘルパーメソッドを使用して、可変引数パラメーターを変換できます。
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));
この「パターン」に関する別の質問を読んだだけですが、すでに削除されているため、この解決策が見つからなかったため、この問題に対する別のアプローチを提案したいと思います。
代わりに、開発者にListまたはArrayの入力パラメーターのラップを強制する代わりに、「カレー」アプローチまたはより優れたビルダーパターンを使用すると便利です。
次のコードを検討してください。
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
この方法で確認できるように、必要なときに必要なタイプの新しい要素を追加できます。
すべての実装はラップされています。
lemuel Adaneをフォローしています(担当者がいないため、投稿にコメントできません:))
あなたが使うなら
public void f(Object... args){}
次に、ループを使用して オブジェクトのクラスを判別する方法(Javaの場合)?
たとえばのように
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
またはあなたがするつもりなら何でも。