From 2bf62eb9563778245671a76cae75eaf432da5c3f Mon Sep 17 00:00:00 2001 From: Tristan-Raz Date: Mon, 28 Jul 2025 13:22:39 -0400 Subject: [PATCH] I added typecasting, primitives, variable name, and fixes issue #32 --- source/ch_4_javadatatypes.ptx | 200 ++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 79 deletions(-) diff --git a/source/ch_4_javadatatypes.ptx b/source/ch_4_javadatatypes.ptx index 6d097a7..6992dd8 100644 --- a/source/ch_4_javadatatypes.ptx +++ b/source/ch_4_javadatatypes.ptx @@ -59,6 +59,39 @@ In older versions of Java, it was the programmers responsibility to convert back and forth from a primitive to an object whenever necessary. This process of converting a primitive to an object was called “boxing.” The reverse process is called “unboxing.” In Java 5, the compiler became smart enough to know when to convert back and forth and is called “autoboxing.” In this book, we will typically use the Object version of all the numeric data types and let the compiler do its thing.

+

+ With that distinction in mind, here are the common types you'll use, most of which are similar to Python's types: +

+ + A data type fundamentally defines a set of values and the operations you can perform on them. For instance, you can do math with int and double values, but not with boolean values. This is simlar to Python, where you can perform arithmetic on integers and floats, but not on booleans or strings. +

Let’s look at a simple Python function which converts a Fahrenheit temperature to Celsius. @@ -117,11 +150,6 @@ public class TempConv {

-
  • -

    - Input/Output and the Scanner Class -

    -
  • @@ -202,13 +230,19 @@ public class TempConv { - - Declaring Variables + + Variable Declaration

    - Here is where we run into one of the most important differences between Java and Python. Python is a dynamically typed language. In a dynamically typed language a variable can refer to any kind of object at any time. When the variable is used, the interpreter figures out what kind of object it is. Java is a statically typed language. In a statically typed language the association between a variable and the type of object the variable can refer to is determined when the variable is declared. Once the declaration is made it is an error for a variable to refer to an object of any other type. + Here is where we run into one of the most important differences between Java and Python. Python is a dynamically typed language. In a dynamically typed language a variable can refer to any kind of object at any time. When the variable is used, the interpreter figures out what kind of object it is. Java is a statically typed language. In a statically typed language the association between a variable and the type of object the variable can refer to is determined when the variable is declared. Once the declaration is made it is an error for a variable to refer to an object of any other type.

    +

    + A valid variable name in Java can contain letters, digits, and underscores. It must begin with a letter, an underscore, or a dollar sign. It cannot start with a digit and it cannot be a reserved keyword (like class, int, or static). Variable names are case-sensitive, so fahr and Fahr are different variables. The convention is to use lower case for variable names, and to use camel case (where the first word is lowercase and subsequent words are capitalized) for multi-word variable names, such as fahrenheitTemperature. +

    +

    + An important feature of Java is that when you declare a variable of a primitive type (like int or double), the system automatically allocates a fixed amount of memory to store its value directly. This is different from reference types (like String or Scanner), where the variable holds a memory address that points to the actual object data stored elsewhere. This distinction makes operations on primitives very fast. +

    In the example above, lines 5—7 contain variable declarations. Specifically we are saying that fahr and cel are going to reference objects that are of type Double. The variable in will reference a Scanner object. This means that if we were to try an assignment like fahr = "xyz" the compiler would generate an error because "xyz" is a string and fahr is supposed to be a double.

    @@ -223,86 +257,94 @@ public class TempConv {

    - The general rule in Java is that you must decide what kind of an object your variable is going to reference and then you must declare that variable before you use it. There is much more to say about the static typing of Java, but for now this is enough. + The general rule in Java is that you must decide what kind of an object your variable is going to reference and then you must declare that variable before you use it. In our temperature converter, the calculation (fahr - 32) * 5.0/9.0 works correctly because 5.0 and 9.0 are treated as double values, preventing the integer division that would occur if we had written 5/9, which would result in 0.

    -
    - - - - Input / Output / Scanner - -

    - In the previous section we created a Scanner object. In Java, Scanner objects make getting input from the user, a file, or even over the network relatively easy. In our case we simply want to ask the user to type in a number at the command line, so in line 9 we construct a Scanner by calling the constructor and passing it the System.in object. Notice that this Scanner object is assigned to the name in, which we declared to be a Scanner on line 7. System.in is similar to System.out except, of course, it is used for input. If you are wondering why we must create a Scanner to read data from System.in when we can write data directly to System.out using println, you are not alone. We will talk about the reasons why this is so later when we talk in-depth about Java streams. You will also see in other examples that we can create a Scanner by passing the Scanner a File object. You can think of a Scanner as a kind of “adapter” that makes low level objects easier to use. -

    - -

    - On line 11 we use the Scanner object to read in a number. Here again we see the implications of Java being a strongly typed language. Notice that we must call the method nextDouble because the variable fahr was declared as a double. So, we must have a function that is guaranteed to return each kind of object we might want to read. In this case, we need to read a Double so we call the function nextDouble. The compiler matches up these assignment statments and if you try to assign the results of a method call to the wrong kind of variable it will be flagged as an error. -

    - -

    - The table below shows some commonly used methods of the Scanner class. There are many more methods supported by this class and we will talk about how to find them in our chapter about . -

    - - - - - Return type - Method name - Description - - - - boolean - hasNext() - returns true if more data is present - + + - - boolean - hasNextInt() - returns true if the next thing to read is an integer - +
    + Typecasting - - boolean - hasNextFloat() - returns true if the next thing to read is a float - +

    + Typecasting is the process of converting a variable from one type to another. In Java, this is often necessary when you want to perform operations that require different data types. For example, if you have an integer and you want to convert it to a double for more precise calculations, you would use typecasting. +

    - - boolean - hasNextDouble() - returns true if the next thing to read is a double - +

    + In Java, typecasting can be done in two ways: implicit and explicit. Implicit typecasting occurs automatically when converting from a smaller data type to a larger one (like int to double), while explicit typecasting requires you to specify the conversion manually (like double to int). +

    - - Integer - nextInt() - returns the next thing to read as an integer - +

    + Implicit typecasting happens automatically when converting a value from a smaller data type to a larger one, as there is no risk of losing information. For example, you can assign an int to a double without any special syntax. +

    +
     
    +        int myInt = 10;
    +        double myDouble = myInt; // Automatic casting from int to double
    +        
    + +

    + Explicit typecasting is required when converting from a larger data type to a smaller one, as you might lose data. You must do this manually by placing the target type in parentheses () before the value. +

    +
    +        double originalDouble = 9.78;
    +        int castedInt = (int) originalDouble; // Explicitly casts double to int. The value of castedInt is now 9.
    +        
    - - Float - nextFloat() - returns the next thing to read as a float - +

    + Besides primitive types, type casting is also a fundamental concept when working with objects, especially within an inheritance hierarchy. This involves converting an object reference from one class type to another, typically between a superclass and a subclass. This is often referred to as upcasting and downcasting. +

    +

    + Let's imagine we have a simple class hierarchy: an Animal superclass and a Dog subclass. +

    +
    +class Animal {
    +    public void makeSound() {
    +        System.out.println("The animal makes a sound.");
    +    }
    +}
     
    -                    
    -                         Double 
    -                         nextDouble() 
    -                         returns the next thing to read as a Double 
    -                    
    +class Dog extends Animal {
    +    public void bark() {
    +        System.out.println("The dog barks!");
    +    }
    +}
    +    
    + +

    + Upcasting (Implicit): Upcasting is casting a subclass instance to a superclass reference type. This is always safe because a subclass object is guaranteed to have all the methods and properties of its superclass. Therefore, upcasting is done implicitly by the compiler. +

    +
    +// A Dog object is created, but the reference is of type Animal.
    +// This is implicit upcasting.
    +Animal myAnimal = new Dog(); 
    +
    +myAnimal.makeSound(); // This is valid, as makeSound() is defined in Animal.
    +
    +// myAnimal.bark(); // This would cause a compile-time error!
    +// The compiler only knows about the methods in the Animal reference type.
    +    
    +

    + Downcasting (Explicit): Downcasting is casting a superclass reference back to its original subclass type. This is potentially unsafe because the superclass reference might not actually point to an object of the target subclass. You must perform an explicit cast. If you cast to the wrong type, Java will throw a ClassCastException at runtime. +

    +

    + To safely downcast, you should first check the object's type using the instanceof operator. +

    +
    +// 'myAnimal' is an Animal reference, but it points to a Dog object.
    +if (myAnimal instanceof Dog) {
    +    // The check passed, so this downcast is safe.
    +    Dog myDog = (Dog) myAnimal;
    +
    +    // Now we can access methods specific to the Dog class.
    +    myDog.bark(); // This is now valid.
    +}
    +    
    - - String - next() - returns the next thing to read as a String - - -
    -
    - +

    + In this example, we first create a Dog object and assign it to an Animal reference (upcasting). Then, we check if the Animal reference is actually pointing to a Dog object before downcasting it back to a Dog reference. +

    + +
    String