কেন একটি জাভা শ্রেণি একটি ফাঁকা রেখার সাথে আলাদাভাবে সংকলন করে?


207

আমি নিম্নলিখিত জাভা ক্লাস আছে

public class HelloWorld {
  public static void main(String []args) {
  }
}

আমি যখন এই ফাইলটি সংকলন করি এবং ফলাফল প্রাপ্ত ক্লাস ফাইলটিতে একটি sha256 চালাই

9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff  HelloWorld.class

পরবর্তী আমি ক্লাসটি সংশোধন করেছি এবং এর মতো একটি ফাঁকা রেখা যুক্ত করেছি:

public class HelloWorld {

  public static void main(String []args) {
  }
}

আবার আমি একই ফলাফল পাওয়ার আশা করে আউটপুটটিতে একটি sha256 চালিয়েছিলাম তবে পরিবর্তে আমি পেয়েছি

11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f  HelloWorld.class

আমি এই টিউটোরিয়ালপয়েন্ট নিবন্ধে পড়েছি যে:

সম্ভবত একটি মন্তব্য সহ কেবলমাত্র সাদা স্থানযুক্ত একটি লাইন একটি ফাঁকা রেখা হিসাবে পরিচিত, এবং জাভা একে একে একে একে উপেক্ষা করে।

সুতরাং আমার প্রশ্নটি হল যেহেতু জাভা ফাঁকা রেখা উপেক্ষা করে কেন উভয় প্রোগ্রামের জন্যই সংকলিত বাইকোড আলাদা?

যাহোক HelloWorld.classএকটি 0x03বাইটের মধ্যে পার্থক্য একটি বাইট দ্বারা প্রতিস্থাপিত হয় 0x04


45
নোট করুন যে সংকলকটি সাধারণভাবে সত্ত্বেও ক্লাস ফাইল তৈরিতে নির্বিচারবাদী হতে বাধ্য নয়। এই প্রশ্নটি দেখুন । ডিফল্টভাবে জার ফাইলগুলি পুনরায় উত্পাদনযোগ্য নয় , এমনকি একই কোডটি সংকলন করার ফলে দুটি পৃথক জেআর হতে হবে। কারণ ফাইলগুলি এবং টাইমস্ট্যাম্পগুলির ক্রম মেলে না। নির্দিষ্ট কনফিগারেশনের মাধ্যমে পুনরুত্পাদনযোগ্য বিল্ডগুলি সম্ভব।
গিয়াকোমো আলজেটা

22
টিউটোরিয়ালপয়েন্টটি দাবি করেছে যে ফাঁকা রেখাগুলি "জাভা সম্পূর্ণ উপেক্ষা করে"জাভা ল্যাঙ্গুয়েজ স্পেসিফিকেশনের ৩.৪ ধারা অন্যথায় বলে says কোনটি বিশ্বাস করবেন? ...
স্কোমিসা

37
@ স্পোমিসা
wizzwizz4

4
@ গিয়াকোমো অলজিটা এমনকি একটি একক বাইটকোড ফাইলের জন্য একটি নির্দিষ্ট বাইটকোড ফর্মও নেই। উদাহরণস্বরূপ, সদস্যদের ক্রমটি অনির্ধারিত, সুতরাং যদি সংকলক Setঅভ্যন্তরীণভাবে র্যান্ডমাইজেশন সহ নতুন অপরিবর্তনীয় গুলি ব্যবহার করে তবে এটি প্রতিটি রানের ক্ষেত্রে একটি পৃথক ক্রম উত্পাদন করতে পারে। এটি সংকলন-সময়যুক্ত একটি কাস্টম বৈশিষ্ট্য যুক্ত করতে পারে। এবং আরও…
হলগার

15
@DioPhung অন্য পাঠ শিখেছি: tutorialspoint ভাল টিউটোরিয়াল জন্য একটি নির্ভরযোগ্য উৎস নয়
jwenting

উত্তর:


331

মূলত, লাইন নম্বরগুলি ডিবাগিংয়ের জন্য রাখা হয়, সুতরাং আপনি যদি আপনার উত্স কোডটি আপনার মতো করে পরিবর্তন করেন তবে আপনার পদ্ধতিটি অন্য একটি লাইনে শুরু হয় এবং সংকলিত শ্রেণি পার্থক্যটি প্রতিবিম্বিত করে।


11
এটি ওপি দ্বারা রিপোর্ট করা বাইটগুলির মধ্যে কেন তার পৃথক রয়েছে তাও ব্যাখ্যা করে: end-of-transmissionASCII কোড 4 end-of-textএর পক্ষে এবং ASCII কোড 3 এর জন্য দাঁড়িয়েছে
ফেরিবিগ

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

14
আপনার উত্তরের আনুষ্ঠানিক সমর্থন হিসাবে, জাভা SE 11 এর জন্য জাভা ভাষা নির্দিষ্টকরণের বিভাগ 3.4 ( "লাইন টার্মিনেটর" ) থেকে : "একটি জাভা সংকলক পরবর্তীতে ইউনিকোড ইনপুট অক্ষরের ক্রমকে লাইন টার্মিনেটরগুলি সনাক্ত করে লাইনগুলিতে ভাগ করে ... লাইনগুলি সংজ্ঞায়িত করা হয়েছে লাইন টার্মিনেটর দ্বারা একটি জাভা সংকলক দ্বারা উত্পাদিত লাইন সংখ্যা নির্ধারণ করতে পারে "
স্কোমিসা

4
এই রেখা সংখ্যার একটি গুরুত্বপূর্ণ ব্যবহার হ'ল যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয়; এটি আপনাকে স্ট্যাক ট্রেসের ব্যতিক্রমের লাইন নম্বরটি বলতে পারে।
gparyani

114

আপনি javap -vভারবস তথ্য আউটপুট হবে যা ব্যবহার করে পরিবর্তনটি দেখতে পারেন । ইতিমধ্যে উল্লিখিত অন্যান্যগুলির মতো পার্থক্যটি লাইন সংখ্যায় থাকবে:

$ javap -v HelloWorld.class > with-line.txt
$ javap -v HelloWorld.class > no-line.txt
$ diff -C 1 no-line.txt with-line.txt
*** no-line.txt 2018-10-03 11:43:32.719400000 +0100
--- with-line.txt       2018-10-03 11:43:04.378500000 +0100
***************
*** 2,4 ****
    Last modified 03-Oct-2018; size 373 bytes
!   MD5 checksum 058baea07fb787bdd81c3fb3f9c586bc
    Compiled from "HelloWorld.java"
--- 2,4 ----
    Last modified 03-Oct-2018; size 373 bytes
!   MD5 checksum 435dbce605c21f84dda48de1a76e961f
    Compiled from "HelloWorld.java"
***************
*** 50,52 ****
        LineNumberTable:
!         line 3: 0
        LocalVariableTable:
--- 50,52 ----
        LineNumberTable:
!         line 4: 0
        LocalVariableTable:

আরও স্পষ্টভাবে LineNumberTableবিভাগে ক্লাস ফাইলটি পৃথক :

লাইননবার্টেবল অ্যাট্রিবিউটটি একটি কোড অ্যাট্রিবিউট (§4.7.3) এর বৈশিষ্ট্য সারণীতে একটি inচ্ছিক পরিবর্তনশীল-দৈর্ঘ্যের বৈশিষ্ট্য। এটি ডিবাগাররা ব্যবহার করতে পারেন কোড অ্যারের কোন অংশটি মূল উত্স ফাইলে প্রদত্ত লাইন সংখ্যার সাথে সম্পর্কিত কিনা তা নির্ধারণ করতে।

যদি কোনও কোড অ্যাট্রিবিউটের বৈশিষ্ট্য সারণীতে একাধিক লাইননিবারটেবল অ্যাট্রিবিউট উপস্থিত থাকে তবে সেগুলি যে কোনও ক্রমে উপস্থিত হতে পারে।

কোনও কোড অ্যাট্রিবিউটের বৈশিষ্ট্য সারণীতে উত্স ফাইলের প্রতি লাইন প্রতি একাধিক লাইননবার্টেবল অ্যাট্রিবিউট থাকতে পারে। এটি হ'ল লাইন নম্বারটেবল বৈশিষ্ট্যগুলি একসাথে উত্স ফাইলের একটি প্রদত্ত লাইন উপস্থাপন করতে পারে এবং উত্স রেখাগুলির সাথে এক থেকে এক হওয়ার দরকার নেই।


57

"জাভা ফাঁকা রেখা উপেক্ষা করে" ধারণাটি ভুল The এখানে একটি কোড স্নিপেট যা পদ্ধতির আগে খালি লাইনের সংখ্যার উপর নির্ভর করে আলাদা আচরণ করে main:

class NewlineDependent {

  public static void main(String[] args) {
    int i = Thread.currentThread().getStackTrace()[1].getLineNumber();
    System.out.println((new String[]{"foo", "bar"})[((i % 2) + 2) % 2]);
  }
}

এর আগে যদি কোনও খালি লাইন না থাকে তবে mainএটি মুদ্রণ করে "foo"তবে আগে একটি খালি লাইন দিয়ে mainএটি মুদ্রণ করে "bar"

যেহেতু রানটাইম আচরণটি ভিন্ন, কোনও টাইমস্ট্যাম্প বা অন্যান্য মেটাডেটা নির্বিশেষে .classফাইলগুলি অবশ্যই আলাদা হতে হবে

এটি কেবল জাভা নয়, লাইন সংখ্যা সহ স্ট্যাক ফ্রেমে অ্যাক্সেস করে এমন প্রতিটি ভাষার জন্য এটি ধারণ করে।

দ্রষ্টব্য: যদি এটি -g:none(কোনও ডিবাগিং তথ্য ছাড়াই) দিয়ে সংকলিত হয় , তবে লাইন নম্বরগুলি অন্তর্ভুক্ত করা হবে না, getLineNumber()সর্বদা ফিরে আসে -1এবং প্রোগ্রামটি সর্বদা প্রিন্ট করে "bar", লাইন বিরতির সংখ্যা নির্বিশেষে।


11
এটি মুদ্রণ করতে পারে Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
xehpuk

1
@ এক্সেহপুক আমি যেভাবে পেলাম তা কেবল পতাকাটি -1ব্যবহার করা -g:none। সাধারণ ব্যবহার করে এই ব্যতিক্রমটি পাওয়ার কোনও অন্য উপায় আছে কি javac?
আন্দ্রে টিউকিন

3
আমি কেবল -gবিকল্প দিয়ে অনুমান করি । এছাড়াও আছে -g:varsএবং -g:sourceযা প্রজন্মের প্রতিরোধ করে LineNumberTable
xehpuk

14

ডিবাগিংয়ের জন্য যে কোনও লাইন নম্বর বিশদের পাশাপাশি আপনার ম্যানিফেস্টে বিল্ড সময় এবং তারিখও সঞ্চয় করতে পারে। প্রতিবার আপনি সংকলন করার সময় এটি স্বাভাবিকভাবেই আলাদা হবে।


14
সি # তেও এই সমস্যা আছে; সম্প্রতি পর্যন্ত কম্পাইলার সবসময় একটি তাজা GUID এমবেডেড সমাবেশ যাতে আপনি নিশ্চিত হবে যে দুটি তৈরী করে দেওয়া হতো উত্পন্ন না বাইনারি অভিন্ন হবে, যাতে আপনি তাদের বলুন পারে পৃথক্!
এরিক লিপার্ট 0

3
@ এরিকলিপার্ট যদি দুটি বিল্ডগুলি কেবল তাদের উত্পন্ন সময় অনুসারে আলাদা হয় (অর্থাত্ অভিন্ন কোড বেস), আমরা কি তাদেরকে একই হিসাবে ব্যবহার করব না? আধুনিক সিআই / সিডি বিল্ড পাইপলাইন (জেনকিনস, টিমসিটি, সার্কেলসিআই) সহ, আমাদের বিল্ডগুলির মধ্যে পার্থক্য করার একটি উপায় থাকবে তবে অ্যাপ্লিকেশন দৃষ্টিকোণ থেকে, অভিন্ন কোড বেস সহ নতুন বাইনারি স্থাপন কার্যকর হবে বলে মনে হয় না।
ডিও ফুং

2
@ ডিওফং এটি অন্যভাবে। আপনি দুটি ভিন্ন বিল্ডের একই জিইউডি থাকতে চান না কারণ সিস্টেমটি ঠিক কীভাবে কোনটি ব্যবহার করবেন তা সিদ্ধান্ত নিতে পারে। সুতরাং প্রতিবার একটি নতুন জিইউডি উত্পন্ন করা সহজ; এবং তারপরে আপনি এর পার্শ্ব প্রতিক্রিয়াটি পান যা এরিক একটি অনিচ্ছাকৃত ফলাফল হিসাবে বর্ণনা করে।
গ্রাহাম

3
@ লাইকিংস্টিভ লাইক আমি বলেছি, দুটি ভিন্ন বিল্ড একই জিইউইডি-র সাথে প্রতিবেদন করা আরও কম সহায়ক হবে, যা পরে একই সফ্টওয়্যার হিসাবে সিস্টেমে জানানো হবে। এটি যে কোনও ধরণের প্রভিডিং স্কিমের সম্পূর্ণ ব্যর্থতার কারণ হতে পারে, তাই এটি মিশন-সমালোচনা যে জিইউইডিগুলি কখনই সদৃশ হয় না (যুক্তিসঙ্গত সম্ভাবনার মধ্যে!)। একই উত্স কোডের দুটি পৃথক বিল্ডের জন্য পৃথক জিইউইডি থাকা সর্বাধিক তুচ্ছ বিরক্তি। সুতরাং একটি মিশন-সমালোচনামূলক ব্যর্থতার দৃশ্যের মুখোমুখি হয়ে আপনি যা খানিকটা অস্বাস্থ্যকর বলে মনে করেন তা বাস্তবে চিত্রিত হয় না।
গ্রাহাম

4
@ লাইকিংস্টিভ বাইনারিটির কোড অংশটি এখনও একই (যদি আমি বুঝতে পারি, আমি কোনও সি # দেব নই), এটি বাইনারি সংযুক্ত কিছু মেটাডেটা।
ক্যাপ্টেন ম্যান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.