سؤال

يمكنك القيام بذلك في .NET باستخدام الكلمة الأساسية "ref".هل هناك أي طريقة للقيام بذلك في جافا؟

هل كانت مفيدة؟

المحلول

وماذا تفعلون في طريقة لديك؟ إذا كنت مجرد ملء صفيف موجودة، فإنك لا تحتاج دلالات تمرير كل إشارة - سواء في .NET أو في جاوة. في كلتا الحالتين، سيتم تمرير الإشارة من حيث القيمة - من التغييرات إلى <م> الكائن سوف تكون مرئية من قبل المتصل. وهذا مثل قول أحدهم عنوان منزلك ويطلب منهم تقديم شيء لها - لا مشكلة

إذا <م> حقا تريد تمرير كل إشارة دلالات، أي المتصل سوف نرى أي تغييرات يتم إجراؤها على المعلمة نفسها، على سبيل المثال تعيين إلى فارغة أو إشارة إلى صفيف بايت مختلفة، ثم يحتاج إما طريقة لإرجاع قيمة جديدة، أو تحتاج إلى تمرير إشارة إلى نوع من "حامل" والذي يتضمن إشارة إلى صفيف بايت، والتي يمكن أن يكون أمسك (ربما تغيرت) إشارة منه لاحقا.

وبعبارة أخرى، إذا الأسلوب الخاص بك يبدو أمثال هذا:

public void doSomething(byte[] data)
{
    for (int i=0; i < data.length; i++)
    {
        data[i] = (byte) i;
    }
}

وبعد ذلك كنت على ما يرام. إذا طريقتك يبدو مثل هذا:

public void createArray(byte[] data, int length)
{
    // Eek! Change to parameter won't get seen by caller
    data = new byte[length]; 
    for (int i=0; i < data.length; i++)
    {
        data[i] = (byte) i;
    }
}

وبعد ذلك كنت بحاجة إلى تغيير لأنها إما:

public byte[] createArray(int length)
{
    byte[] data = new byte[length]; 
    for (int i=0; i < data.length; i++)
    {
        data[i] = (byte) i;
    }
    return data;
}

وأو:

public class Holder<T>
{
    public T value; // Use a property in real code!
}

public void createArray(Holder<byte[]> holder, int length)
{
    holder.value = new byte[length]; 
    for (int i=0; i < length; i++)
    {
        holder.value[i] = (byte) i;
    }
}

لمزيد من التفاصيل، وقراءة معلمة يمر في C # و <لأ href = " http://pobox.com/~skeet/java/parameters.html "يختلط =" noreferrer "> المعلمة يمر في جاوة . (السابق هو أفضل خطي من هذا الأخير، وأنا أخشى في يوم من الأيام سوف تحصل على جولة لفعل التحديث.)

نصائح أخرى

في الواقع، في جافا، يتم تمرير المراجع حسب القيمة.

وفي هذه الحالة يكون المرجع أ byte[] هدف.سيتم رؤية أي تغييرات تؤثر على الكائن نفسه من خلال طريقة المتصل.

ومع ذلك، إذا حاولت استبدال المرجع، على سبيل المثال باستخدام new byte[length], ، أنت تقوم فقط باستبدال المرجع الذي حصلت عليه من خلال قيمة التمرير، لذلك لا تقوم بتغيير المرجع في طريقة المتصل.

إليك قراءة مثيرة للاهتمام حول هذه المشكلة: Java هي لعبة Pass-by-Value اللعنة!


إليك مثال ملموس:

public class PassByValue
{
    public static void modifyArray(byte[] array)
    {
        System.out.println("Method Entry:  Length: " + array.length);
        array = new byte[16];
        System.out.println("Method Exit:   Length: " + array.length);
    }

    public static void main(String[] args)
    {
        byte[] array = new byte[8];
        System.out.println("Before Method: Length: " + array.length);
        modifyArray(array);
        System.out.println("After Method:  Length: " + array.length);
    }
}

سيقوم هذا البرنامج بإنشاء byte مجموعة من الطول 8 في ال main الطريقة التي سوف تستدعي modifyArray الطريقة، حيث الجديد byte مجموعة من الطول 16 أنشئ.

قد يبدو أنه من خلال إنشاء ملف جديد byte مصفوفة في modifyArray الطريقة، أن طول byte مجموعة عند العودة إلى main ستكون الطريقة 16, ومع ذلك، فإن تشغيل هذا البرنامج يكشف شيئًا مختلفًا:

Before Method: Length: 8
Method Entry:  Length: 8
Method Exit:   Length: 16
After Method:  Length: 8

طول byte مجموعة عند العودة من modifyArray تعود الطريقة إلى 8 بدلاً من 16.

لماذا هذا؟

ذلك لأن main طريقة تسمى modifyArray طريقة وإرسالها إشارة منسوخة إلى new byte[8] باستخدام القيمة العابرة.ثم، modifyArray طريقة تخلص من المرجع المنسوخ عن طريق إنشاء ملف new byte[16].بحلول الوقت الذي نغادر فيه modifyArray, ، إشارة إلى new byte[16] خارج النطاق (وفي النهاية سيتم جمع البيانات المهملة.) ومع ذلك، فإن main الأسلوب لا يزال لديه إشارة إلى new byte[8] كما هو فقط أرسل المرجع المنسوخ وليس مرجعا فعليا للمرجع.

يجب أن يوضح ذلك أن Java ستمرر المرجع باستخدام قيمة التمرير.

تستخدم Java التمرير حسب القيمة لوسائط الطريقة.

  • البدائيون (int، boolean، إلخ) هي حالات خاصة في Java.ليست كائنات في حد ذاتها.في هذه الحالة، يتم تمرير نسخة من البدائية (الوسيطة) إلى الوظيفة.وهذا يتوافق بشكل جيد مع نظرية التمرير بالقيمة.
  • بالنسبة للكائنات، ما يحدث هو أن المرجع للكائن يتم تمريره حسب القيمة (يتم إنشاء نسخة من المرجع بدلاً من الكائن)...لكن كلا المرجعين يشيران إلى نفس الكائن.لذا، إذا قمت بتعديل معلمة كائن في إحدى الطرق، فسيتم تعديل الكائن الفعلي.

هذه المقالة يجب أن تساعدك..http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

أما بالنسبة لسؤال OP، فما عليك سوى تمرير الإشارة إلى مصفوفة البايت[] إلى الطريقة.ستكون النتيجة الصافية مماثلة للتمرير حسب المرجع.إذا قمت بتعديل مصفوفة البايت، فسيتمكن المتصل من رؤية تنفيذ طريقة نشر التغييرات.

تحديث لقمع المقاومة :) => يشير إلى الإخراج

.نت لاند

class Counter
{
  private int m_count = 0;
  public override string  ToString()
  {
     return String.Format("Counter ID{0} : Value {1}", this.GetHashCode(), m_count);
  }
  public void Increment()
  {  m_count++;  }
}
class MakeAPass
{
   public void PassByValueAndModify(int i)
   {   i = 20;    }

   public void PassByRefAndModify(ref int i)
   {   i = 20;   }

   public void PassByValueAndModify(Counter c)
   {   c.Increment();   }

   public void PassByRefAndModify(ref Counter c)
   {   c.Increment();   }

   public void PassByRefAndReassign(ref Counter c)
   {
      c = new Counter();
      for (int i=0; i<5; ++i)
         c.Increment();
   }
}

static void Main(string[] args)
{
   MakeAPass obj = new MakeAPass();
   int intVal = 10;
   obj.PassByValueAndModify(intVal);
   Console.WriteLine(intVal);              // => 10
   obj.PassByRefAndModify(ref intVal);
   Console.WriteLine(intVal);              // => 20

   Counter obCounter = new Counter();
   obj.PassByValueAndModify(obCounter);
   Console.WriteLine(obCounter.ToString());  // => Counter ID58225482 : Value 1
   obj.PassByRefAndModify(ref obCounter);
   Console.WriteLine(obCounter.ToString());  // => Counter ID58225482 : Value 2
   obj.PassByRefAndReassign(ref obCounter);
   Console.WriteLine(obCounter.ToString());  // => Counter ID54267293 : Value 5
}

جافا لاند

تعديلات طفيفة مطلوبة:استخدم hashCode() و+ لربط السلاسل في Counter.java...

class MakeAPass
{
   public void PassByValueAndModify(int i)
   {   i = 20;   }

   // can't be done.. Use Integer class which wraps primitive
   //public void PassByRefAndModify(ref int i)

   public void PassByValueAndModify(Counter c)
   {   c.Increment();   }

   // same as above. no ref keyword though
   //public void PassByRefAndModify(ref Counter c)

   // this can't be done as in .net
   //public void PassByRefAndReassign(ref Counter c)
   public void PassAndReassign(Counter c)
   {
      c = new Counter();
      for (int i=0; i<5; ++i)
         c.Increment();
   }
}
public static void main(String args[])
{
   MakeAPass obj = new MakeAPass();
   int intVal = 10;
   obj.PassByValueAndModify(intVal);
   System.out.println(intVal);                 // => 10 
   //obj.PassByRefAndModify(ref intVal);
   //System.out.println(intVal);               // can't get it to say 20

   Counter obCounter = new Counter();
   obj.PassByValueAndModify(obCounter);
   System.out.println(obCounter.ToString());    // => Counter ID3541984 : Value 1
   //obj.PassByRefAndModify(ref obCounter);
   //Console.WriteLine(obCounter.ToString());   // no ref. but can make it 2 by repeating prev call
   obj.PassAndReassign(obCounter);
   System.out.println(obCounter.ToString());    // => Counter ID3541984 : Value 1
                                                // can't get it to say 5  
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top