variables en Java tipos primitivos String final casting heap stack

Variables en Java — tipos primitivos, String, final y casting desde cero

Las variables en Java son el primer punto donde la diferencia con Python se hace realmente evidente. En Python una variable era simplemente un nombre que apuntaba a un valor, sin declarar nada, sin especificar tipos, sin límites de tamaño. En Java cada variable tiene un tipo fijo que se declara antes de usarla y que no puede cambiar nunca.

En este artículo vemos por qué es así, qué tipos existen, cómo convertir entre ellos y una de las trampas más clásicas de Java: la diferencia entre == y .equals().

Por qué en Java hay que declarar el tipo de cada variable

En Python las variables son dinámicas — pueden guardar cualquier tipo de dato y cambiar de tipo en cualquier momento:

# Python — sin tipos declarados
x = 5          # x es un int
x = "hola"     # ahora x es un String
x = 3.14       # ahora x es un float

Java es un lenguaje de tipado estático, el tipo de cada variable se fija en el momento de declararla y no puede cambiar nunca:

// Java — tipo declarado obligatorio
int x = 5;
x = "hola";   // error de compilación — x es int, no String
x = 3.14;     // error de compilación — x es int, no double

La razón es que Java es un lenguaje compilado. El compilador de Java necesita saber el tipo de cada variable antes de ejecutar el programa para verificar que todas las operaciones tienen sentido, que no estás sumando un texto con un número, que no estás llamando a un método que no existe en ese tipo, etc. Si hay un error de tipos, el compilador lo detecta antes de que ejecutes el programa, no en tiempo de ejecución como en Python.

La ventaja real es que los errores de tipo se detectan mucho antes y el código es más predecible. La desventaja es que hay que escribir más.

Cómo se declaran las variables en Java

La sintaxis es siempre: tipo nombre = valor;

tipo nombre = valor;
# Python — sin tipo
nombre = "Sergio"
edad = 22
nota = 7.5
aprobado = True
// Java — con tipo
String nombre = "Sergio";
int edad = 22;
double nota = 7.5;
boolean aprobado = true;

También puedes declarar sin inicializar, pero antes de usar la variable tienes que darle un valor, o el compilador da error:

int edad;          // declarada sin valor
edad = 22;         // ahora tiene valor
System.out.println(edad);    // correcto

int altura;
System.out.println(altura);  // error: variable might not have been initialized

Los tipos primitivos — qué son y por qué existen

En Java hay dos categorías de tipos: primitivos y objetos. Es una distinción fundamental que no existe en Python.

Los tipos primitivos son los tipos más básicos, guardan directamente el valor en memoria, sin ninguna envoltura. Son ocho:

byte     → entero muy pequeño         (8 bits)
short    → entero pequeño             (16 bits)
int      → entero estándar            (32 bits)  ← el más usado
long     → entero grande              (64 bits)
float    → decimal de precisión simple (32 bits)
double   → decimal de doble precisión  (64 bits)  ← el más usado
boolean  → verdadero o falso           (1 bit lógico)
char     → un carácter                 (16 bits)

En Python cuando escribías x = 5, Python creaba un objeto Integer completo con métodos y todo. En Java cuando escribes int x = 5, Java guarda solo el número 5 en bruto, nada más. Por eso los primitivos son más rápidos y ocupan menos memoria.

Los tipos enteros — byte, short, int y long

Los cuatro tipos enteros difieren solo en el tamaño, cuántos bits usan y por tanto qué rango de valores pueden guardar:

byte   → -128 a 127                        (8 bits)
short  → -32.768 a 32.767                  (16 bits)
int    → -2.147.483.648 a 2.147.483.647    (32 bits)
long   → -9.223.372.036.854.775.808
         a 9.223.372.036.854.775.807       (64 bits)
byte b = 100;
short s = 30000;
int i = 1000000;
long l = 9000000000L;    // L al final — indica que es long

¿Cuándo usar cada uno?

La regla práctica para FP2 es muy simple: usa int para casi todo. Es el tipo entero por defecto en Java y cubre todos los números que vas a usar en ejercicios académicos.

Usa long cuando el número puede superar los 2.000 millones, como IDs de usuarios en aplicaciones reales, o cálculos astronómicos. El sufijo L al final del literal es obligatorio para que Java sepa que es un long y no un int que se ha desbordado.

byte y short se usan cuando necesitas ahorrar memoria con arrays enormes, situaciones que no vas a ver en FP2.

byte y char — la conexión con ASCII

byte y char tienen una relación especial con los códigos de caracteres.

Un byte puede guardar valores de -128 a 127, o de 0 a 255 si lo tratas como sin signo. Esto no es casualidad: la tabla ASCII estándar tiene 128 caracteres (0-127) y la tabla ASCII extendida llega a 255. Cada carácter de texto tiene un número en esa tabla:

'A' → 65
'a' → 97
'0' → 48
' ' → 32
'\n' → 10  (salto de línea)

Un char en Java guarda un único carácter Unicode codificado en 16 bits (valores 0-65535). Los primeros 128 valores coinciden exactamente con ASCII:

char letra = 'A';              // el carácter A
char letra2 = 65;              // también el carácter A (código ASCII 65)
int codigo = 'A';              // 65 — el código numérico de A

System.out.println(letra);     // → A
System.out.println(codigo);    // → 65
System.out.println((char)65);  // → A
System.out.println((int)'Z');  // → 90

Fíjate en la diferencia de comillas: los chars usan comillas simples 'A', los Strings usan comillas dobles "A". Esta distinción en Java es estricta, 'A' es un char, "A" es un String de un carácter. En Python no había distinción entre comillas simples y dobles.

char c = 'A';      // correcto — comillas simples
char c = "A";      // error — "A" es String, no char
String s = "A";    // correcto — comillas dobles
String s = 'A';    // error — 'A' es char, no String

Puedes hacer aritmética con chars porque internamente son números:

char letra = 'A';
System.out.println((char)(letra + 1));    // → B (A es 65, B es 66)
System.out.println((char)(letra + 25));   // → Z (A + 25 = 90 = Z)

// Recorrer el alfabeto
for (char c = 'a'; c <= 'z'; c++) {
    System.out.print(c + " ");
}
// → a b c d e f g h i j k l m n o p q r s t u v w x y z

Los tipos decimales — float y double

float  → precisión de ~7 dígitos decimales   (32 bits)
double → precisión de ~15 dígitos decimales  (64 bits)
float f = 3.14f;      // f al final — indica que es float
double d = 3.14;      // sin sufijo — los decimales son double por defecto
double d2 = 3.14d;    // d al final — también válido pero innecesario

¿Cuándo usar float y cuándo double?

La regla para FP2: usa siempre double. Es el tipo decimal por defecto en Java y tiene más precisión. float se usa en aplicaciones donde la memoria es crítica (gráficos 3D, sensores), situaciones que no verás en FP2.

Si olvidas la f al declarar un float, Java da error porque por defecto los literales decimales son double:

float f = 3.14;     // error: possible lossy conversion from double to float
float f = 3.14f;    // correcto
float f = (float)3.14;  // también correcto — casting explícito

boolean — verdadero o falso

En Python era True y False con mayúscula. En Java es true y false en minúscula:

# Python
aprobado = True
suspenso = False
// Java
boolean aprobado = true;
boolean suspenso = false;

Los booleanos en Java son estrictamente true o false, no hay conversión automática desde números como en Python:

# Python — 0 es falso, cualquier otro número es verdadero
if 1:
    print("verdadero")    # se ejecuta
// Java — un int nunca es un boolean
int x = 1;
if (x) {    // error de compilación — x es int, no boolean
    ...
}
if (x != 0) {    // correcto — condición booleana explícita
    ...
}

String — el que no es primitivo

String no es un tipo primitivo, es una clase. Esa distinción es importante y tiene consecuencias. Por eso se escribe con mayúscula (String), igual que todas las clases en Java, mientras que los primitivos van en minúscula (int, double, boolean).

String nombre = "Sergio";
String saludo = "Hola, " + nombre;
String vacio = "";
String nulo = null;    // un String puede ser null — sin valor asignado

Los Strings en Java son inmutables, igual que en Python. Una vez creado un String no puedes modificar sus caracteres. Cuando haces nombre = nombre + "!", no estás modificando el String original, estás creando uno nuevo y reasignando la variable.

String s = "Hola";
s = s + " mundo";    // crea un nuevo String "Hola mundo"
                     // el String "Hola" original sigue en memoria hasta que
                     // el garbage collector lo elimine

Primitivos vs objetos — heap y stack

Esta es la diferencia más importante entre primitivos y objetos, y la que explica por qué == se comporta diferente con Strings que con ints.

En Java la memoria se divide en dos zonas principales:

Stack (pila) — memoria rápida y ordenada. Aquí se guardan las variables locales y sus valores primitivos. Cuando termina un método, todo lo que estaba en el stack de ese método se libera automáticamente.

Heap (montón) — memoria más grande y flexible. Aquí se guardan los objetos, instancias de clases, arrays, Strings. El heap persiste más allá del método que creó el objeto.

STACK                    HEAP
┌─────────────────┐      ┌─────────────────────────┐
│ int edad = 22   │      │ String "Sergio"          │
│    edad → [22]  │      │ String "Hola"            │
│                 │      │ (otros objetos...)       │
│ String nombre ──┼──────► "Sergio"                 │
└─────────────────┘      └─────────────────────────┘

Cuando declaras int edad = 22, el valor 22 se guarda directamente en el stack, es el valor en sí.

Cuando declaras String nombre = "Sergio", en el stack se guarda una referencia, la dirección de memoria del heap donde está el String «Sergio». La variable nombre no contiene el texto, contiene la dirección donde está el texto.

int a = 5;
int b = a;    // copia el VALOR — b tiene su propio 5
b = 10;       // cambiar b no afecta a a
System.out.println(a);    // → 5 (no cambió)
System.out.println(b);    // → 10

String s1 = "Hola";
String s2 = s1;    // copia la REFERENCIA — s1 y s2 apuntan al mismo String

La diferencia entre == y .equals() — la trampa clásica de Java

Aquí está la consecuencia directa de todo lo anterior. El operador == en Java compara valores. Para primitivos eso funciona perfectamente:

int a = 5;
int b = 5;
System.out.println(a == b);    // → true — compara los valores 5 y 5

Pero para objetos (incluidos Strings), == compara referencias, es decir, compara si las dos variables apuntan exactamente al mismo objeto en el heap, no si tienen el mismo contenido:

String s1 = new String("Hola");    // crea un nuevo String en el heap
String s2 = new String("Hola");    // crea OTRO nuevo String en el heap

System.out.println(s1 == s2);         // → false — son objetos distintos en memoria
System.out.println(s1.equals(s2));    // → true  — tienen el mismo contenido
HEAP:
  dirección 0x1000: "Hola"   ← s1 apunta aquí
  dirección 0x2000: "Hola"   ← s2 apunta aquí

s1 == s2   → ¿0x1000 == 0x2000? → false
s1.equals(s2) → ¿"Hola".equals("Hola")? → true

La confusión surge porque Java tiene una optimización llamada String pool, cuando usas literales de String (sin new), Java reutiliza el mismo objeto si el contenido es igual:

String s1 = "Hola";    // Java mete "Hola" en el String pool
String s2 = "Hola";    // Java reutiliza el "Hola" del pool

System.out.println(s1 == s2);    // → true — ambas apuntan al mismo objeto del pool

Esto puede hacer que == parezca que funciona con Strings, pero solo por casualidad. Si en algún momento el String viene de una variable, de la entrada del usuario, de un método… ya no hay garantía:

String s1 = "Hola";
String s2 = "Ho" + "la";              // se resuelve en compilación → mismo objeto del pool
String s3 = new String("Hola");       // fuerza un nuevo objeto fuera del pool
String s4 = obtenerString();          // viene de un método — objeto nuevo

System.out.println(s1 == s2);         // → true  (por el pool)
System.out.println(s1 == s3);         // → false (new fuerza objeto nuevo)
System.out.println(s1 == s4);         // → false (objeto nuevo)
System.out.println(s1.equals(s4));    // → true  (mismo contenido)

La regla de oro: para comparar Strings (y cualquier objeto) usa siempre .equals(), nunca ==.

// MAL — trampa clásica de Java
if (nombre == "Sergio") { ... }      // puede fallar

// BIEN — siempre .equals() para objetos
if (nombre.equals("Sergio")) { ... } // siempre correcto

final — la constante de Java

final en Java es el equivalente de las constantes, una variable declarada final no puede cambiar su valor después de la asignación inicial. Es el equivalente aproximado de las constantes en Python, aunque Python no las enforce realmente:

# Python — convención de constante (mayúsculas), pero nada impide cambiarla
PI = 3.14159
PI = 5    # Python no da error aunque viole la convención
// Java — final obliga a que no cambie
final double PI = 3.14159;
PI = 5;    // error de compilación: cannot assign a value to final variable PI

final int MAX_INTENTOS = 3;
final String NOMBRE_APP = "SergioLearns";

Por convención, las variables final en Java se escriben en MAYÚSCULAS con guiones bajos, igual que las constantes en Python. No es obligatorio pero es el estilo estándar.

final int MAX = 100;              // constante entera
final double GRAVEDAD = 9.8;      // constante decimal
final String TITULO = "FP2";      // constante String

final también puede aplicarse a variables que se inicializan más tarde, pero solo pueden recibir valor una vez:

final int x;
x = 5;         // primera y única asignación — correcto
x = 10;        // error — ya tiene valor

Conversión entre tipos — casting

Java no convierte tipos automáticamente en todos los casos. Hay dos tipos de conversión:

Conversión implícita (widening): de un tipo más pequeño a uno más grande. Java la hace automáticamente porque no hay riesgo de perder datos:

int i = 100;
long l = i;        // int → long — automático, sin pérdida
double d = i;      // int → double — automático, sin pérdida
float f = i;       // int → float — automático

// Jerarquía: byte → short → int → long → float → double
// A la derecha siempre caben los de la izquierda

Conversión explícita (narrowing): de un tipo más grande a uno más pequeño. Puede perder datos, así que Java la exige explícita con casting:

double d = 9.99;
int i = d;           // error — posible pérdida de datos
int i = (int) d;     // correcto — casting explícito → i = 9 (trunca decimales)

long l = 1000000L;
int i = (int) l;     // correcto — casting explícito → i = 1000000 (cabe)

long l = 3000000000L;  // mayor que Integer.MAX_VALUE (2.147.483.647)
int i = (int) l;       // correcto sintácticamente pero da resultado incorrecto
                       // — los bits se truncan → resultado imprevisible
// Casting con char e int
char c = 'A';
int codigo = c;          // char → int — automático → 65
char c2 = (char) 66;     // int → char — casting explícito → 'B'

System.out.println(codigo);    // → 65
System.out.println(c2);        // → B

Conversión entre String y números

Convertir entre String y tipos numéricos no es casting, son métodos:

// String → número
int i = Integer.parseInt("42");
double d = Double.parseDouble("3.14");
long l = Long.parseLong("9000000000");

// número → String
String s1 = String.valueOf(42);       // → "42"
String s2 = String.valueOf(3.14);     // → "3.14"
String s3 = Integer.toString(42);     // → "42" (también válido)
String s4 = "" + 42;                  // → "42" (concatenación — menos formal)

Si el String no es un número válido, parseInt lanza NumberFormatException:

int i = Integer.parseInt("hola");    // NumberFormatException — "hola" no es un int
int i = Integer.parseInt("3.14");    // NumberFormatException — tiene decimales

Las clases envoltorio — Integer, Double, Boolean…

Cada tipo primitivo tiene una clase envoltorio (wrapper class) que lo convierte en objeto:

int      → Integer
double   → Double
float    → Float
long     → Long
boolean  → Boolean
char     → Character
byte     → Byte
short    → Short

Las necesitarás cuando Java exija un objeto en vez de un primitivo, por ejemplo en colecciones como ArrayList. Java hace la conversión automáticamente en la mayoría de casos (autoboxing/unboxing):

Integer objetoInt = 42;       // autoboxing — int → Integer automático
int primitivo = objetoInt;    // unboxing — Integer → int automático

Integer a = 127;
Integer b = 127;
System.out.println(a == b);   // → true (Java cachea Integer de -128 a 127)

Integer c = 200;
Integer d = 200;
System.out.println(c == d);   // → false (fuera del caché — objetos distintos)
System.out.println(c.equals(d)); // → true — siempre usa equals con objetos

También tienen métodos útiles:

int max = Integer.MAX_VALUE;    // → 2147483647
int min = Integer.MIN_VALUE;    // → -2147483648
System.out.println(Integer.toBinaryString(10));    // → 1010
System.out.println(Integer.toHexString(255));      // → ff
System.out.println(Double.isNaN(0.0/0.0));         // → true

Declaración múltiple y var

Puedes declarar varias variables del mismo tipo en una línea:

int a = 1, b = 2, c = 3;
double x = 0.0, y = 0.0;

Desde Java 10 puedes usar var para que Java infiera el tipo automáticamente, como Python, pero solo para variables locales:

var nombre = "Sergio";    // Java infiere String
var edad = 22;            // Java infiere int
var nota = 8.5;           // Java infiere double

var no significa que la variable no tenga tipo, significa que el compilador lo deduce del valor. Una vez asignado el tipo no puede cambiar:

var x = 5;
x = "hola";    // error — x es int, no String

En FP2 verás más el estilo explícito (int x = 5) que var, porque los apuntes y los exámenes usan la forma tradicional. Pero var existe y es válido.

Resumen rápido

// TIPOS PRIMITIVOS
byte b    = 100;           // -128 a 127
short s   = 30000;         // -32768 a 32767
int i     = 1000000;       // ← más usado — entero estándar
long l    = 9000000000L;   // L obligatorio — entero grande
float f   = 3.14f;         // f obligatorio — decimal simple precisión
double d  = 3.14;          // ← más usado — decimal doble precisión
boolean b = true;          // true o false (minúscula, no True/False)
char c    = 'A';           // comillas simples — un carácter

// char y ASCII
char c = 'A';              // 'A' = 65 en ASCII
int codigo = 'A';          // → 65
char letra = (char) 66;    // → 'B'

// String — NO es primitivo, es objeto
String nombre = "Sergio";  // comillas dobles
// NUNCA == para comparar Strings
nombre.equals("Sergio")    // ← siempre .equals() para objetos

// final — constante
final int MAX = 100;       // no puede cambiar después

// CASTING
double d = 9.99;
int i = (int) d;           // → 9 (trunca decimales) — casting explícito

// conversión implícita (sin pérdida)
int i = 5;
double d = i;              // automático — int cabe en double

// String ↔ número
int n = Integer.parseInt("42");
double x = Double.parseDouble("3.14");
String s = String.valueOf(42);

// CLASES ENVOLTORIO
Integer, Double, Boolean, Character, Long, Float, Byte, Short

// HEAP vs STACK
// Primitivos → valor en el stack
// Objetos    → referencia en el stack, valor en el heap
// Por eso == con objetos compara referencias, no contenido

// REGLAS DE ORO
// 1. Usa int para enteros y double para decimales en FP2
// 2. Siempre .equals() para comparar Strings — nunca ==
// 3. Comillas simples para char, dobles para String
// 4. Sufijo L para long, f para float
// 5. (tipo) para casting explícito cuando puedes perder datos

En el próximo artículo vemos la entrada de datos con Scanner y el control de flujo, if/else, switch y cómo usar las variables que acabas de aprender.


Java variables — primitive types, String, final and casting from scratch

Java variables are where the difference from Python becomes really clear. In Python a variable was just a name pointing to a value — no declarations, no types, no size limits. In Java every variable has a fixed type declared before use that can never change.

Why Java requires declaring the type of every variable

Java is statically typed, the type of every variable is fixed at declaration and cannot change:

# Python — no types
x = 5
x = "hello"    # fine in Python
// Java — type declaration required
int x = 5;
x = "hello";    // compile error — x is int, not String

The compiler checks all type operations before running the program, errors are caught at compile time, not runtime.

Variable declaration syntax

// type name = value;
String name = "Sergio";
int age = 22;
double grade = 7.5;
boolean passed = true;

The eight primitive types

byte     → tiny integer          (8 bits,  -128 to 127)
short    → small integer         (16 bits, -32768 to 32767)
int      → standard integer      (32 bits) ← most used
long     → large integer         (64 bits)
float    → single precision decimal (32 bits)
double   → double precision decimal (64 bits) ← most used
boolean  → true or false
char     → single character      (16 bits)

When to use each:

FP2 rule: use int for integers and double for decimals. That covers 95% of cases. Use long when numbers exceed ~2 billion (add L suffix). Use float only when explicitly needed (add f suffix).

int i = 1000000;
long l = 9000000000L;    // L suffix required
double d = 3.14;
float f = 3.14f;         // f suffix required
boolean b = true;        // lowercase — not True like Python
char c = 'A';            // single quotes — not double

byte, char and ASCII

byte holds values 0-255 (unsigned), matching the ASCII table range. char holds a single Unicode character (16 bits, values 0-65535). The first 128 values match ASCII exactly:

char letter = 'A';         // the character A
int code = 'A';            // 65 — ASCII code of A
char next = (char)('A'+1); // 'B'

System.out.println((int)'Z');    // → 90
System.out.println((char)65);    // → A

// Iterate through alphabet
for (char c = 'a'; c <= 'z'; c++) {
    System.out.print(c + " ");
}
// → a b c d e f ... z

Single quotes for char, double quotes for String, strict rule in Java:

char c = 'A';     // correct
char c = "A";     // error — "A" is a String
String s = "A";   // correct
String s = 'A';   // error — 'A' is a char

String — not a primitive

String is a class, not a primitive, hence the capital letter. Strings are immutable (like Python).

Heap and Stack

Java memory has two main zones:

Stack — fast, ordered. Stores local variables and primitive values. Freed automatically when a method finishes.

Heap — larger, flexible. Stores objects. Persists beyond the method that created them.

STACK                    HEAP
int age = 22 → [22]      String "Sergio" (at address 0x1000)
String name ─────────────► "Sergio"

Primitives store their value directly in the stack. Objects store a reference (memory address) in the stack pointing to the actual data in the heap.

== vs .equals() — Java’s classic trap

== compares values for primitives, works correctly:

int a = 5, b = 5;
System.out.println(a == b);    // → true

For objects, == compares references, whether two variables point to the exact same object in the heap:

String s1 = new String("Hello");
String s2 = new String("Hello");

System.out.println(s1 == s2);         // → false — different objects in heap
System.out.println(s1.equals(s2));    // → true  — same content

The String pool creates confusion, Java reuses String objects for literals:

String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);    // → true (same pool object — coincidence)

But once a String comes from a method, user input, or new, == fails. Golden rule: always use .equals() to compare Strings. Never ==.

if (name.equals("Sergio")) { ... }    // correct
if (name == "Sergio") { ... }         // wrong — could fail

final — Java’s constant

# Python — convention only, not enforced
PI = 3.14159
PI = 5    # Python allows this
// Java — enforced by compiler
final double PI = 3.14159;
PI = 5;    // compile error: cannot assign a value to final variable

final int MAX_ATTEMPTS = 3;     // UPPERCASE_WITH_UNDERSCORES convention
final String APP_NAME = "FP2";

Casting — type conversion

Implicit (widening): smaller to larger type. Java does it automatically:

int i = 100;
double d = i;    // automatic — int fits in double
long l = i;      // automatic
// Hierarchy: byte → short → int → long → float → double

Explicit (narrowing): larger to smaller. May lose data, must be explicit:

double d = 9.99;
int i = (int) d;     // → 9 (truncates decimals)

char c = (char) 66;  // → 'B'
int code = 'A';      // → 65 (automatic char → int)

String ↔ number conversion:

int n = Integer.parseInt("42");
double x = Double.parseDouble("3.14");
String s = String.valueOf(42);     // → "42"
String s = "" + 42;                // → "42" (concatenation)

Wrapper classes

int → Integer    double → Double    boolean → Boolean    char → Character

Java does autoboxing/unboxing automatically. Always use .equals() with wrapper objects, not ==.

Quick summary

// PRIMITIVES
int i = 5;          // standard integer ← most used
long l = 5L;        // large integer — L suffix
double d = 3.14;    // decimal ← most used
float f = 3.14f;    // single precision — f suffix
boolean b = true;   // lowercase true/false
char c = 'A';       // single quotes

// char and ASCII
int code = 'A';         // → 65
char letter = (char)66; // → 'B'

// String — object, not primitive
String s = "text";              // double quotes
s.equals("other")               // ALWAYS .equals() for objects — never ==

// final — constant
final int MAX = 100;            // cannot change

// CASTING
int i = (int) 9.99;            // → 9 (truncates)
double d = 5;                   // automatic (int → double)

// String ↔ number
int n = Integer.parseInt("42");
String s = String.valueOf(42);

// HEAP vs STACK
// Primitives: value stored in stack
// Objects: reference in stack → value in heap
// That's why == with objects compares addresses, not content

// GOLDEN RULES
// 1. int for integers, double for decimals in FP2
// 2. Always .equals() for Strings — never ==
// 3. Single quotes for char, double quotes for String
// 4. L suffix for long, f suffix for float
// 5. (type) for explicit cast when data loss is possible

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *