Как да съхранявате данни в Java обекти

Последна актуализация: януари 2020 г.

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

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

Променливи и примитивни типове

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

/ * * Това също е коментар. Компилаторът игнорира всичко от * първата / * до "наклонена черта", която завършва коментара. * * Ето „звездната наклонена черта“, която завършва коментара. * / public class IntegerTest {public static void main (String [] args) {// Ето декларацията на int променлива, наречена anInteger, // която давате начална стойност 100. int anInteger = 100; // Деклариране и инициализиране на anInteger System.out.println (anInteger); // Изходи 100 // Можете също така да правите аритметика с примитивни типове, като използвате // стандартните аритметични оператори. anInteger = 100 + 100; System.out.println (anInteger); // Изходи 200}}

Java също използва типове с плаваща запетая, които могат да съдържат реални числа, което означава числа, които включват десетичен знак. Ето примерна програма:

публичен клас DoubleTest {public static void main (String [] args) {// Ето декларацията на двойна променлива, наречена aDouble. // Вие също така давате aDouble начална стойност от 5.76. удвоен aDouble = 5,76; // Деклариране и инициализиране на aDouble System.out.println (aDouble); // Изходи 5.76 // Можете също да правите аритметика с типове с плаваща запетая. aDouble = 5,76 + 1,45; System.out.println (aDouble); // Изходи 7.21}}

Опитайте да стартирате програмите по-горе. Не забравяйте, че трябва да компилирате, преди да можете да ги стартирате:

javac * .java java IntegerTest java DoubleTest 

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

Интегрални типове

ТИП Байт Къс Международна Дълго
РАЗМЕР (бита) 8 16. 32 64
ОБХВАТ -128 до 127 -32,768 до 32,767 -2,147,483,648 до 2,147,483,647 -263 до 263-1

Типове с плаваща запетая (формат IEEE 754)

 
ТИП Плаваща запетая с една прецизност Плаваща точка с двойна прецизност
РАЗМЕР (бита) 32 64
ОБХВАТ +/- 1,18x10-38 до +/- 3,4x1038 +/- 2.23x10-308 до +/- 1.8x10308

А тип низ държи струни, и ги третира различно от начина, интеграл и плаващи видове точкови справят номера. Езикът Java включва Stringклас за представяне на низове. Декларирате низ, използвайки типа String, и го инициализирате с цитиран низ, последователност от символи, съдържащи се в двойни кавички, както е показано по-долу. Можете също да комбинирате два низа с помощта на +оператора.

// Кодов фрагмент // Декларация на променлива s от тип String, // и инициализация с цитиран низ "Здравейте." Низ s = "Здравей"; // Конкатенация на низ в s с цитиран низ "World" String t = s + "World"; System.out.println (t); // Изходи Hello World

Променлив обхват

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

Досега съм обсъждал локални променливи , които съдържат временни данни, които използвате в даден метод. Декларирате локални променливи вътре в методите и можете да получите достъп до тях само от тези методи. Това означава, че можете да извлечете само локални променливи anInteger, които сте използвали IntegerTestи aDouble, които сте използвали DoubleTest, от основния метод, в който са декларирани и никъде другаде.

Можете да декларирате локални променливи във всеки метод. Примерният код по-долу декларира локална променлива в AlarmClock snooze()метода:

публичен клас AlarmClock {public void snooze () {// Време за отлагане в милисекунди = 5 секунди дълго snoozeInterval = 5000; System.out.println ("ZZZZZ за:" + snoozeInterval); }}

Можете да стигнете snoozeIntervalсамо до snooze()метода, който е мястото, където сте деклариралиsnoozeInterval, as shown here: 

публичен клас AlarmClockTest {public static void main (String [] args) {AlarmClock aClock = new AlarmClock (); aClock.snooze (); // Това все още е добре. // Следващият ред код е ГРЕШКА . // Нямате достъп до snoozeInterval извън метода snooze. snoozeInterval = 10000; }}

Параметри на метода

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

публичен клас AlarmClock {public void snooze (long snoozeInterval) {System.out.println ("ZZZZZ за:" + snoozeInterval); }}
публичен клас AlarmClockTest {public static void main (String [] args) {AlarmClock aClock = new AlarmClock (); // Преминете в интервала за отлагане, когато извикате метода. aClock.snooze (10000); // Отлагане за 10000 msecs. }}

Член променливи: Как обектите съхраняват данни

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

Членските променливи - от които има две, екземпляр и статични - съставляват част от клас.

Променлив обхват и живот

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

Instances are the actual objects that you create from the blueprint you design in the class definition. You declare instance variables in the class definition, affecting each instance you create from the blueprint. Each instance contains those instance variables, and data held within the variables can vary from instance to instance.

Consider the AlarmClock class. Passing the snoozeInterval into the snooze() method isn't a great design. Imagine having to type in a snooze interval on your alarm clock each time you fumbled for the snooze button. Instead, just give the whole alarm clock a snoozeInterval. You complete this with an instance variable in the AlarmClock class, as shown below:

public class AlarmClock { // You declare snoozeInterval here. This makes it an instance variable. // You also initialize it here. long m_snoozeInterval = 5000; // Snooze time in millisecond = 5 secs. public void snooze() { // You can still get to m_snoozeInterval in an AlarmClock method // because you are within the scope of the class. System.out.println("ZZZZZ for: " + m_snoozeInterval); } } 

You can access instance variables almost anywhere within the class that declares them. To be technical about it, you declare the instance variable within the class scope, and you can retrieve it from almost anywhere within that scope. Practically speaking, you can access the variable anywhere between the first curly bracket that starts the class and the closing bracket. Since you also declare methods within the class scope, they too can access the instance variables.

You can also access instance variables from outside the class, as long as an instance exists, and you have a variable that references the instance. To retrieve an instance variable through an instance, you use the dot operator together with the instance. That may not be the ideal way to access the variable, but for now, complete it this way for illustrative purposes:

public class AlarmClockTest { public static void main(String[] args) { // Create two clocks. Each has its own m_snoozeInterval AlarmClock aClock1 = new AlarmClock(); AlarmClock aClock2 = new AlarmClock(); // Change aClock2 // You'll soon see that there are much better ways to do this. aClock2.m_snoozeInterval = 10000; aClock1.snooze(); // Snooze with aClock1's interval aClock2.snooze(); // Snooze with aClock2's interval } } 

Изпробвайте тази програма и ще видите, че aClock1все още има интервал от 5000, докато aClock2има интервал от 10 000. Отново, всеки екземпляр има свои собствени данни за екземпляра.

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

JavaWorld

Капсулиране

Encapsulation is one of the foundations of object-oriented programming. When using encapsulation, the user interacts with the type through the exposed behavior, not directly with the internal implementation. Through encapsulation, you hide the details of a type's implementation. In Java, encapsulation basically translates to this simple guideline: "Don't access your object's data directly; use its methods."

That is an elementary idea, but it eases our lives as programmers. Imagine, for example, that you wanted to instruct a Person object to stand up. Without encapsulation, your commands could go something like this: "Well, I guess you'd need to tighten this muscle here at the front of the leg, loosen this muscle here at the back of the leg. Hmmm -- need to bend at the waist too. Which muscles spark that movement? Need to tighten these, loosen those. Whoops! Forgot the other leg. Darn. Watch it -- don't tip over ..." You get the idea. With encapsulation, you would just need to invoke the standUp() method. Pretty easy, yes?

Some advantages to encapsulation:

  • Abstraction of detail: The user interacts with a type at a higher level. If you use the standUp() method, you no longer need to know all the muscles required to initiate that motion.
  • Isolation from changes: Changes in internal implementation don't affect the users. If a person sprains an ankle, and depends on a cane for a while, the users still invoke only the standUp() method.
  • Correctness: Users can't arbitrarily change the insides of an object. They can only complete what you allow them to do in the methods you write.

Here's a short example in which encapsulation clearly helps in a program's accuracy:

// Bad -- doesn't use encapsulation public class Person { int m_age; } public class PersonTest { public static void main(String[] args) { Person p = new Person(); p.m_age = -5; // Hey -- how can someone be minus 5 years old? } } // Better - uses encapsulation public class Person { int m_age; public void setAge(int age) { // Check to make sure age is greater than 0. I'll talk more about // if statements at another time. if (age > 0) { m_age = age; } } } public class PersonTest { public static void main(String[] args) { Person p = new Person(); p.setAge(-5); // Won't have any effect now. } } 

Дори тази проста програма показва как можете да се измъкнете в беда, ако имате директен достъп до вътрешните данни на класовете. Колкото по-голяма и по-сложна е програмата, толкова по-важно е капсулирането. Също така не забравяйте, че много програми започват от малки и след това растат, за да продължат безкрайно, така че е от съществено значение да ги проектирате правилно, от самото начало. За да приложите капсулиране AlarmClock, можете просто да създадете методи за манипулиране на интервала на отлагане.

Бележка за методите

Методите могат да върнат стойности, които повикващият използва. За да върнете стойност, декларирайте неизбежен тип на връщане и използвайте returnизраз. В getSnoozeInterval()метода, показан в примера по-долу илюстрира това.

Напишете програмата