Начин на живот на файловия клас Java

Добре дошли в друга част от „Под капака“. В статията от миналия месец обсъдих Java Virtual Machine, или JVM, абстрактният компютър, за който са съставени всички Java програми. Ако не сте запознати с JVM, може да искате да прочетете статията от миналия месец преди тази. В тази статия предлагам поглед към основната структура и начин на живот на файла с класа на Java.

Роден да пътува

Файлът на класа Java е точно дефиниран формат за компилирана Java. Изходният код на Java се компилира в файлове на класа, които могат да бъдат заредени и изпълнени от всеки JVM. Файловете на класа могат да пътуват през мрежа, преди да бъдат заредени от JVM.

Всъщност, ако четете тази статия чрез браузър с възможност за Java, файловете на класа за симулационния аплет в края на статията прелитат през Интернет към вашия компютър в момента. Ако искате да ги слушате (и компютърът ви има звук), натиснете следния бутон:

За да видите този аплет, ви е необходим браузър с активиран Java

Звучи сякаш се забавляват, а? Това е в тяхната природа. Файловете от клас Java са проектирани да пътуват добре. Те са независими от платформата, така че ще бъдат добре дошли на повече места. Те съдържат байт кодове, компактният набор инструкции за JVM, така че те могат да пътуват леко. Файловете от клас Java непрекъснато се пренасят през мрежи с бясна скорост, за да достигнат до JVM по целия свят.

Какво има в файла на класа?

Файлът на класа Java съдържа всичко, което JVM трябва да знае за един клас или интерфейс на Java. В техния ред на появяване във файла на класа основните компоненти са: магия, версия, постоянен пул, флагове за достъп, този клас, супер клас, интерфейси, полета, методи и атрибути.

Информацията, съхранявана във файла на класа, често се различава по дължина - тоест действителната дължина на информацията не може да бъде прогнозирана преди зареждането на файла на класа. Например броят на методите, изброени в компонента методи, може да се различава между файловете на класа, тъй като зависи от броя на методите, дефинирани в изходния код. Такава информация се организира във файла на класа чрез предварително представяне на действителната информация по нейния размер или дължина. По този начин, когато класът се зарежда от JVM, първо се чете размерът на информацията с променлива дължина. След като JVM знае размера, той може правилно да прочете действителната информация.

Обикновено информацията се записва във файла на класа, без интервал или запълване между последователни части от информация; всичко е подравнено по граници на байта. Това помага да се запазят малките файлове на класовете, така че те да бъдат аеродинамични, докато летят през мрежи.

Редът на файловите компоненти на класа е строго дефиниран, за да могат JVM да знаят какво да очакват и къде да го очакват, когато зареждат файл с клас. Например всеки JVM знае, че първите осем байта на файл с клас съдържат магията и номерата на версиите, че константният пул започва от деветия байт и че флаговете за достъп следват постоянния пул. Но тъй като постоянният пул е с променлива дължина, той не знае точното местонахождение на флаговете за достъп, докато не приключи четенето в постоянния пул. След като приключи четенето в постоянния пул, той знае, че следващите два байта ще бъдат флаговете за достъп.

Магия и номера на версиите

Първите четири байта на всеки файл на класа винаги са 0xCAFEBABE. Това магическо число улеснява идентифицирането на файловете от клас Java, тъй като шансовете са, че некласовите файлове биха започнали със същите първоначални четири байта. Номерът се нарича магия, защото може да бъде изваден от шапка от дизайнерите на файловия формат. Единственото изискване е той да не се използва вече от друг файлов формат, който може да се срещне в реалния свят. Според Патрик Нотън, ключов член на оригиналния екип на Java, магическото число е избрано "много преди името Java някога да е било произнесено по отношение на този език. Търсихме нещо забавно, уникално и лесно за запомняне. Това е само съвпадение, че OxCAFEBABE, наклонена препратка към сладките баристи в кафето Peet's, предвещаваше името Java. "

Вторите четири байта на файла с класа съдържат главните и малките номера на версиите. Тези числа идентифицират версията на файловия формат на класа, към който се придържа определен файл на класа, и позволяват на JVM да проверят дали файлът на класа може да се зарежда. Всеки JVM има максимална версия, която може да зареди, и JVM ще отхвърлят файловете с класове с по-нови версии.

Постоянен басейн

Файлът на класа съхранява константи, свързани с неговия клас или интерфейс в константния пул. Някои константи, които могат да се видят в играта, са буквални низове, крайни стойности на променливи, имена на класове, имена на интерфейси, имена и типове променливи и имена на методи и подписи. Подписът на метода е неговият тип връщане и набор от типове аргументи.

Константният пул е организиран като масив от елементи с променлива дължина. Всяка константа заема по един елемент в масива. В целия файл на класа константите се посочват от целочисления индекс, който показва тяхната позиция в масива. Първоначалната константа има индекс едно, втората константа има индекс два и т.н. Масивът на константния пул се предшества от размера на масива, така че JVM ще знаят колко константи да очакват при зареждане на файла на класа.

Всеки елемент от пула на константи започва с еднобайтов маркер, указващ типа константа на тази позиция в масива. След като JVM грабне и интерпретира този маркер, той знае какво следва маркера. Например, ако тагът показва, че константата е низ, JVM очаква следващите два байта да бъдат дължината на низа. След тази двубайтова дължина JVM очаква да намери дължината на броя байтове, които съставляват символите на низа.

В останалата част на статията понякога ще се позовавам на n-ия елемент на масива с константни пулове като константа_пул [n]. Това има смисъл, доколкото постоянният пул е организиран като масив, но имайте предвид, че тези елементи имат различни размери и типове и че първият елемент има индекс един.

Флагове за достъп

Първите два байта след константния пул, флаговете за достъп, показват дали този файл дефинира клас или интерфейс, дали класът или интерфейсът са публични или абстрактни и (ако това е клас, а не интерфейс) дали класът е окончателен.

Този клас

Следващите два байта, компонентът на този клас , са индекс в масива с постоянен пул. Константата, посочена от този клас , константа_пул [този_клас], има две части, еднобайтов маркер и двубайтов индекс на име. Маркерът ще бъде равен на CONSTANT_Class, стойност, която показва, че този елемент съдържа информация за клас или интерфейс. Constant_pool [name_index] е низова константа, съдържаща името на класа или интерфейса.

Компонентът този клас дава представа как се използва константният пул. Самият този клас е просто индекс на константния пул. Когато JVM търси константа_пул [този_клас], той намира елемент, който се идентифицира като CONSTANT_Class със своя таг. JVM знае, че елементите CONSTANT_Class винаги имат двубайтов индекс в константния пул, наречен индекс на име, след техния еднобайтов маркер. Така че търси константа_пул [name_index], за да получи низа, съдържащ името на класа или интерфейса.

Супер клас

След този компонент на клас е компонентът на супер клас , друг двубайтов индекс в константния пул. Constant_pool [super_class] е елемент CONSTANT_Class, който сочи към името на супер класа, от който този клас произлиза.

Интерфейси

Компонентът интерфейси започва с двубайтово броене на броя интерфейси, реализирани от класа (или интерфейса), дефиниран във файла. Веднага следва масив, който съдържа един индекс в константния пул за всеки интерфейс, реализиран от класа. Всеки интерфейс е представен от елемент CONSTANT_Class в константния пул, който сочи към името на интерфейса.

Полета

Компонентът полета започва с двубайтово броене на броя полета в този клас или интерфейс. Полето е екземпляр или променлива на класа на класа или интерфейса. След броенето е масив от структури с променлива дължина, по една за всяко поле. Всяка структура разкрива информация за едно поле като името на полето, типа и, ако е крайна променлива, неговата постоянна стойност. Част от информацията се съдържа в самата структура, а друга се съдържа в постоянни места на пула, посочени от структурата.

Единствените полета, които се появяват в списъка, са тези, които са декларирани от класа или интерфейса, дефинирани във файла; в списъка не се появяват полета, наследени от супер класове или суперинтерфейси.

Методи

Компонентът методи започва с двубайтово броене на броя на методите в класа или интерфейса. Този брой включва само онези методи, които са изрично дефинирани от този клас, а не всякакви методи, които могат да бъдат наследени от суперкласове. След броят на методите са самите методи.

Структурата за всеки метод съдържа няколко части информация за метода, включително дескриптора на метода (неговия тип на връщане и списък с аргументи), броя на стековите думи, необходими за локалните променливи на метода, максималният брой стекови думи, необходими за операнда на метода стек, таблица с изключения, уловени от метода, последователността на байт кода и таблица с номера на редове.

Атрибути

Издигащите се отзад са атрибутите, които дават обща информация за конкретния клас или интерфейс, дефинирани от файла. Разделът с атрибути има двубайтов брой на атрибутите, последван от самите атрибути. Например, един атрибут е атрибутът на изходния код; разкрива името на изходния файл, от който е компилиран този файл на класа. JVM ще игнорират безшумно всички атрибути, които не разпознават.

Първо зареждане: симулация на файл от клас, достигащ своята дестинация JVM

Аплетът по-долу симулира JVM, зареждащ файл с клас. Файлът на класа, който се зарежда в симулацията, е генериран от компилатора на javac, като се има предвид следния изходен код на Java:

class Act {публична статична празнота doMathForever () {int i = 0; докато (вярно) {i + = 1; i * = 2; }}}

Горният фрагмент от код идва от статията за JVM от миналия месец. Това е същият метод doMathForever (), изпълнен от аплета EternalMath от статията от миналия месец. Избрах този код, за да дам реален пример, който не беше твърде сложен. Въпреки че кодът може да не е много полезен в реалния свят, той се компилира във файл с реален клас, който се зарежда от симулацията по-долу.

Аплетът GettingLoaded ви позволява да управлявате симулацията на натоварване на клас една стъпка наведнъж. За всяка стъпка по пътя можете да прочетете за следващата част от байтове, която е на път да бъде консумирана и интерпретирана от JVM. Просто натиснете бутона "Стъпка", за да накарате JVM да погълне следващия парче. Натискането на „Назад“ ще отмени предишната стъпка, а натискането на „Нулиране“ ще върне симулацията в първоначалното й състояние, което ви позволява да започнете отначало.

JVM е показан в долния ляв ъгъл, като консумира потока от байтове, съставляващи файла на класа Act.class. Байтовете са показани в шестнадесетичен стрийминг от сървър в долния десен ъгъл. Байтовете се придвижват отдясно наляво, между сървъра и JVM, по една порция. Част от байта, които JVM ще консумира при следващото натискане на бутона "Стъпка", са показани в червено. Тези подчертани байтове са описани в голямата текстова област над JVM. Всички останали байтове след следващото парче са показани в черно.

Опитах се да обясня напълно всяка част от байта в текстовата област. Следователно има много подробности в текстовата област и може да пожелаете да прегледате първо всички стъпки, за да получите общата идея, а след това да потърсите повече подробности.

Щастливо щракване.

За да видите този аплет, ви е необходим браузър с активиран Java.

Щракнете тук за изходния код на GettingLoaded. За да стартирате този аплет самостоятелно, ще ви трябват и двата файла, които този аплет извлича от сървъра, ASCII файлът, който съдържа текста за всяка стъпка, и самият файл Act.class. Щракнете тук за изходния код на аудио аплета Flying Class Files.

ЗАБЕЛЕЖКА: Дребният шрифт: „Начин на живот на Java Class File“ Член Авторско право (c) 1996 Bill Venners. Всички права запазени. Аплет „GettingLoaded“ Copyright (c) 1996 Artima Software Company. Всички права запазени.

: END_END ЗАБЕЛЕЖКА

Бил Венърс е президент на Artima Software Company. Чрез Artima той прави разработка на софтуер и консултации по поръчка.

Научете повече за тази тема

  • Спецификацията за виртуална машина Java, официалната дума от Sun.

    //java.sun.com/1.0alpha3/doc/vmspec/vmspec_1.html

  • Когато излезе, книгата The Java Virtual Machine Specification , //www.aw.com/cp/lindholm-yellin.html, от Тим ​​Линдхолм и Франк Йелин (ISBN 0-201-63452-X), част от Java Series, //www.aw.com/cp/javaseries.html), от Addison-Wesley, вероятно ще бъде най-добрият JVM ресурс.
  • Чернова на глава 4 от Спецификацията на виртуалната машина Java , която описва формата на файла на класа и верификатора на байт кода, може да бъде извлечена от JavaSoft.

    //java.sun.com/java.sun.com/newdocs.html

Тази история „Начинът на живот на Java класния файл“ първоначално е публикувана от JavaWorld.