From the course: Learning JVM Languages: JVM, Java, Scala

JVM concepts and Java editions

- [Instructor] Welcome to the next video, JVM Concepts and Java Editions. In the previous video, we looked at popular use cases. In this video, we're going to take a look at important JVM concepts such as virtual machine, compilers, classes and backward compatibility. We'll look at three Java editions and learn about where each one is used. Every aspiring JVM developer should be familiar with its most important concepts. JVM is a virtual machine. Most implementations feature a just-in-time JIT compiler. It offers a few built-in primitive datatypes. Everything else is an object. Objects are accessed via reference types. The garbage collector, GC process, removes obsolete objects from memory. Build tools are used a lot in the JVM world. Finally, it should be noted that each application that runs on JVM loads its own instance of JVM on system memory. This means when you run multiple Java applications at the same time, they will all have their own copy of JVM at their disposal. This also means different applications can use different versions of JVM if required for whatever reason. For security reasons, it's not suggested that you have different versions of the JDK or JRE on one system. It's usually better to have only the latest supported versions installed. Although not dictated anywhere, all popular JVM implementations are not just simply interpreters. They feature complex JIT compilers along with their interpreters. When you launch a Java application, JVM is launched and initialized first. Once it is done, it immediately starts interpreting and running the Java byte code. If the interpreter believes it makes sense, it will compile sections of the programs and load libraries to native executable code and memory, and start executing that version of the code instead of the interpreted Java byte code version. This often results in code that could be executed much faster. Whether the code is complied or interpreted depends on many things. If a routine is called often, it becomes a probable candidate for the JIT compiler to compile it to the native code. The advantage of the JIT approach is that the distributed files can be cross platform and the user did not have to wait for native compiling of the whole application. Applications start executing immediately after JVM is initialized, and the optimization is done under the hood. JVM has a few so called built in primitive data types. This is the main reason why Java is not considered a pure OOP language. Variables of these types are not objects and always have a value. The table here provides clarification. Note that not all JVM languages support the creation of variables of primitive types, and follows more than assumption. Everything takes the object approach. We'll see that this is usually not a problem as the Java class library has wrapper objects that wrap primitive types. In most languages, including Java, automatically use these wrappers when required. This process is called Autoboxing. Now moving onto classes. Functions and variables are always declared inside a class. Even the application entry function that is called upon a program lodge called the main function is a function that's located inside a class. JVM only supports the single inheritance model. Classes always inherit from one class at the maximum. This is not a big loss. As we'll see in the next section, a structure called an interface comes to the rescue. An interface is basically a list of function prototypes and constants. Classes that implement the interface are required by the compiler to have implementations for those functions. Classes can implement as many interfaces as they want, but they must provide implementations to each method of all the implemented interfaces. Some languages covered in this course hide the facts completely from the developer. JVM classes are usually grouped in packages. In the next section, we'll see how classes are organized. Let's look at reference types now. Like most modern programming languages, JVM does not work with direct memory pointers to objects. It uses references types. A reference type variable either points to a specific instance of a class or it points to nothing. If a reference type points to an object, it can be used to call the object's methods or access public attributes. If a reference points to nothing, it's called a null reference. When calling methods or reading attributes using a null reference, an arrow will be generated at run time. Let's take a look at this code. Assume that product is a class here that is available to the programmer. We create a product instance and the p variable points to it. We then call this setName method on this object instance. JVM does not give direct access to the memory location where the product location is stored. It just provides a reference to the created object. When using the variable p, JVM figures out which memory location it has to reach for the object that the variable points to. We add these lines to the snippet. A reference can be declared explicitly by assigning null to it. Now the p variable is a null reference. This code will compile fine. When running the program, the last line will cause a null pointer exception error, though. If no error handling capabilities was implemented in the application, it will crash. Many modern IDEs try to detect these situations and warn the developer about them. Let's see what the garbage collector does. JVM does not require the programmer to manually allocate and release blocks of memory when creating or disposing of objects. The programmer can generally concentrate on just creating objects when he or she needs them. A process known as the GC halts the application at certain interval and scans the memory for objects that are no longer in scope. It will remove those objects that can be safely deleted from memory, and reclaim the freed space. This process used to cause very serious performance issues in the past, but the algorithm has improved much over the years. Also, if an application needs it, system administrators can configure many parameters of the GC to better control it. The developer should always keep the high level concept of the GC algorithm in mind. If you keep creating tons of objects and always keep them in the scope, then out of memory errors are very likely to occur sooner or later. For example, let's assume you developed an e-commerce application for an online store. Also, let's assume each logged in user has their own shopping basket instance that holds the products that they add to their basket. Say a user has logged in today and is planning to buy a soap bar and a delicious pack of cookies. For this user, the application will create two product instances, one for each chosen product, and add them to the products list of shopping basket. Just before visiting the check out page, the user sees that Amazon offers the same cookies at a much better price, and decides to remove the cookies from the basket. Technically the application would remove the product instance from the list of products. But from there on, the product instance respecting chocolate cookies is null for object. As there is no reference to it, it can not be reached by the application. After a while, JVM's GC kicks in and sees the chocolate cookies object instance. It determines that the object cannot be reached in any way by the application anymore, and therefore decides to remove it. The memory the object was using up will now be released. There are several tricks to tame GC. One well known trick when an application needs to work with lots of similar objects is to put these objects in a pool. When an application needs an object, it simply gets one from the pool and modifies the object according to its needs. When it's finished and doesn't need the object anymore, it will put it back in the pool. Since these objects are always in the scope, GC will not try to dispose of these objects. Now our next topic is backward compatibility. The maintainers of JVM and Java class library understand the needs of business developers. The code that's written today should ideally run tomorrow. JVM offers reasonable backward compatibility. Developers familiar with Python 2 and 3 will know this is not given in the industry. Newer JVM versions can run applications that were compiled for older JVM versions, as long as the applications code does not use APIs or technologies that will remove from the JVM version that's running the application. Here's an example. Libraries compiled for Java 6 can still be loaded and used in projects that run on a Java 8 JVM instance. But this is not the case the other way around. Applications running on a Java 6 JVM instance cannot load classes compiled for later versions. Further we'll learn about build tools. Back when projects were simpler, simple batch or operating system shell scripts were used to ultimate the compiling and packaging process. As projects became more complex, it became harder to define these scripts. For different operating systems, completely different scripts had to be written. Soon the first set of dedicated Java build tools appeared. These worked with XML build files. More or less cross-platform compatible scripts were written this way. At first, long and cumbersome scripts had to be written. Later, tools worked with the convention over configuration paradigm. When using the convention suggested by the tool, much less code had to be written. However, if your situation is different from the default behavior, it can take a lot of effort to let the tools do what you want or need. Newer tools ditch XML files and provide script languages to automate building. Some of the features that many of these tools offer are as displayed. The JDK does not offer a build tool itself, but it will be hard to find projects that do not at least use a patchy end, a patchy maven or gradle. JVM programmers that use a popular IDE do not have to worry too much build automation tools. This is because all IDEs can generate build scripts themselves. If you want more control, you can start writing scripts manually and let the IDE use that script to compile, test, and run your project. Moving on the the second portion of the video. Java Editions Several editions of Java are available. Each one aims are different use cases. Some of the editions have had numerous name changes over the years. The current names of the editions are: Java Standard Edition (Java SE), Java Enterprise Edition (Java EE), and Java Micro Edition (Java ME). Let's start with Java SE. This is the most important edition. When people mention the term Java, they usually refer to this edition. This course concentrates solely on the Java SE platform. This edition is meant to run on desktop machines and servers. As we'll see later, an embedded version is also available, and bundled with Raspberry Pi's linux distribution. Java SE comes with the complete Java class library. It includes the classic swing GUI toolkit. Most versions also contain the modern FX GUI toolkit. Java SE is mostly meant to create standalone consoles, desktop GUIs, or headless applications. Alternatively, it's used to create external libraries. Next edition is Java EE. Java EE builds upon Java SE, therefore it requires that Java SE is installed. It adds lots of APIs in a lot of categories. Java EE application usually run inside JVM application servers. This course does not cover Java EE in depth, but we'll mention it from time to time. This is because it's a very important edition to the Java platform, especially for business developers. It's not possible to download Java EE standalone edition from the oracle website. Instead, you'll have to download a full application server that's compatible with the Java EE platform version you want to use. Some IDEs bundle the Java EE application servers as well. We'll cover this in the next section. Java EE standard only describes the APIs that must be available, but it does not dictate the implementation. It's up to the Java EE compatible application servers to come up with actual implementations that adhere to these standards. Finally, we have Java ME. Before the days of IOS and android, Java ME happened to be an important platform for feature phones and early smartphones for games and some basic applications. IOS and android both never supported Java ME applications. So nowadays it does not play a major role anymore. It featured a subset of the Java Class Library, and offered some additional APIs to work with mobile devices. Java ME got a second life as Java ME Embedded, which can be used for commercial IoT devices. Cool, we learned so much in this video about different JVM concepts and Java editions. In the next video, we'll learn about other languages on JVM.

Contents