জাভা প্রতিবিম্ব: একটি চলকের নাম কীভাবে পাবেন?


139

জাভা প্রতিবিম্ব ব্যবহার করে, কোনও স্থানীয় ভেরিয়েবলের নাম পাওয়া সম্ভব? উদাহরণস্বরূপ, আমার যদি এটি থাকে:

Foo b = new Foo();
Foo a = new Foo();
Foo r = new Foo();

এই জাতীয় ভেরিয়েবলের নামগুলি খুঁজে পেতে পারে এমন কোনও পদ্ধতি কার্যকর করা কি সম্ভব:

public void baz(Foo... foos)
{
    for (Foo foo: foos) {
        // Print the name of each foo - b, a, and r
        System.out.println(***); 
    }
}

সম্পাদনা: এই প্রশ্নটি আলাদা যা জাভায় কোনও ফাংশনে পাস হওয়া ভেরিয়েবলের নাম খুঁজে পাওয়ার কোনও উপায় আছে কি? এতে এটি স্থানীয় ভেরিয়েবলের নাম নির্ধারণের জন্য কেউ প্রতিবিম্ব ব্যবহার করতে পারে কিনা সে সম্পর্কে আরও বিশুদ্ধভাবে প্রশ্ন জিজ্ঞাসা করে, অন্য প্রশ্নটি (স্বীকৃত উত্তর সহ) ভেরিয়েবলের মান পরীক্ষার উপর বেশি কেন্দ্রীভূত হয়।


11
সব দুর্দান্ত উত্তর! প্রত্যুত্তর এবং মন্তব্য করার জন্য প্রত্যেককে ধন্যবাদ - এটি একটি আকর্ষণীয় এবং অন্তর্দৃষ্টিপূর্ণ আলোচনা হয়েছে।
ডেভিড কোয়েল


এটা সম্ভব. আমার [সারাংশ] [1] দেখুন। JDK 1.1 থেকে JDK 7 এর জন্য কাজ করে [[1]: gist.github.com/2011728
চেন


3
সদৃশ নয়, এবং কেন তা ব্যাখ্যা করার জন্য আমার প্রশ্ন আপডেট করেছে। যদি কিছু হয়, অন্য প্রশ্নটি এটির একটি সদৃশ (বা বিশেষ ক্ষেত্রে)!
ডেভিড কোয়েল

উত্তর:


65

জাভা 8 হিসাবে, কিছু স্থানীয় পরিবর্তনশীল নামের তথ্য প্রতিবিম্বের মাধ্যমে পাওয়া যায়। দেখুন "আপডেট" বিভাগটি দেখুন।

সম্পূর্ণ তথ্য প্রায়শই ক্লাস ফাইলে সংরক্ষণ করা হয়। একটি সংকলন-সময় অপ্টিমাইজেশন হ'ল এটি সরিয়ে ফেলা, স্থান সাশ্রয় করা (এবং কিছুটা অস্পষ্টতা সরবরাহ করা)। যাইহোক, এটি উপস্থিত থাকলে, প্রতিটি পদ্ধতিতে একটি স্থানীয় ভেরিয়েবল সারণী বৈশিষ্ট্য থাকে যা স্থানীয় ভেরিয়েবলের ধরণ এবং নাম এবং তাদের সুযোগের দিক নির্দেশনার পরিধি তালিকাভুক্ত করে।

সম্ভবত এএসএমের মতো বাইট-কোড ইঞ্জিনিয়ারিং লাইব্রেরি আপনাকে রানটাইম এ এই তথ্যটি পরীক্ষা করার অনুমতি দেবে। এই তথ্যের প্রয়োজনের জন্য আমি কেবলমাত্র যুক্তিসঙ্গত জায়গাটি বিকাশের সরঞ্জামে এবং তাই বাইট-কোড ইঞ্জিনিয়ারিং অন্যান্য উদ্দেশ্যেও কার্যকর হতে পারে।


আপডেট: এর জন্য সীমিত সমর্থনটি জাভা ৮-এ যুক্ত করা হয়েছিল প্যারামিটার (স্থানীয় ভেরিয়েবলের একটি বিশেষ শ্রেণি) নামগুলি এখন প্রতিবিম্বের মাধ্যমে উপলব্ধ। অন্যান্য উদ্দেশ্যে, এটি @ParameterNameনির্ভরতা ইনজেকশন পাত্রে ব্যবহৃত টীকাগুলি প্রতিস্থাপন করতে সহায়তা করতে পারে ।


49

এটা মোটেই সম্ভব নয়। পরিবর্তনীয় নামগুলি জাভায় যোগাযোগ করা হয় না (এবং সংকলক অপ্টিমাইজেশনের কারণে এটিও মুছে ফেলা হতে পারে)।

সম্পাদনা (মন্তব্য সম্পর্কিত):

যদি আপনি এটিকে ফাংশন প্যারামিটার হিসাবে ব্যবহার করার ধারণা থেকে পিছিয়ে যান তবে এখানে একটি বিকল্প রয়েছে (যা আমি ব্যবহার করব না - নীচে দেখুন):

public void printFieldNames(Object obj, Foo... foos) {
    List<Foo> fooList = Arrays.asList(foos);
    for(Field field : obj.getClass().getFields()) {
         if(fooList.contains(field.get()) {
              System.out.println(field.getName());
         }
    }
}

a == b, a == r, or b == rঅন্যান্য ক্ষেত্রগুলির ক্ষেত্রে একই উল্লেখ রয়েছে তবে সেখানে সমস্যা থাকবে।

প্রশ্নটি স্পষ্ট হওয়ার পর এখনই সম্পাদনা অপ্রয়োজনীয়


তারপরে আপনি কীভাবে এটি ব্যাখ্যা করবেন: java.sun.com/javase/6/docs/api/java/lang/reflect/Feld.html ?
আউটলা প্রোগ্রামার

1
-1: আমি মনে করি আপনি ভুল বুঝতে পেরেছেন। @ ডেভিড ক্ষেত্রগুলির পরে, স্থানীয় ভেরিয়েবল নয়। রিফ্লেকশন এপিআইয়ের মাধ্যমে স্থানীয় ভেরিয়েবলগুলি প্রকৃতপক্ষে অনুপলব্ধ।
লুক উডওয়ার্ড

আমি মনে করি পোড়োকুই লাইটেস্টেডটা সঠিক। স্পষ্টতই ক্ষেত্রগুলি অপ্টিমাইজ করা যায় না, তাই মার্সেল জে অবশ্যই স্থানীয় ভেরিয়েবলগুলির কথা ভাবছেন।
মাইকেল ম্যাইইয়ার্স

3
@ ডেভিড: আপনার স্থানীয় ভেরিয়েবলের পরিবর্তে ক্ষেত্র বোঝাতে চাইলে আপনাকে এডিট করতে হবে। মূল প্রশ্নটি এমন কোড দেয় যা খ, ক এবং আর স্থানীয় ভেরিয়েবল হিসাবে ঘোষণা করে।
জেসন এস

7
আমি স্থানীয় ভেরিয়েবলগুলি বোঝাতে চেয়েছিলাম এবং এটি প্রতিফলিত করার জন্য আমি প্রশ্নটি সম্পাদনা করেছি। আমি ভেবেছিলাম ভেরিয়েবলের নাম পাওয়া সম্ভব না, তবে আমি অনুভব করেছি যে অসম্ভব বিবেচনা করার আগে আমি এসওকে জিজ্ঞাসা করব।
ডেভিড কোয়েল

30

( সম্পাদনা করুন: পূর্ববর্তী দুটি উত্তর মুছে ফেলা হয়েছে, একটি সম্পাদনার আগে দাঁড়িয়ে থাকা প্রশ্নের উত্তর দেওয়ার জন্য একটি এবং একেবারে ভুল না হলেও, অন্তত এটির নিকটেই। )

আপনি ( javac -g) -এ ডিবাগ তথ্য দিয়ে সংকলন করা হলে স্থানীয় ভেরিয়েবলের নামগুলি। ক্লাস ফাইলে রাখা হয়। উদাহরণস্বরূপ, এই সাধারণ ক্লাসটি নিন:

class TestLocalVarNames {
    public String aMethod(int arg) {
        String local1 = "a string";
        StringBuilder local2 = new StringBuilder();
        return local2.append(local1).append(arg).toString();
    }
}

সংকলনের পরে javac -g:vars TestLocalVarNames.java, স্থানীয় ভেরিয়েবলের নামগুলি এখন .class ফাইলটিতে রয়েছে। javapএর -lপতাকা ("মুদ্রণ লাইন নম্বর এবং স্থানীয় ভেরিয়েবল টেবিল") এগুলি প্রদর্শন করতে পারে।

javap -l -c TestLocalVarNames শো:

class TestLocalVarNames extends java.lang.Object{
TestLocalVarNames();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5      0    this       LTestLocalVarNames;

public java.lang.String aMethod(int);
  Code:
   0:   ldc     #2; //String a string
   2:   astore_2
   3:   new     #3; //class java/lang/StringBuilder
   6:   dup
   7:   invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V
   10:  astore_3
   11:  aload_3
   12:  aload_2
   13:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   16:  iload_1
   17:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   20:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   23:  areturn

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      24      0    this       LTestLocalVarNames;
   0      24      1    arg       I
   3      21      2    local1       Ljava/lang/String;
   11      13      3    local2       Ljava/lang/StringBuilder;
}

VM- র বৈশিষ্ট ব্যাখ্যা আমরা এখানে কী দেখছি:

Rib4.7.9 LocalVariableTableবৈশিষ্ট্য :

LocalVariableTableঅ্যাট্রিবিউটে একটি এর একটি ঐচ্ছিক পরিবর্তনশীল দৈর্ঘ্যের অ্যাট্রিবিউট Code(§4.7.3) অ্যাট্রিবিউট। এটি কোনও পদ্ধতি কার্যকর করার সময় প্রদত্ত স্থানীয় ভেরিয়েবলের মান নির্ধারণ করতে ডিবাগাররা ব্যবহার করতে পারেন।

LocalVariableTableদোকানে নাম এবং প্রতিটি স্লটে ভেরিয়েবল ধরনের, তাই এটি বাইটকোড সঙ্গে তাদের মেলে করা সম্ভব। ডিবাগাররা এভাবেই "এক্সপ্রেশনকে মূল্যায়ন করুন" করতে পারেন।

যেমন ইরিকসন বলেছেন, যদিও সাধারণ প্রতিবিম্বের মাধ্যমে এই টেবিলটি অ্যাক্সেস করার কোনও উপায় নেই। আপনি যদি এখনও এটি করার জন্য দৃ determined় প্রতিজ্ঞ হন তবে আমি বিশ্বাস করি জাভা প্ল্যাটফর্ম ডিবাগার আর্কিটেকচার (জেপিডিএ) সাহায্য করবে (তবে আমি নিজে এটি কখনও ব্যবহার করি নি)।


1
উহ-ওহ, আমি সম্পাদনা করার সময় এরিকসন পোস্ট করেছে এবং এখন আমি তার বিরোধিতা করছি। যার সম্ভবত আমি ভুল করছি means
মাইকেল ম্যাইইয়ার্স

ডিফল্টরূপে, javacডিবাগিংয়ে সহায়তা করার জন্য প্রতিটি পদ্ধতির জন্য ক্লাসে স্থানীয় ভেরিয়েবল টেবিল রাখে। স্থানীয় ভেরিয়েবল টেবিলটি দেখতে -lবিকল্পটি ব্যবহার করুন javap
এরিকসন

ডিফল্টরূপে নয়, মনে হয়। javac -g:varsএটি পেতে আমাকে ব্যবহার করতে হয়েছিল। (আমি সম্পাদনা করতে গত তিন ঘন্টার জন্য এই উত্তরটি চেষ্টা করেছি, কিন্তু আমি আগেই বলেছি আমার নেটওয়ার্ক সংযোগ সমস্যা হচ্ছে, যা এটি গবেষণা কঠিন করে তোলে।)
মাইকেল ম্যাইইয়ার্স

2
আপনি ঠিক বলেছেন, সে সম্পর্কে দুঃখিত। এটি লাইন নম্বর যা ডিফল্টরূপে "চালু" থাকে।
এরিকসন

15
import java.lang.reflect.Field;


public class test {

 public int i = 5;

 public Integer test = 5;

 public String omghi = "der";

 public static String testStatic = "THIS IS STATIC";

 public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
  test t = new test();
  for(Field f : t.getClass().getFields()) {
   System.out.println(f.getGenericType() +" "+f.getName() + " = " + f.get(t));
  }
 }

}

3
getDeclaredFields()আপনি প্রাইভেট ফিল্ডের নামও চাইলে ব্যবহার করা যেতে পারে
coffeMug

10

আপনি এটির মতো করতে পারেন:

Field[] fields = YourClass.class.getDeclaredFields();
//gives no of fields
System.out.println(fields.length);         
for (Field field : fields) {
    //gives the names of the fields
    System.out.println(field.getName());   
}

আপনার উত্তরটি সমস্ত ফায়াদ পেতে ভাল কাজ করে। কেবলমাত্র একটি ক্ষেত্র পাওয়ার জন্য, আমি যখন ব্যবহার করব: আপনারক্লাস। আমি নালপয়েন্টার পেয়েছি। এটি ব্যবহার করতে সমস্যা কি? আমার কীভাবে getDeclaredField পদ্ধতি ব্যবহার করা উচিত?
শশী রঞ্জন

0

আপনাকে যা করতে হবে তা হ'ল ক্ষেত্রগুলির একটি অ্যারে তৈরি করা এবং তারপরে এটি নীচে দেখানো পছন্দ মতো শ্রেণিতে সেট করুন।

Field fld[] = (class name).class.getDeclaredFields();   
for(Field x : fld)
{System.out.println(x);}

আপনি যদি উদাহরণস্বরূপ

Field fld[] = Integer.class.getDeclaredFields();
          for(Field x : fld)
          {System.out.println(x);}

আপনি পাবেন

public static final int java.lang.Integer.MIN_VALUE
public static final int java.lang.Integer.MAX_VALUE
public static final java.lang.Class java.lang.Integer.TYPE
static final char[] java.lang.Integer.digits
static final char[] java.lang.Integer.DigitTens
static final char[] java.lang.Integer.DigitOnes
static final int[] java.lang.Integer.sizeTable
private static java.lang.String java.lang.Integer.integerCacheHighPropValue
private final int java.lang.Integer.value
public static final int java.lang.Integer.SIZE
private static final long java.lang.Integer.serialVersionUID

0

সাধারণ হিসাবে @ মার্সেল জ্যাকওয়ার্থ এর উত্তর আপডেট করুন।

এবং কেবল ক্লাস অ্যাট্রিবিউটের সাথে কাজ করছে, পদ্ধতি ভেরিয়েবলের সাথে কাজ করছে না।

    /**
     * get variable name as string
     * only work with class attributes
     * not work with method variable
     *
     * @param headClass variable name space
     * @param vars      object variable
     * @throws IllegalAccessException
     */
    public static void printFieldNames(Object headClass, Object... vars) throws IllegalAccessException {
        List<Object> fooList = Arrays.asList(vars);
        for (Field field : headClass.getClass().getFields()) {
            if (fooList.contains(field.get(headClass))) {
                System.out.println(field.getGenericType() + " " + field.getName() + " = " + field.get(headClass));
            }
        }
    }

-1

এই উদাহরণটি দেখুন:

PersonneTest pt=new PersonneTest();
System.out.println(pt.getClass().getDeclaredFields().length);
Field[]x=pt.getClass().getDeclaredFields();
System.out.println(x[1].getName());
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.