Packages and imports
Organizing classes into folders with names, importing what you need, and the classpath.
Finished reading?
Mark this session so you can track where you are.
Organizing classes into folders with names, importing what you need, and the classpath.
Finished reading?
Mark this session so you can track where you are.
Every program you have written so far has lived in one file, with one or two classes stacked inside it. That is fine for ten lines. But a real Java project has hundreds of classes, and if you threw them all into one folder with no organization, you would lose your mind. Today we learn how Java keeps order: it sorts classes into named drawers called packages.
package is, and how the dotted name relates to folders on disk.package declaration and an import, and explain what each one does.public to be reached from another package.public, private, and protected in encapsulation. You also saw classes nested inside classes in inner classes. This session zooms out one more level: instead of organizing fields inside a class, we organize whole classes inside packages. No new object ideas here, just a way to arrange the ones you have.Picture a banking application. It has a class for a customer, a class for an account, a class for a transaction, a class that prints reports, a class that talks to the database, and dozens more. Now imagine all of those sitting loose in a single folder, every .java file shoulder to shoulder with no grouping. Finding the one you want means scrolling through a wall of names. Worse, two different parts of the project might both want a class called Reader: one that reads bank records, one that reads a file. With everything in one pile, those two names collide and the language has no way to tell them apart.
A package is a named group of related classes. It is the folder system of Java, with one twist: the folder name is written into the code itself, so the language always knows which drawer a class lives in.
__init__.py inside, and wrote things like from collections import deque. Java's packages are the same instinct. The big difference is that Java ties the package name directly to the folder layout on disk, and it enforces that link strictly. There is no skipping it the way a quick Python script sometimes does.To put a class into a package, you write one line at the very top of the file, before anything else except comments. It names the package the class belongs to.
package com.bank.model; public class Customer { String name; double balance;}That first line, package com.bank.model;, says “this class lives in the package com.bank.model”. The name uses dots, and each dot is a step deeper into a folder. So a package named com.bank.model corresponds to a folder path com/bank/model on disk, and the file Customer.java must physically sit inside that folder. The structure on disk mirrors the dotted name exactly. If they disagree, the compiler complains.
A picture helps. Here is how three classes in two packages lay out on disk. The dotted names become the nested folders.
src/ com/ bank/ model/ Customer.java (package com.bank.model;) Account.java (package com.bank.model;) report/ Printer.java (package com.bank.report;)package declaration must be the first statement in the file, above any importlines and any class. Only comments may come before it. A file belongs to exactly one package, so there is at most one package line per file. If you write a class with no package line at all, it lands in the unnamed default package, which is acceptable for tiny throwaway programs but discouraged for anything real.Once a class lives in a package, its real, complete name includes that package. The class we just wrote is not merely Customer. Its true name is com.bank.model.Customer. That long form is called the fully qualified name: the package, then a dot, then the class. It is unambiguous anywhere in the world, because the package part pins down exactly which Customeryou mean.
The catch is that nobody wants to type com.bank.model.Customer every single time they use it. So Java lets you use the short name, Customer, on its own, as long as the compiler can figure out which package you meant. Inside the same package, it figures that out for free. From a different package, you have to tell it, and that is what import is for.
Customer.com.bank.model.Customer.Scanner s;java.util.Scanner.An importline tells the compiler “when I write this short name, I mean the class from that package”. After importing, you use the short name freely. The most famous example is the keyboard reader, Scanner, which lives in the package java.util.
package com.bank.app; import java.util.Scanner; public class Greeter { public static void main(String[] args) { Scanner in = new Scanner(System.in); // imagine the user typed: there String name = "there"; System.out.println("Hello " + name); }}Hello there
Read the top of that file as a small stack. First the package line says where this class lives. Then the import java.util.Scanner; line pulls one class in by name. From that point on, writing Scanner is enough, the compiler knows you mean java.util.Scanner because you said so. The import does not copy any code into your file and it does not make your program bigger. It is just a note to the compiler about how to read a short name.
Scanner reads what a person types at the keyboard, so it needs real input that the read-along block here cannot provide. The full, runnable treatment of reading from the console is the next session: Scanner and console applications. Today the point is only the import line itself, not what Scanner does.You write one import per class you want by its short name. If you need several from the same package, you can list them one by one, or use a star to bring in every public class from that package at once.
import java.util.Scanner; // just this one classimport java.util.ArrayList; // and this one import java.util.*; // OR: every public class in java.utilimport java.util.*;, looks tidy but hides what your file actually depends on, and it can quietly pull in a name that clashes with one of your own classes. Most teams and most IDEs prefer the explicit one-class-per-line form. Your editor will add those import lines for you automatically as you type, so the cost of being explicit is basically zero.You have used String, System, and Math since your very first program, and you never wrote an import for them. That is not magic. They live in a package called java.lang, and Java imports java.lang for you automatically into every file. It holds the classes so fundamental that no program could function without them, so the language spares you the import.
public class NoImports { public static void main(String[] args) { String s = "hello"; int max = Math.max(2, 5); System.out.println(s.toUpperCase() + " " + max); }}HELLO 5
Every name in that program, String, Math, and System, comes from java.lang, which is why it needs no import at all. Anything outside java.lang, like Scanner from java.util, must be imported or written out in full.
There is a gap to close. When your program says new Scanner(...), the running Java machine has to find the actual compiled Scanner code somewhere on the computer and load it. How does it know where to look? The answer is the classpath: a list of locations Java searches for compiled classes.
Remember that you write .java source files, but Java does not run those directly. It compiles them into .class files full of bytecode, and those compiled files are what actually run. The classpath is the set of folders and bundled archives where the running program hunts for the .class file matching each name it needs. When a class is in package com.bank.model, Java looks for the folder path com/bank/model inside each classpath location until it finds the right .class file. This is the same mirror-the-folders rule, now used at run time.
The classpath answers one question: when the program needs a class by name, which folders should Java search to find its compiled code? Get it wrong and you see the dreaded
ClassNotFoundExceptionorNoClassDefFoundError.
.java files. At run time, the Java machine loads .classfiles. The classpath is about that second step: finding compiled classes while the program runs. When you hear “put it on the classpath”, picture adding a folder to the list of places Java will search for .class files.Packages do more than tidy your files. They draw a real boundary that the access modifiers from encapsulationrespect. The question now is not just “can this class see that field?” but “can a class in one package use a class in another package at all?” The deciding word is public.
A class with no modifier in front of the word class is package-private: visible only to other classes in the same package. To use a class from a different package, it must be marked public. The same goes for the members inside it. A field or method you want to reach from another package must be public too. This is exactly why you have been writing public class and public static void main all along: main has to be reachable from outside, so it is public.
// File 1: com/bank/model/Account.javapackage com.bank.model; public class Account { // public: usable from other packages public double balance; // public: readable from other packages double secretPin; // no modifier: package-private, hidden outside} // File 2: com/bank/app/Demo.javapackage com.bank.app; import com.bank.model.Account; // different package, so we import it public class Demo { public static void main(String[] args) { Account a = new Account(); // OK, Account is public a.balance = 500.0; // OK, balance is public // a.secretPin = 1234; // ERROR: secretPin is package-private }}Walk the boundary slowly. Demo lives in com.bank.app, while Account lives in com.bank.model, two different packages. So Demo must import the Account class, and Account must be public or the import would be useless. Inside, balance is public, so Demo can read and set it. But secretPin has no modifier, so it is package-private: visible to anything in com.bank.model, invisible to Demo next door. The commented line would not compile.
main and most API classes are.class Account in one package, then cannot understand why another package will not compile against it. The class is package-private by default, so it simply does not exist as far as the other package is concerned. The fix is one word: public class Account. The same trap catches methods you meant to expose. If another package needs it, it must say public.Here is the full life of a name, from the file that defines it to the file that uses it, in four steps.
package com.bank.model;. On disk it sits in the matching folder com/bank/model.com.bank.model.Customer, unique in all the world.import com.bank.model.Customer; so it can use the short name Customer. For that to be allowed, Customer must be public.com/bank/model/Customer.class and load it. The folders mirror the package name once more.Notice the same idea appearing three times: the dotted package name is mirrored by the folder layout, at the source level, in the fully qualified name, and on the classpath at run time. Hold onto that one correspondence and packages stop being mysterious. They are just folders with names the language keeps track of.
package on the first line puts a class in a drawer; the drawer is a folder on disk.import lets you use a class from another drawer by its short name..class files.public is the key that opens a class or member across a package boundary.Try each one yourself first, then open the answer.
package com.shop.cart;. In which folder on disk must its .java file sit?System.out.println(...) and never imported System. Why does it work with no import?Scanner class, and write the two equivalent ways to create one: with an import, and without.Account in package com.bank.model is written as class Account with no modifier. A class in package com.bank.app tries to import and use it and fails to compile. What single word fixes it, and why?Take these away. They continue exactly what we just did.
Book, Member, Loan, and a Main that runs it. Choose sensible package names and draw the folder tree, showing which .java file sits in which folder. Write the package line that would top each file.import line another package would need to use it by its short name. Finally, note the one change required on the class itself for that import to be legal.import exists given that you can always use the fully qualified name instead..java and .class files.