JavaRush /Java-Blog /Random-DE /Primitive Typen in Java: Sie sind nicht so primitiv
Viacheslav
Level 3

Primitive Typen in Java: Sie sind nicht so primitiv

Veröffentlicht in der Gruppe Random-DE

Einführung

Unter Anwendungsentwicklung versteht man die Arbeit mit einigen Daten bzw. deren Speicherung und Verarbeitung. Heute möchte ich auf den ersten wesentlichen Aspekt eingehen. Wie werden Daten in Java gespeichert? Hier haben wir zwei mögliche Formate: Referenz- und primitive Datentypen. Sprechen wir über die Arten primitiver Typen und die Möglichkeiten, mit ihnen zu arbeiten (was auch immer man sagen mag, dies ist die Grundlage unserer Kenntnisse einer Programmiersprache). Die primitiven Java-Datentypen sind die Grundlage, auf der alles ruht. Nein, ich übertreibe überhaupt nicht. Oracle hat ein separates Tutorial zu Primitiven: Primitive Datentypen Primitive Typen in Java: Sie sind nicht so primitiv - 1 . Ein wenig Geschichte. Am Anfang war Null. Aber Null ist langweilig. Und dann erschien etwas . Warum wurde er so genannt? Der Name leitet sich von der Abkürzung „ binary digi t “ (Binärzahl) ab. Das heißt, es hat nur zwei Bedeutungen. Und da es Null war, ist es logisch, dass es jetzt entweder 0 oder 1 ist. Und das Leben hat mehr Spaß gemacht. Die Stücke begannen sich in Schwärmen zu sammeln. Und diese Herden wurden Byte (Byte) genannt . In der modernen Welt ist Byte = 2 hoch dritter Potenz, d.h. 8. Es stellt sich jedoch heraus, dass dies nicht immer der Fall war. Es gibt viele Vermutungen, Legenden und Gerüchte darüber, woher der Name Byte stammt. Einige Leute denken, dass es nur um die damaligen Kodierungen ging, während andere denken, dass es profitabler war, Informationen auf diese Weise zu lesen. Ein Byte ist der kleinste adressierbare Speicherbereich. Es sind die Bytes, die im Speicher eindeutige Adressen haben. Es gibt eine Legende, dass ByTe eine Abkürzung für Binary Term ist – ein Maschinenwort. Maschinenwort – vereinfacht ausgedrückt ist dies die Datenmenge, die der Prozessor in einem Vorgang verarbeiten kann. Zuvor entsprach die Maschinenwortgröße dem kleinsten adressierbaren Speicher. In Java können Variablen nur Bytewerte speichern. Wie ich oben sagte, gibt es in Java zwei Arten von Variablen:
  • Java-Primitivtypen speichern direkt den Wert von Datenbytes (wir werden uns die Typen dieser Primitive weiter unten genauer ansehen);
  • Ein Referenztyp speichert die Bytes der Objektadresse im Heap, d. h. über diese Variablen erhalten wir direkten Zugriff auf das Objekt selbst (eine Art Fernbedienung für das Objekt).

Java-Byte

Der Verlauf hat uns also ein Byte gegeben – die minimale Speichermenge, die wir verwenden können. Und es besteht aus 8 Bits. Der kleinste ganzzahlige Datentyp in Java ist Byte. Dies ist ein vorzeichenbehafteter 8-Bit-Typ. Was bedeutet das? Lass uns zählen. 2^8 ist 256. Aber was ist, wenn wir eine negative Zahl wollen? Und die Java-Entwickler entschieden, dass der Binärcode „10000000“ -128 darstellen würde, d. h. das höchstwertige Bit (das Bit ganz links) würde anzeigen, ob die Zahl negativ ist. Binär „0111 1111“ entspricht 127. Das heißt, 128 kann in keiner Weise bezeichnet werden, weil es wird -128 sein. Die vollständige Berechnung finden Sie in dieser Antwort: Warum beträgt der Bytebereich in Java -128 bis 127? Um zu verstehen, wie die Zahlen ermittelt werden, sollten Sie sich das Bild ansehen:
Primitive Typen in Java: Sie sind nicht so primitiv - 2
Dementsprechend beträgt die Berechnung der Größe 2^(8-1) = 128. Dies bedeutet, dass die Mindestgrenze (und sie hat ein Minus) bei -128 liegt. Und das Maximum ist 128 – 1 (Null subtrahieren). Das heißt, das Maximum liegt bei 127. Tatsächlich arbeiten wir nicht so oft mit dem Byte-Typ auf „hohem Niveau“. Im Grunde handelt es sich hierbei um die Verarbeitung von „Rohdaten“. Wenn Sie beispielsweise mit der Datenübertragung über ein Netzwerk arbeiten, handelt es sich bei den Daten um eine Reihe von Nullen und Einsen, die über einen Kommunikationskanal übertragen werden. Oder beim Lesen von Daten aus Dateien. Sie können auch beim Arbeiten mit Zeichenfolgen und Kodierungen verwendet werden. Beispielcode:
public static void main(String []args){
        byte value = 2;
        byte shortByteValue = 0b10; // 2
        System.out.println(shortByteValue);
        // Начиная с JDK7 мы можем разделять литералы подчёркиваниями
        byte minByteValue = (byte) 0B1000_0000; // -128
        byte maxByteValue = (byte) 0b0111_1111; // 127
        byte minusByteValue = (byte) 0b1111_1111; // -128 + 127
        System.out.println(minusByteValue);
        System.out.println(minByteValue + " to " + maxByteValue);
}
Denken Sie übrigens nicht, dass die Verwendung des Byte-Typs den Speicherverbrauch verringert. Byte wird hauptsächlich verwendet, um den Speicherverbrauch beim Speichern von Daten in Arrays zu reduzieren (z. B. Speichern von über das Netzwerk empfangenen Daten in einem Puffer, der als Byte-Array implementiert wird). Bei der Durchführung von Datenoperationen wird die Verwendung von Bytes jedoch nicht Ihren Erwartungen entsprechen. Dies ist auf die Implementierung der Java Virtual Machine (JVM) zurückzuführen. Da die meisten Systeme 32- oder 64-Bit sind, werden Byte und Short während der Berechnung in ein 32-Bit-Int konvertiert, worüber wir später sprechen werden. Dies erleichtert die Berechnung. Weitere Einzelheiten finden Sie unter Wird das Hinzufügen von Byte aufgrund von Java-Sprachregeln oder aufgrund von JVM in int konvertiert? . Die Antwort enthält auch Links zu JLS (Java Language Specification). Darüber hinaus kann die Verwendung von Byte an der falschen Stelle zu unangenehmen Momenten führen:
public static void main(String []args){
        for (byte i = 1; i <= 200; i++) {
            System.out.println(i);
        }
}
Hier wird es eine Schleife geben. Da der Zählerwert das Maximum (127) erreicht, kommt es zu einem Überlauf und der Wert wird auf -128 gesetzt. Und wir werden nie aus diesem Kreislauf herauskommen.

kurz

Die Grenze für Bytewerte ist recht gering. Deshalb haben wir uns für den nächsten Datentyp entschieden, die Anzahl der Bits zu verdoppeln. Das heißt, jetzt sind es nicht 8 Bit, sondern 16, also 2 Byte. Die Werte können auf die gleiche Weise berechnet werden. 2^(16-1) = 2^15 = 32768. Dies bedeutet, dass der Bereich von -32768 bis 32767 reicht. Es wird sehr selten für Sonderfälle verwendet. In der Java-Sprachdokumentation heißt es: „ Sie können einen Short verwenden, um in großen Arrays Speicher zu sparen .“

int

Damit sind wir beim am häufigsten verwendeten Typ angelangt. Es nimmt 32 Bit oder 4 Bytes ein. Generell verdoppeln wir weiter. Der Wertebereich reicht von -2^31 bis 2^31 – 1.

Maximaler int-Wert

Der Maximalwert von int 2147483648 beträgt 1, was überhaupt nicht klein ist. Wie oben erwähnt, um Berechnungen zu optimieren, weil Für moderne Computer ist es unter Berücksichtigung ihrer Bitkapazität bequemer zu zählen; Daten können implizit in int konvertiert werden. Hier ist ein einfaches Beispiel:
byte a = 1;
byte b = 2;
byte result = a + b;
Solch harmloser Code, aber wir erhalten die Fehlermeldung: „Fehler: inkompatible Typen: mögliche verlustbehaftete Konvertierung von int in byte.“ Sie müssen es wie folgt korrigieren: byte result = (byte)(a + b); Und noch ein harmloses Beispiel. Was passiert, wenn wir den folgenden Code ausführen?
int value = 4;
System.out.println(8/value);
System.out.println(9/value);
System.out.println(10/value);
System.out.println(11/value);
Und wir werden die Schlussfolgerung ziehen
2
2
2
2
*Geräusche der Panik*
Tatsache ist, dass bei der Arbeit mit int-Werten der Rest verworfen wird und nur der ganze Teil übrig bleibt (in solchen Fällen ist es besser, double zu verwenden).

lang

Wir verdoppeln weiter. Wir multiplizieren 32 mit 2 und erhalten 64 Bit. Traditionell sind dies 4 * 2, also 8 Bytes. Der Wertebereich reicht von -2^63 bis 2^63 – 1. Mehr als genug. Mit diesem Typ können Sie große, große Zahlen zählen. Wird oft bei der Arbeit mit der Zeit verwendet. Oder zum Beispiel über weite Strecken. Um anzuzeigen, dass eine Zahl lang ist, platzieren Sie nach der Zahl das Literal „L – Long“. Beispiel:
long longValue = 4;
longValue = 1l; // Не ошибка, но плохо читается
longValue = 2L; // Идеально
Ich möchte über mich hinauswachsen. Als nächstes betrachten wir die Tatsache, dass es entsprechende Wrapper für Primitiven gibt, die es ermöglichen, mit Primitiven als Objekten zu arbeiten. Aber es gibt eine interessante Funktion. Hier ist ein Beispiel: Mit demselben Tutorialspoint-Online-Compiler können Sie den folgenden Code überprüfen:
public class HelloWorld {

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

    public static void printLong(long longValue) {
        System.out.println(longValue);
    }
}
Dieser Code funktioniert fehlerfrei, alles ist in Ordnung. Aber sobald der Typ in der printLong-Methode von long auf Long ersetzt wird (d. h. der Typ wird nicht primitiv, sondern zum Objekt), wird es für Java unklar, welchen Parameter wir übergeben. Es wird davon ausgegangen, dass ein int übertragen wird und ein Fehler auftritt. Daher muss im Fall einer Methode explizit 4L angegeben werden. Bei der Arbeit mit Datenbanken wird long häufig als ID verwendet.

Java Float und Java Double

Diese Typen werden Gleitkommatypen genannt. Das heißt, es handelt sich nicht um Ganzzahltypen. Der Float-Typ ist 32 Bit (wie int), und double wird als Typ mit doppelter Genauigkeit bezeichnet, also 64 Bit (multipliziert mit 2, genau wie wir es mögen). Beispiel:
public static void main(String []args){
        // float floatValue = 2.3; lossy conversion from double to float
        float floatValue = 2.3F;
        floatValue = 2.3f;
        double doubleValue = 2.3;
        System.out.println(floatValue);
        double cinema = 7D;
}
Und hier ist ein Beispiel für den Werteunterschied (aufgrund der Typgenauigkeit):
public static void main(String []args){
        float piValue = (float)Math.PI;
        double piValueExt = Math.PI;
        System.out.println("Float value: " + piValue );
        System.out.println("Double value: " + piValueExt );
 }
Diese primitiven Typen werden beispielsweise in der Mathematik verwendet. Hier ist der Beweis, eine Konstante zur Berechnung der Zahl PI . Nun, im Allgemeinen können Sie sich die API der Math-Klasse ansehen. Folgendes sollte sonst noch wichtig und interessant sein: Selbst in der Dokumentation heißt es: „ Dieser Datentyp sollte niemals für präzise Werte wie Währungen verwendet werden.“ Dazu müssen Sie stattdessen die Klasse java.math.BigDecimal verwenden. Numbers and Strings deckt BigDecimal und andere nützliche Klassen ab, die von der Java-Plattform bereitgestellt werden. " Das heißt, Geld in Float und Double muss nicht berechnet werden. Ein Beispiel zur Genauigkeit am Beispiel der Arbeit bei der NASA: Java BigDecimal, Umgang mit hochpräzisen Berechnungen. Nun, um es selbst zu spüren:
public static void main(String []args){
        float amount = 1.0000005F;
        float avalue = 0.0000004F;
        float result = amount - avalue;
        System.out.println(result);
}
Folgen Sie diesem Beispiel und fügen Sie dann 0 vor den Zahlen 5 und 4 hinzu. Und Sie werden den ganzen Horror sehen) Es gibt einen interessanten Bericht auf Russisch über Float und Double zum Thema: https://youtu.be/1RCn5ruN1fk Arbeitsbeispiele mit BigDecimal ist hier zu sehen: Mit BigDecimal Cent machen . Float und Double können übrigens mehr als nur eine Zahl zurückgeben. Das folgende Beispiel gibt beispielsweise Infinity zurück:
public static void main(String []args){
        double positive_infinity = 12.0 / 0;
        System.out.println(positive_infinity);
}
Und dieser wird NAN zurückgeben:
public static void main(String []args){
        double positive_infinity = 12.0 / 0;
        double negative_infinity = -15.0 / 0;
        System.out.println(positive_infinity + negative_infinity);
}
Es ist klar, dass es unendlich ist. Was ist NaN? Dies ist keine Zahl , was bedeutet, dass das Ergebnis nicht berechnet werden kann und keine Zahl ist. Hier ein Beispiel: Wir wollen die Quadratwurzel von -4 berechnen. Die Quadratwurzel aus 4 ist 2. Das heißt, 2 muss quadriert werden und dann erhalten wir 4. Was muss quadriert werden, um -4 zu erhalten? Es wird nicht funktionieren, weil... wenn es eine positive Zahl gibt, dann bleibt sie bestehen. Und wenn es negativ war, dann ergibt Minus für Minus ein Plus. Das heißt, es ist nicht berechenbar.
public static void main(String []args){
        double sqrt = Math.sqrt(-4);
        System.out.println(sqrt + 1);
        if (Double.isNaN(sqrt)) {
           System.out.println("So sad");
        }
        System.out.println(Double.NaN == sqrt);
}
Hier noch ein toller Überblick zum Thema Gleitkommazahlen: Wo ist Ihr Standpunkt?
Was gibt es sonst noch zu lesen:

Java-Boolescher Wert

Der nächste Typ ist Boolean (logischer Typ). Es kann nur die Werte wahr oder falsch akzeptieren, bei denen es sich um Schlüsselwörter handelt. Wird in logischen Operationen wie While-Schleifen und bei Verzweigungen mit if, switch verwendet. Was können Sie hier Interessantes erfahren? Nun, theoretisch benötigen wir beispielsweise nur 1 Bit Information, 0 oder 1, also wahr oder falsch. Aber in Wirklichkeit wird Boolean mehr Speicher beanspruchen und dies hängt von der spezifischen JVM-Implementierung ab. Normalerweise kostet dies genauso viel wie int. Eine andere Möglichkeit ist die Verwendung von BitSet. Hier ist eine kurze Beschreibung aus dem Buch „Java Fundamentals“: BitSet

Java-Zeichen

Jetzt sind wir beim letzten primitiven Typ angekommen. Die Daten in char nehmen also 16 Bit ein und beschreiben das Zeichen. Java verwendet Unicode-Codierung für char. Das Symbol kann gemäß zwei Tabellen eingestellt werden (Sie können es hier sehen ):
  • Unicode-Zeichentabelle
  • ASCII-Zeichentabelle
Primitive Typen in Java: Sie sind nicht so primitiv - 3
Beispiel im Studio:
public static void main(String[] args) {
    char symbol = '\u0066'; // Unicode
    symbol = 102; // ASCII
    System.out.println(symbol);
}
Übrigens unterstützt char, da es im Wesentlichen eine Zahl ist, mathematische Operationen wie sum. Und manchmal kann das zu lustigen Konsequenzen führen:
public class HelloWorld{

    public static void main(String []args){
        String costForPrint = "5$";
        System.out.println("Цена только для вас " +
        + costForPrint.charAt(0) + getCurrencyName(costForPrint.charAt(1)));
    }

    public static String getCurrencyName(char symbol) {
        if (symbol == '$') {
            return " долларов";
        } else {
            throw new UnsupportedOperationException("Not implemented yet");
        }
    }

}
Ich empfehle dringend, sich die Online -IDE von Tutorialspoint anzusehen . Als ich dieses Rätsel auf einer der Konferenzen sah, hob es meine Stimmung. Ich hoffe, euch gefällt das Beispiel auch) AKTUALISIERT: Das war bei Joker 2017, Bericht: „ Java Puzzlers NG S03 – Wo kommt ihr alle her?!

Literale

Ein Literal ist ein explizit angegebener Wert. Mithilfe von Literalen können Sie Werte in verschiedenen Zahlensystemen angeben:
  • Dezimalsystem: 10
  • Hexadezimal: 0x1F4, beginnt mit 0x
  • Oktalsystem: 010, beginnt bei Null.
  • Binärsystem (seit Java7): 0b101, beginnt bei 0b
Ich würde etwas mehr auf das Oktalsystem eingehen, weil es lustig ist:
int costInDollars = 08;
Diese Codezeile lässt sich nicht kompilieren:
error: integer number too large: 08
Es scheint Unsinn zu sein. Erinnern wir uns nun an das Binär- und Oktalsystem. Es gibt keine Zweien im Binärsystem, weil Es gibt zwei Werte (beginnend bei 0). Und das Oktalsystem hat 8 Werte, beginnend bei Null. Das heißt, der Wert 8 selbst existiert nicht. Es handelt sich also um einen Fehler, der auf den ersten Blick absurd erscheint. Und zur Erinnerung: Hier ist die „Folgeregel“ für die Übersetzung von Werten:
Primitive Typen in Java: Sie sind nicht so primitiv - 4

Wrapper-Klassen

Primitive in Java verfügen über eigene Wrapper-Klassen, sodass Sie mit ihnen als Objekte arbeiten können. Das heißt, für jeden primitiven Typ gibt es einen entsprechenden Referenztyp. Primitive Typen in Java: Sie sind nicht so primitiv - 5Wrapper-Klassen sind unveränderlich: Das bedeutet, dass nach der Erstellung eines Objekts sein Zustand – der Wert des Wertfelds – nicht mehr geändert werden kann. Wrapper-Klassen werden als finale Objekte deklariert, sozusagen schreibgeschützt. Ich möchte auch erwähnen, dass es nicht möglich ist, von diesen Klassen zu erben. Java führt automatisch Konvertierungen zwischen primitiven Typen und ihren Wrappern durch:
Integer x = 9;          // autoboxing
int n = new Integer(3); // unboxing
Der Vorgang des Konvertierens primitiver Typen in Referenztypen (int->Integer) wird als Autoboxing bezeichnet , und der umgekehrte Vorgang wird als Unboxing bezeichnet . Diese Klassen ermöglichen es, ein Grundelement in einem Objekt zu speichern, und das Objekt selbst verhält sich wie ein Objekt (naja, wie jedes andere Objekt). Mit all dem erhalten wir eine große Anzahl vielfältiger, nützlicher statischer Methoden, wie z. B. das Vergleichen von Zahlen, das Umwandeln eines Symbols in Groß- und Kleinschreibung, das Bestimmen, ob ein Symbol ein Buchstabe oder eine Zahl ist, die Suche nach der Mindestzahl usw. Der bereitgestellte Funktionsumfang hängt nur vom Wrapper selbst ab. Ein Beispiel für Ihre eigene Implementierung eines Wrappers für int:
public class CustomerInt {

   private final int value;

   public CustomerInt(int value) {
       this.value = value;
   }

   public int getValue() {
       return value;
   }
}
Das Hauptpaket, java.lang, enthält bereits Implementierungen der Klassen Boolean, Byte, Short, Character, Integer, Float, Long, Double, und wir müssen nichts Eigenes erstellen, sondern einfach das Vorgefertigte wiederverwenden Einsen. Solche Klassen geben uns beispielsweise die Möglichkeit, beispielsweise eine Liste zu erstellen , da eine Liste nur Objekte enthalten sollte, was bei Grundelementen nicht der Fall ist. Um einen Wert eines primitiven Typs zu konvertieren, gibt es statische valueOf-Methoden. Beispielsweise gibt Integer.valueOf(4) ein Objekt vom Typ Integer zurück. Für die umgekehrte Konvertierung gibt es die Methoden intValue(), longValue() usw. Der Compiler fügt Aufrufe an valueOf und *Value selbst ein, das ist die Essenz von Autoboxing und Autounboxing. Wie das oben dargestellte Beispiel für Autopacking und Autounpacking tatsächlich aussieht:
Integer x = Integer.valueOf(9);
int n = new Integer(3).intValue();
Weitere Informationen zum automatischen Packen und Entpacken finden Sie in diesem Artikel .

Gießen

При работе с примитивами существует такое понятие Wie приведение типов, одно из не очень приятных свойств C++, тем не менее приведение типов сохранено и в языке Java. Иногда мы сталкиваемся с такими ситуациями, когда нам нужно совершать взаимодействия с данными разных типов. И очень хорошо, что в некоторых ситуациях это возможно. В случае с ссылочными переменными, там свои особенности, связанные с полиморфизмом и наследованием, но сегодня мы рассматриваем простые типы и соответственно приведение простых типов. Существует преобразование с расширением и преобразование сужающее. Всё на самом деле просто. Если тип данных становится больше (допустим, был int, а стал long), то тип становится шире (из 32 бит становится 64). И в этом случае мы не рискуем потерять данные, т.к. если влезло в int, то в long влезет тем более, поэтому данное приведение мы не замечаем, так Wie оно осуществляется автоматически. А вот в обратную сторону преобразование требует явного указания от нас, данное приведение типа называется — сужение. Так сказать, чтобы мы сами сказали: «Да, я даю себе отчёт в этом. В случае чего — виноват сам».
public static void main(String []args){
   int intValue = 128;
   byte value = (byte)intValue;
   System.out.println(value);
}
Wasбы потом в таком случае не говорoder что «Ваша Джава плохая», когда получат внезапно -128 anstatt 128 ) Мы ведь помним, что в Byteе 127 верхнее Bedeutung и всё что находилось выше него соответственно можно потерять. Когда мы явно превратoder наш int в Byte, то произошло переполнение и Bedeutung стало -128.

Область видимости

Это то место в Codeе, где данная переменная будет выполнять свои функции и хранить в себе Wieое-то Bedeutung. Когда же эта область закончится, переменная перестанет существовать и будет стерта из памяти и. Wie уже можно догадаться, посмотреть oder получить ее Bedeutung будет невозможно! Так что же это такое — область видимости? Primitive Typen in Java: Sie sind nicht so primitiv - 6Область определяется "блоком" — вообще всякой областью, замкнутой в фигурные скобки, выход за которые сулит удаление данных объявленных в ней. Или Wie минимум — сокрытие их от других блоков, открытых вне текущего. В Java область видимости определяется двумя основными способами:
  • Классом.
  • Методом.
Как я и сказал, переменная не видна Codeу, если она определена за пределами блока, в котором она была инициализирована. Смотрим пример:
int x;
x = 6;
if (x >= 4) {
   int y = 3;
}
x = y;// переменная y здесь не видна!
И Wie итог мы получим ошибку:

Error:(10, 21) java: cannot find symbol
  symbol:   variable y
  location: class com.javaRush.test.type.Main
Области видимости могут быть вложенными (если мы объявoder переменную в первом, внешнем блоке, то во внутреннем она будет видна).

Заключение

Сегодня мы познакомoderсь с восемью примитивными типами в Java. Эти типы можно разделить на четыре группы:
  • Целые числа: byte, short, int, long — представляют собой целые числа со знаком.
  • Числа с плавающей точкой — эта группа включает себе float и double — типы, которые хранят числа с точностью до определённого знака после запятой.
  • Булевы значения — boolean — хранят значения типа "истина/ложь".
  • Zeichen – diese Gruppe umfasst den Typ char.
Wie der obige Text zeigt, sind die Grundelemente in Java nicht so primitiv und ermöglichen es Ihnen, viele Probleme effektiv zu lösen. Damit werden aber auch einige Funktionen eingeführt, die wir berücksichtigen sollten, wenn wir in unserem Programm nicht auf unvorhersehbares Verhalten stoßen möchten. Wie heißt es so schön: Man muss für alles bezahlen. Wenn wir ein Grundelement mit einem „steilen“ (breiten) Bereich wünschen – etwa lang – opfern wir die Zuweisung eines größeren Speicherabschnitts und gehen in die entgegengesetzte Richtung. Durch die Einsparung von Speicher und die Verwendung von Bytes erhalten wir einen begrenzten Bereich von -128 bis 127.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION