Java'da C # 'ın ref ve out anahtar sözcükleri gibi bir şey var mı?


113

Aşağıdakine benzer bir şey:

ref örneği:

void changeString(ref String str) {
    str = "def";
}

void main() {
    String abc = "abc";
    changeString(ref abc);
    System.out.println(abc); //prints "def"
}

dışarı örnek:

void changeString(out String str) {
    str = "def";
}

void main() {
    String abc;
    changeString(out abc);
    System.out.println(abc); //prints "def"
}


5
IMO çok şey kaçırmıyorsun. Şimdiye kadar kullanmak sadece zaman refya outben gibi bir desen kullanıyorum zaman C # olan TryParse()yöntem bir boolean sonuç döndürür, ve bunun dışında bir çözümlü değerini almak için tek yol kullanmaktır refya out.
Robert Harvey

3
Bil bakalım ne oldu, kullanmam gereken şey bu! ;)
yiyip

Bunu yapmanın diğer yolu, içinde hem durum hem de boş değer atanabilir değer içeren bir bileşik nesne döndürmektir. Ama bunun biraz Rube Goldberg-ish olduğunu kabul ediyorum.
Robert Harvey

1
Önceden tanımlanmış kullanılabilir bir tane (örn. Tuple) olsaydı, bir bileşik nesneyi döndürmede yanlış bir şey yoktur. Ama bekleyin, bunun verimli olması için ilkel türlerle çalışan silinmemiş jeneriklere ihtiyacı var :)
Pavel Minaev

Yanıtlar:


102

Hayır, Java'da C # gibi bir şey refve outreferansla geçiş için anahtar sözcükler yoktur.

Java'da yalnızca değere göre geçiş yapabilirsiniz. Referanslar bile değere göre aktarılır. Daha fazla ayrıntı için Jon Skeet'in Java'da parametre geçişiyle ilgili sayfasına bakın.

Benzer bir şey yapmak için refveya outbaşka bir nesnenin içine Parametrelerinizi sarın ve bir parametre olarak bu nesne referansı geçmesi gerekecekti.


5
Bu, bazılarında genişletilmelidir. Değer olarak yalnızca ilkelleri (int, short, char, vb.) Geçirebilirsiniz. Ve hayır, çıkış yok.
Corey Sunwold

14
Bu% 100 doğru değil, Bir dizi veya bir sınıfa geçirirseniz, dizi veya nesneye referans değer tarafından iletilir, Diziye veya nesneye olan içselleri değiştirebilirsiniz ve çağırıcıya yansıtılır.
Romain Hippeau

12
@fearofawhackplanet: Um, kullanmadığınız sürece ref.
Robert Harvey

2
@fearofawhackplanet: Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. yoda.arachsys.com/csharp/parameters.html
Mark Byers

5
CLR açısından, yönetilen bir referansı ( T&) değere göre geçiriyorsunuz , evet. Ancak C # kendi terminolojisine sahiptir ve özellikle tür değerleri gibi şeyler içermez ref T- C # açısından, refkesinlikle bir parametre değiştiricidir ve ona göre "değere göre bir referansı iletmekten" bahsetmek mantıklı değildir .
Pavel Minaev

30

Doğrudan cevap: Hayır

Ancak , sarmalayıcılarla referansı simüle edebilirsiniz .

Ve aşağıdakileri yapın:

void changeString( _<String> str ) {
    str.s("def");
}

void testRef() {
     _<String> abc = new _<String>("abc");
     changeString( abc );
     out.println( abc ); // prints def
}

Dışarı

void setString( _<String> ref ) {
    str.s( "def" );
}
void testOut(){
    _<String> abc = _<String>();
    setString( abc );
    out.println(abc); // prints def
}

Ve temelde aşağıdakiler gibi diğer türler:

_<Integer> one = new <Integer>(1);
addOneTo( one );

out.println( one ); // May print 2

28
Ahh. Bu çirkin.
devoured elysium

46
Hiç söylemedim, Bu zarif yolla yapabilirsin : P
OscarRyz

öyleyse neden aşağıdakiler çalışmıyor: private static void ParseLine (String newline, String [] aWrapper, Integer [] bWrapper) {StringTokenizer st = new StringTokenizer (yeni satır); aWrapper [0] = st.nextToken (); bWrapper [0] = yeni Tamsayı (st.nextToken ()); } ParseLine (yeni satır, yeni Dize [] {a}, yeni Tamsayı [] {b});
Elad Benda

3
@ user311130 Kodunuzu okumak zor, ancak şöyle bir şey söyleyerek yeni bir soru oluşturabilirsiniz: "Bu yanıtı buldum <
cevabıma

Bu iğrenç, ama yine de bunu
beğeniyorum çünkü problemi

8

Aslında Java dilinde bildiğim kadarıyla ne ref ne de out anahtar sözcüğü eşdeğeri yok . Ancak ben sadece bir dönüştürülmüş ettik C # içine kodu Java kullandığı o dışarı parametresi ve ben sadece ne yaptık bildirecektir. Herhangi bir nesneyi bir sarmalayıcı sınıfına sarmalı ve sarmalayıcı nesne örneğine sarılmış değerleri aşağıdaki gibi iletmelisiniz;

Sarmalayıcıyı Kullanmak İçin Basit Bir Örnek

İşte Sarmalayıcı Sınıfı ;

public class Wrapper {
    public Object ref1; // use this as ref
    public Object ref2; // use this as out

    public Wrapper(Object ref1) {
        this.ref1 = ref1;
    }
}

Ve işte test kodu;

public class Test {

    public static void main(String[] args) {
        String abc = "abc";
        changeString(abc);
        System.out.println("Initial object: " + abc); //wont print "def"

        Wrapper w = new Wrapper(abc);
        changeStringWithWrapper(w);
        System.out.println("Updated object: " + w.ref1);
        System.out.println("Out     object: " + w.ref2);
    }

    // This won't work
    public static void changeString(String str) {
        str = "def";
    }

    // This will work
    public static void changeStringWithWrapper(Wrapper w) {
        w.ref1 = "def";
        w.ref2 = "And this should be used as out!";
    }

}

Gerçek Dünya Örneği

Out parametresini kullanan AC # .NET yöntemi

Burada out anahtar sözcüğünü kullanan bir C # .NET yöntemi vardır ;

public bool Contains(T value)
{
    BinaryTreeNode<T> parent;
    return FindWithParent(value, out parent) != null;
}

private BinaryTreeNode<T> FindWithParent(T value, out BinaryTreeNode<T> parent)
{
    BinaryTreeNode<T> current = _head;
    parent = null;

    while(current != null)
    {
        int result = current.CompareTo(value);

        if (result > 0)
        {
            parent = current;
            current = current.Left;
        }
        else if (result < 0)
        {
            parent = current;
            current = current.Right;
        }
        else
        {
            break;
        }
    }

    return current;
}

Out parametresini kullanan C # kodunun Java Eşdeğeri

Ve bu yöntemin wrapper sınıfı yardımıyla Java eşdeğeri aşağıdaki gibidir;

public boolean contains(T value) {
    BinaryTreeNodeGeneration<T> result = findWithParent(value);

    return (result != null);
}

private BinaryTreeNodeGeneration<T> findWithParent(T value) {
    BinaryTreeNode<T> current = head;
    BinaryTreeNode<T> parent = null;
    BinaryTreeNodeGeneration<T> resultGeneration = new BinaryTreeNodeGeneration<T>();
    resultGeneration.setParentNode(null);

    while(current != null) {
        int result = current.compareTo(value);

        if(result >0) {
            parent = current;
            current = current.left;
        } else if(result < 0) {
            parent = current;
            current = current.right;
        } else {
            break;
        }
    }

    resultGeneration.setChildNode(current);
    resultGeneration.setParentNode(parent);

    return resultGeneration;
}

Sarmalayıcı Sınıfı

Ve bu Java kodunda kullanılan sarmalayıcı sınıfı aşağıdaki gibidir;

public class BinaryTreeNodeGeneration<TNode extends Comparable<TNode>>  {

    private BinaryTreeNode<TNode>   parentNode;
    private BinaryTreeNode<TNode>   childNode;

    public BinaryTreeNodeGeneration() {
        this.parentNode = null;
        this.childNode = null;
    }

    public BinaryTreeNode<TNode> getParentNode() {
        return parentNode;
    }

    public void setParentNode(BinaryTreeNode<TNode> parentNode) {
        this.parentNode = parentNode;
    }

    public BinaryTreeNode<TNode> getChildNode() {
        return childNode;
    }

    public void setChildNode(BinaryTreeNode<TNode> childNode) {
        this.childNode = childNode;
    }

}

önceki cevapları görün.
17:11 pashute

Ayrıntılı bir cevap vermek, olumsuz bir oylama yapmak eğlenceli. SO'ya baktım ve demo koduyla iyi bir tam cevap bulamadım, bu yüzden hatırlayabildiğim kadarıyla bu cevabı yazdım. Tek bir cevabı beklerseniz ve diğer her cevaba olumsuz oy verirseniz, SO soru sahibinden onay alan dışındaki tüm cevabı yasaklamalıdır.
Levent Divilioğlu

Tamam, olumsuz oyu ancak yanıtı düzenlerseniz kaldırabilirim. Öyleyse diğer cevapları okuyun ve bu çözümleri neden kullanmak istemediğinizi açıklayın. Bir sarmalayıcı (ve özellikle eğlence için bir REF ve OUT sarmalayıcı). 5 kişi örneklerle kısa ve tam cevaplar verdi ve sadece Eyal temelde "Hayır yapamazsın" yazdı.
pashute

1
Bu cevap iyi görünüyor. En üstteki cevaba benzer, ancak Java'da bir sarmalayıcı sınıfının nasıl kullanılacağına dair tam detaylı örnekler verir.
hubatish

8

Java, parametreleri değere göre geçirir ve referansla geçişe izin verecek herhangi bir mekanizmaya sahip değildir. Bu, bir parametre her iletildiğinde, değerinin çağrıyı işleyen yığın çerçevesine kopyalandığı anlamına gelir .

Burada kullandığım şekliyle değer terimi biraz açıklamaya ihtiyaç duyar. Java'da iki tür değişkenimiz vardır - ilkeller ve nesneler. Bir ilkelin değeri ilkelin kendisidir ve bir nesnenin değeri referansıdır (başvurulan nesnenin durumu değildir). Bu nedenle, yöntem içindeki değerde yapılacak herhangi bir değişiklik yalnızca yığındaki değerin kopyasını değiştirecek ve arayan tarafından görülmeyecektir. Örneğin, iki referans alan ve onları değiştiren (içeriğini değil!) Gerçek bir takas yöntemi uygulamanın herhangi bir yolu yoktur.


6

Diğerleri gibi, bir C # projesini Java'ya dönüştürmem gerekiyordu. Out ve ref değiştiricilerle ilgili web'de tam bir çözüm bulamadım . Ancak, bulduğum bilgileri alıp, gereksinimleri karşılamak için kendi sınıflarımı oluşturmak üzere genişletebildim. Kod netliği için ref ve out parametreleri arasında bir ayrım yapmak istedim . Aşağıdaki sınıflar ile mümkündür. Bu bilgiler başkalarına zaman ve emekten tasarruf etsin.

Aşağıdaki koda bir örnek verilmiştir.

//*******************************************************************************************
//XOUT CLASS
//*******************************************************************************************
public class XOUT<T>
{
    public XOBJ<T> Obj = null;

    public XOUT(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XOUT()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(this);
    }

    public XREF<T> Ref()
    {
        return(Obj.Ref());
    }
};

//*******************************************************************************************
//XREF CLASS
//*******************************************************************************************

public class XREF<T>
{
    public XOBJ<T> Obj = null;

    public XREF(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XREF()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(Obj.Out());
    }

    public XREF<T> Ref()
    {
        return(this);
    }
};

//*******************************************************************************************
//XOBJ CLASS
//*******************************************************************************************
/**
 *
 * @author jsimms
 */
/*
    XOBJ is the base object that houses the value. XREF and XOUT are classes that
    internally use XOBJ. The classes XOBJ, XREF, and XOUT have methods that allow
    the object to be used as XREF or XOUT parameter; This is important, because
    objects of these types are interchangeable.

    See Method:
       XXX.Ref()
       XXX.Out()

    The below example shows how to use XOBJ, XREF, and XOUT;
    //
    // Reference parameter example
    //
    void AddToTotal(int a, XREF<Integer> Total)
    {
       Total.Obj.Value += a;
    }

    //
    // out parameter example
    //
    void Add(int a, int b, XOUT<Integer> ParmOut)
    {
       ParmOut.Obj.Value = a+b;
    }

    //
    // XOBJ example
    //
    int XObjTest()
    {
       XOBJ<Integer> Total = new XOBJ<>(0);
       Add(1, 2, Total.Out());    // Example of using out parameter
       AddToTotal(1,Total.Ref()); // Example of using ref parameter
       return(Total.Value);
    }
*/


public class XOBJ<T> {

    public T Value;

    public  XOBJ() {

    }

    public XOBJ(T value) {
        this.Value = value;
    }

    //
    // Method: Ref()
    // Purpose: returns a Reference Parameter object using the XOBJ value
    //
    public XREF<T> Ref()
    {
        XREF<T> ref = new XREF<T>();
        ref.Obj = this;
        return(ref);
    }

    //
    // Method: Out()
    // Purpose: returns an Out Parameter Object using the XOBJ value
    //
    public XOUT<T> Out()
    {
        XOUT<T> out = new XOUT<T>();
        out.Obj = this;
        return(out);
    }

    //
    // Method get()
    // Purpose: returns the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    public T get() {
        return Value;
    }

    //
    // Method get()
    // Purpose: sets the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    public void set(T anotherValue) {
        Value = anotherValue;
    }

    @Override
    public String toString() {
        return Value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return Value.equals(obj);
    }

    @Override
    public int hashCode() {
        return Value.hashCode();
    }
}


-1

java'nın bunu yapmanın standart bir yolu yoktur. Çoğu takas, sınıfta paketlenen listede yapılacaktır. ancak bunu yapmanın resmi olmayan bir yolu var:

package Example;

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;



 public class Test{


private static <T> void SetValue(T obj,T value){
    try {
        Field f = obj.getClass().getDeclaredField("value");
        f.setAccessible(true);
        f.set(obj,value);
        } catch (IllegalAccessException | IllegalArgumentException | 
            NoSuchFieldException | SecurityException ex) {
            Logger.getLogger(CautrucjavaCanBan.class.getName()).log(Level.SEVERE, 
       null, ex);
        }
}
private  static  void permutation(Integer a,Integer b){
    Integer tmp = new Integer(a);
    SetValue(a, b);
    SetValue(b, tmp);
}
 private  static  void permutation(String a,String b){
    char[] tmp = a.toCharArray();
    SetValue(a, b.toCharArray());
    SetValue(b, tmp);
}
public static void main(String[] args) {
    {
        Integer d = 9;
        Integer e = 8;
        HoanVi(d, e);
        System.out.println(d+" "+ e);
    }
    {
        String d = "tai nguyen";
        String e = "Thai nguyen";
        permutation(d, e);
        System.out.println(d+" "+ e);
    }
}

}

2
Bu size bir parametre için referans anlambilim vermez, bu sadece değişmez olacak şekilde tasarlanmış bir nesneyi değiştirmek için yansımayı kullanmak, bu korkunç bir fikirdir ve yine de parametre için referans anlambilim sağlamaz.
2018
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.