الاستيراد وتعارض الأسماء
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
In the last lesson you put classes into packages. A class in one package now has a longer name, such as com.example.bank.Account. Writing that full name every time you use the class would be tiring and hard to read. The import statement is the shortcut: it tells the compiler "when I write Account, I mean com.example.bank.Account".
In our filing cabinet picture, an import is a note on your desk that says which drawer a document comes from, so you can refer to it by its short title. The document is not copied to your desk, and nothing is loaded. You just get a shorter way to name it.
Why this matters: every Java file you will read or write in a backend project begins with a block of imports. You need to read that block quickly, avoid the * shortcut in serious code, and know what to do when two libraries both offer a class with the same name. That last situation is common: dates, lists and loggers all appear in several libraries.
This lesson builds on "Packages and folders" and uses the same com.example layout.
Learning Objectives
By the end of this lesson you will be able to:
- Explain what an
importdoes and what it does not do. - Write single-type imports in the correct place in a file.
- Say which classes need no import (same package,
java.lang). - Explain what
import java.util.*;does and where it stops. - Resolve a name clash between two classes by importing one and spelling out the other.
- Read the compiler errors for a missing import and for an ambiguous name.
- Explain why explicit imports are preferred in real code.
Written Explanation
What an import is
An import is a naming shortcut, nothing more. The Java Language Specification describes imports as letting code use simple names for types from other packages, where otherwise it would need fully qualified names. An import does not copy code, does not run anything and does not decide what is compiled. If you wrote java.util.List everywhere instead, the program would behave identically.
Imports go after the package line and before the class:
package com.example.app;
import com.example.bank.Account;
import java.util.List;
public class Main { }Each import line names one class by its full name and ends with a semicolon. This form is called a single-type import.
Three cases where you need no import
- The class is in the same package. All classes of one package see each other by simple name. In our test,
PrinterandStatementboth live incom.example.bank, soPrinterusesStatementwith no import. - The class is in
java.lang. The JLS says every file behaves as if it began withimport java.lang.*;. That is whyString,Object,MathandSystemwork with no import. - You write the fully qualified name.
java.util.List<String> names = ...needs no import line, because there is nothing to shorten.
Everything else needs an import (or a full name): List, ArrayList, Scanner, and every class of your own that lives in a different package.
The wildcard import
The second form is the on-demand import, written with *:
import java.util.*;It makes all the accessible classes directly in java.util available by simple name. Points to know:
- It does not import sub-packages.
import java.util.*;gives youList, but not anything fromjava.util.concurrent. Hierarchy in names has no special meaning to Java: the JLS says there is no access relationship betweenoliver.twistandoliver. - It does not make the program bigger or slower. It is only a name lookup rule for the compiler.
- It can create ambiguity, as the next section shows.
Most teams prefer explicit single-type imports in real code: a reader sees exactly which classes a file depends on, and a new class added to a wildcard-imported package cannot silently clash with yours. Your IDE can add and tidy imports for you (the menu names vary by IDE, so check its help for "organize imports" or similar).
Name clashes
Two different packages may contain classes with the same simple name. The standard library has java.util.Date and java.sql.Date. If both are in play in one file, Date alone is ambiguous. There are three situations.
Situation 1: two wildcard imports.
import java.util.*;
import java.sql.*;
// ... Date d = new Date(0L);The compiler refuses at the point of use:
error: reference to Date is ambiguous
both class java.sql.Date in java.sql and class java.util.Date in java.util matchSituation 2: two single-type imports of the same simple name.
import java.util.Date;
import java.sql.Date;error: a type with the same simple name is already defined by the single-type-import of DateThe JLS says two single-type imports of the same simple name from different types are an error.
Situation 3: the fix. Import one class and write the other with its full name:
import java.util.Date;
java.sql.Date day = new java.sql.Date(0L);Choose the class you use most as the imported one. The full name is always legal, wherever the class is accessible.
A single-type import also wins over a wildcard import of the same simple name, so import java.util.Date; together with import java.sql.*; resolves Date to java.util.Date. Do not lean on that. Explicit is easier to read.
Imports and visibility are separate
An import never grants access. A class you import must also be accessible. A class that is not public can only be used inside its own package, even with an import line. The next lesson is about that rule.
Two limits to remember
- Each file has its own imports. They do not carry over to other files, even in the same package.
- You cannot import a package alone.
import java.util;is an error. You import a class (java.util.List) or all classes (java.util.*).
Examples
Example 1: a missing import (simple)
Main uses Account from another package but has no import line:
package com.example.app;
public class Main {
public static void main(String[] args) {
Account a = new Account("Sara", 100);
}
}error: cannot find symbol
Account a = new Account("Sara", 100);
^
symbol: class Account
location: class MainThe compiler reports "cannot find symbol" for the type and again for the constructor call. The fix is one line after the package line: import com.example.bank.Account;. Whenever you see cannot find symbol ... class X for a class you know exists, ask: is it in a different package, and did I import it?
Example 2: classes that need no import (practical)
Two classes in package com.example.bank:
package com.example.bank;
public class Statement {
public String title() { return "Monthly statement"; }
}package com.example.bank;
public class Printer {
public static String print(Statement s) { // same package: no import
return "[" + s.title() + "]";
}
}Main in package com.example.app needs both:
package com.example.app;
import com.example.bank.Printer;
import com.example.bank.Statement;
public class Main {
public static void main(String[] args) {
System.out.println(Printer.print(new Statement()));
String s = "lang"; // String is in java.lang: no import
System.out.println(s.length());
}
}Output:
[Monthly statement]
4Printer needed no import for Statement; Main needed two imports; String needed none.
Example 3: using both Date classes (realistic)
A reporting class reads timestamps from an application and writes database dates. It needs both Date types:
package com.example.app;
import java.util.Date;
import java.util.List;
public class Clash {
public static void main(String[] args) {
Date now = new Date(0L);
java.sql.Date day = new java.sql.Date(0L);
List<String> names = List.of("a", "b");
System.out.println(now.getTime() + " " + day.getTime() + " " + names.size());
System.out.println(day.getClass().getName());
}
}Output (JDK 21):
0 0 2
java.sql.DateDate means java.util.Date because that is the one imported. The other is written out in full each time it is used. If you used java.sql.Date many times, you might import that one and spell out the other instead. Pick whichever makes the file easier to read. Some teams avoid the clash by wrapping one of the two in their own class so the rest of the code never sees both.
Backend Insight
Backend code constantly mixes classes from several libraries: your own domain classes, JDK classes, logging, database and web libraries. Name clashes happen in practice with Date, List, Logger and many Request/Response types. The reversed-domain package convention from Lesson 1 is exactly what makes the clash solvable: the full names are different even when the simple names match.
Reading imports is also a fast way to understand a file. The import block tells you what a class depends on: a bank.account class importing from bank.notification shows a link between two features. When imports from many unrelated packages pile up in one class, that is a signal the class does too much. In Lesson 4 we use these import lines to see how packages depend on each other.
Common Mistakes
Mistake 1: thinking an import loads or copies code
An import line changes how names are written, not what the program does. A program works the same with all imports replaced by full names.
Mistake 2: forgetting that the wildcard does not include sub-packages
import java.util.*; does not import java.util.concurrent.ExecutorService, because that class lives in a sub-package. The symptom is the usual cannot find symbol. Import what you need explicitly.
Mistake 3: wildcard imports from two packages that share a name
import java.util.*; import java.sql.*; is fine until you write Date. Then the compiler reports an ambiguity. Switch to single-type imports.
Mistake 4: trying to import a class from the default package
import Helper;
error: '.' expectedAn import needs a package name. This is one more reason to avoid the unnamed package.
Mistake 5: assuming an import makes a hidden class usable
If a class is not public, an import line does not help from another package. The compiler says "is not public ... cannot be accessed from outside package". See the next lesson.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. Which of these need an import in a class of package com.example.app: String, ArrayList, Math, a class com.example.bank.Account?
أظهر الحل A1
A1. ArrayList and Account need imports. String and Math are in java.lang.
A2. Write the import line for java.util.Scanner, and say where it goes relative to the package line.
أظهر الحل A2
A2. import java.util.Scanner;. It goes after the package line (if any) and before the class.
A3. True or false: import java.util.*; also imports java.util.concurrent.TimeUnit. Explain briefly.
أظهر الحل A3
A3. False. The wildcard imports only the classes directly in java.util, not those of sub-packages, so TimeUnit needs import java.util.concurrent.TimeUnit; or import java.util.concurrent.*;.
Level B: Application
B1. This code does not compile. Name the error type and fix it:
package com.example.app;
public class Report {
public static void main(String[] args) {
List<String> lines = new ArrayList<>();
lines.add("x");
}
}أظهر الحل B1
B1. cannot find symbol for List and ArrayList. Add import java.util.List; and import java.util.ArrayList; after the package line.
B2. A file has import java.util.*; and import java.awt.*;. It uses List. Both packages have a class named List. What goes wrong, and how do you fix it, if you want java.util.List?
أظهر الحل B2
B2. Using List is ambiguous because two on-demand imports both provide it, and the compiler reports an ambiguity error. Fix: add import java.util.List;, or replace the wildcards with single-type imports. Writing java.util.List in full also works.
B3. Rewrite this snippet so it compiles, using only one import line and no wildcard:
java.util.Date a = new java.util.Date(0L);
java.sql.Date b = new java.sql.Date(0L);أظهر الحل B3
B3.
import java.util.Date;
Date a = new Date(0L);
java.sql.Date b = new java.sql.Date(0L);Importing the java.sql one and spelling out java.util.Date is equally correct.
Level C: Challenge
C1. Class Auditor in package com.example.bank calls Printer.print(...), where Printer is in package com.example.bank too. A teammate adds import com.example.bank.Printer; anyway. Is that an error? What would you say in code review?
أظهر الحل C1
C1. It is not an error (the JLS lets code refer to the current package's types freely, and importing a type from your own package is harmless), but it is redundant noise. In review, ask to remove it, because the same-package rule makes the line unnecessary. Many IDEs flag it as unused or redundant.
C2. Explain why a team might forbid wildcard imports. Give two reasons.
أظهر الحل C2
C2. Reasons: readers cannot tell which classes a file depends on; and a wildcard may start causing ambiguity when a new class with a clashing name is added to one of the packages. Also, tooling output about dependencies is clearer with explicit lines.
Mini Challenge
Take the project from Lesson 1 (com.example.shop.Product and com.example.app.Main). Add a second class PriceFormatter in com.example.shop that has a public static method format(Product p) returning text such as Pen costs 2.5, and a class Invoice in com.example.app that uses both Product and PriceFormatter and a java.util.List<Product>.
Check your work: Invoice has exactly three imports (two of your own, one java.util.List), uses no wildcard, and compiles. Now remove the import of Product and read the error. Then add a use of java.sql.Date and java.util.Date in the same file, importing only one.
Summary & Next Lesson
Key takeaways
- An
importis a naming shortcut for the compiler. It copies nothing and runs nothing. - Imports sit after the
packageline and before the class. - No import is needed for classes in the same package or in
java.lang. import x.y.*;imports the classes directly inx.y, not sub-packages, and can create ambiguity. Prefer explicit single-type imports.- When two classes share a simple name, import one and write the other with its full name.
- An import never changes visibility: the imported class must still be accessible.
Next lesson
You have just seen the error "is not public ... cannot be accessed from outside package". The next lesson, "Package-private: the forgotten modifier", explains the visibility rule behind it and shows how to use it on purpose to hide helper classes.
Self-check
- What does
import com.example.bank.Account;let you do? - Why does
Stringneed no import? - What does
import java.util.*;leave out? - How do you use both
java.util.Dateandjava.sql.Datein one file? - Does an import make a non-public class from another package usable?
أظهر الإجابات
- Write
Accountinstead ofcom.example.bank.Accountin that file. - It is in
java.lang, which every file imports automatically. - Classes in sub-packages such as
java.util.concurrent. - Import one of them and write the other with its full name.
- No. Visibility rules still apply, so the class must be public (or in the same package).
References
- Oracle, The Java Language Specification, SE 21, Chapter 7: Packages and Modules. Supports the definition of single-type and on-demand imports, the automatic
java.langimport, errors for duplicate single-type imports, that sub-packages are not imported, and that package hierarchy gives no special access. - Oracle, The Java Tutorials: Naming a Package. Supports the point that classes with the same simple name can live in different packages and are told apart by full names.
- The compiler errors and program outputs were produced with JDK 21 in a scratch directory. The rule that a single-type import wins over a wildcard import comes from the JLS shadowing discussion as we read it; the on-demand/ambiguity compiler message was observed directly.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.