import
A shorthand for names. It does not load or include anything.
import java.util.ArrayList;
This lets you write ArrayList instead of java.util.ArrayList. That is all it does.
It is worth being clear about what it is not, because the C background misleads: import does not copy code into your file, does not affect compiled output, and has no run-time cost. It is purely a naming convenience resolved at compile time.
Where it goes
After the package declaration, before the class:
package com.example.app;
import java.util.List;
import java.util.Map;
public class Thing { }
Wildcards
import java.util.*;
Imports every class in java.util, not sub-packages. java.util.* does not bring in java.util.concurrent.Executor.
There is no performance difference. The argument against wildcards is readability and collisions: with a wildcard you cannot tell from the file where a class came from, and adding a class to a library can suddenly make an existing name ambiguous.
java.lang is automatic
String, System, Integer, Math, Object, Exception and the rest of java.lang need no import.
The same package needs none
Classes in the same package see each other without imports. Imports are for crossing package boundaries.
Collisions
Two classes with the same simple name cannot both be imported:
import java.util.Date;
import java.sql.Date; // error
Import one and fully qualify the other:
import java.util.Date;
...
java.sql.Date d = ...;
Static imports
Brings in a static member so you can drop the class name:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
double c = sqrt(a * a + b * b) * PI;
Useful for assertion methods in tests, where assertEquals reads better than Assertions.assertEquals. Used widely elsewhere it removes the context that told the reader where a method came from. max(a, b) is less clear than Math.max(a, b).
Unused imports
Harmless, but they suggest code that has moved on without being tidied. Every IDE removes them on request.