Чи у Java є щось на зразок ключових слів для відмови та перегляду C #?


113

Щось таке:

приклад посилання:

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

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

зовнішній приклад:

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

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


5
ІМО, ти мало чого бракуєш. Єдиний раз, коли я коли-небудь використовую refабо outв C #, це коли я використовую такий зразок TryParse(), коли метод повертає бульний результат, і єдиний спосіб отримати з нього розбір значення - це за допомогою refабо out.
Роберт Харві

3
Вгадайте, що, це правильно, що мені потрібно використовувати! ;)
пожирав елізіум

Інший спосіб зробити це - повернути складений об’єкт із статусом і нульовим значенням у ньому. Але я визнаю, це трохи Рубе Голдберг-іш.
Роберт Харві

1
Немає нічого поганого у тому, щоб повернути складений об’єкт, якби тільки був заздалегідь заданий корисний (тобто кортежі). Але зачекайте, для ефективної роботи потрібні неотримані дженерики, що працюють із примітивними типами :)
Павло Мінаєв

Відповіді:


102

Ні, у Java немає щось на зразок C # refі outключових слів для проходження за посиланням.

Ви можете передати лише значення за допомогою Java. Навіть посилання передаються за значенням. Для отримання детальної інформації див. Сторінку Джона Скіта про передачу параметрів на Java .

Щоб зробити щось подібне refабо outвам доведеться загортати параметри всередині іншого об'єкта і передавати посилання на цей об'єкт як параметр.


5
На деяких слід це розширити. Ви можете передавати лише примітиви (int, short, char тощо) як значення. І ні, виходу немає.
Corey Sunwold

14
Це не на 100% вірно. Якщо ви передаєте масив або клас, посилання на масив або об'єкт передається за значенням, ви можете змінити внутрішні масиви на масив або об'єкт, і це відобразиться в абоненті.
Ромен Хіппо

12
@fearofawhackplanet: Гм, якщо ви не використовуєте ref.
Роберт Харві

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
Марк Байєрс

5
З точки зору CLR, ви передаєте керовану посилання ( T&) за значенням, так. Але C # має власну термінологію, і вона конкретно не включає такі речі, як значення типу ref T- з точки зору C #, refє строго модифікатором параметрів, і говорити про "передачу посилання за значенням" стосовно неї не має сенсу. .
Павло Мінаєв

30

Пряма відповідь: Ні

Але ви можете імітувати довідку з обгортками .

І виконайте наступне:

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

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

Вийшов

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

І в основному будь-який інший тип, такий як:

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

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

28
Ой. Це потворно.
пожирав елізіум

46
Я ніколи не говорив: Ви можете це зробити так витончено : P
OscarRyz

тому чому не працює: приватний статичний недійсний ParseLine (String newline, String [] aWrapper, Integer [] bWrapper) {StringTokenizer st = new StringTokenizer (newline); aWrapper [0] = st.nextToken (); bWrapper [0] = новий цілий (st.nextToken ()); } ParseLine (новий рядок, новий рядок [] {a}, новий цілий [] {b});
Elad Benda

3
@ user311130 Ваш код важко читати, але ви можете створити нове запитання, сказавши щось на зразок: "Я знайшов цю відповідь <посилання на мою відповідь>, але наступний не працює <ваш код тут>
OscarRyz

Це противно, але я все одно надаю це подібному тому, що воно вирішує проблему "найчистішим" способом, який я можу придумати для Java на даний момент у часі ...
Pangamma

8

Насправді в мові Java не існує ані реф, ані рефінансування ключових слів , наскільки я знаю. Однак я тільки перетворив C # код в Java , який використовує з параметра і порадить , що я тільки що зробив. Ви повинні загортати будь-який об'єкт у клас обгортки та передавати значення, обернені в екземплярі об’єкта обгортки, наступним чином;

Простий приклад використання Wrapper

Ось клас Wrapper ;

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

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

І ось код тесту;

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!";
    }

}

Приклад реального світу

Метод AC # .NET з використанням параметра

Тут є C # .NET метод , який використовує з ключових слів;

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;
}

Java еквівалент коду C #, який використовує параметр out

А еквівалент Java цього методу за допомогою обгорткового класу такий;

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;
}

Клас обгортки

І клас обгортки, який використовується в цьому коді Java, наведений нижче;

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;
    }

}

див. колишні відповіді.
пашуте

Дати детальну відповідь на негативне голосування - смішно. Я перевірив ТА і не зміг знайти точну точну відповідь з демо-кодом, тому я написав цю відповідь, наскільки я пам'ятаю. Якщо ви чекаєте однозначної відповіді і голосуєте за будь-яку іншу відповідь, тоді ТА повинен заборонити всю відповідь, окрім того, щоб отримати підтвердження від власника питання.
Левент Дівіліоглу

Гаразд, я можу видалити негативне голосування, лише якщо ви відредагуєте відповідь. Тому прочитайте інші відповіді та поясніть, чому ви не хотіли використовувати ці рішення. Обгортка (зокрема, обгортка REF та OUT лише для задоволення). 5 людей дали короткі та повні відповіді з прикладами , і лише Ейал в основному написав: "Ні, ти не можеш".
пашуте

1
Ця відповідь виглядає чудово. Це схоже на головну відповідь, але дає повністю детальні приклади, як використовувати клас обгортки на Java.
hubatish

8

Java передає параметри за значенням і не має жодного механізму, який би дозволяв проходити посилання. Це означає, що щоразу, коли параметр передається, його значення копіюється в кадр стека, що обробляє виклик.

Термін значення , який я використовую тут, потребує невеликого уточнення. У Java у нас є два види змінних - примітиви та об'єкти. Значення примітиву - це сам примітив, а значення об'єкта - його посилання (а не стан об'єкта, на який посилається). Отже, будь-яка зміна значення всередині методу змінить лише копію значення в стеку, і виклик не побачить. Наприклад, не існує жодного способу реалізувати реальний метод swap, який отримує дві посилання та замінює їх (не їх вміст!).


6

Як і багатьом іншим, мені потрібно було перетворити проект C # на Java. Я не знайшов повного рішення в Інтернеті щодо модифікаторів out та ref . Але я зміг взяти знайдену інформацію та розширити її, щоб створити власні класи для виконання вимог. Я хотів зробити різницю між параметрами ref та out для ясності коду. З наведеними нижче класами це можливо. Нехай ця інформація заощадить інший час та сили.

Приклад включений у наведений нижче код.

//*******************************************************************************************
//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 не має стандартного способу це зробити. Більшість свопів буде здійснено у списку, який упакований у клас. але є неофіційний спосіб зробити це:

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);
    }
}

}

1
Це не дає вам еталонної семантики для параметра, це просто використання відображення для мутації об'єкта, призначеного для непорушності, що є жахливою ідеєю, і все ще не забезпечує референтну семантику для параметра.
Сервіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.