Thinking in java
1 OOP
| Modules | Terms | Description |
| Object Oriented Programmming (OOP) | Encapsulation |
The object encapsulates variables and methods, some of which are exposed to the outside, while others are not. |
| Inheritance | ||
| Abstraction |
Circles, triangles, rectangles, and other shapes can be abstracted into a class called "Shape," as they are all shapes. |
|
| Polymorphism |
circle, triangle, rectangle can use shape to execute functions. Shape shape = new Circle(); // Triangle(); Rectangle(); shape.size(); |
2 Method overloading
1 public class Print{ 2 3 void print(){}; 4 void print(int i){}; 5 }
3 Constructor
| Default Constructor | If a constructor is explicitly written in the code, the program will not create a default constructor. Otherwise, there will be a default constructor |
| Code |
public Constructor(int i){ Constructor(); ..... }
|
| this reference |
|
4. Initialization
1) Initialization order of non-static data:
-
Member variables (regardless of where they are written, such as before or after methods)
-
Method block
{} -
MethodsInitialization of static data:
2) static data
-
Static data occupies only one storage area.
-
staticcannot be applied to local variables. -
Initialization process: static first, then non-static.
-
Static members are loaded as the class is loaded.
-
Initialized in order.
5 Array
new Object[] {new Integer(0), new Float(1.0), new Double(1.0)} void printArrs(Object ... args){ for(Object arg : args) .. }
6 Access Control:
| Key Words | Range |
| public | Everywhere |
| private | |
| protected | Used to handle inheritance. In a subclass, protected members can be accessed. protected also provides package-level access. |
| Package Access |
For class access: Only one public class is allowed per file. A class cannot be declared as private or protected. If you want to prevent others from accessing the class, you can declare its constructor as private.
7. Locations for Initializing Reference Objects
1) At the point of definition
public class MyClass { private List<String> list = new ArrayList<>(); // initialized at definition }
2) In the class constructor
public class MyClass { private List<String> list; public MyClass() { list = new ArrayList<>(); // initialized in constructor } }
3) Lazy initialization
public class MyClass { private List<String> list; public List<String> getList() { if (list == null) { list = new ArrayList<>(); // lazy initialization } return list; } }
4) Instance initialization block
public class MyClass { private List<String> list; { // instance initialization block list = new ArrayList<>(); System.out.println("List initialized"); } }
8 If the constructor of the current class conflicts with the parent class, this problem can be resolved through another constructor
public class Dog extends Animal { private String breed; // Constructor 1: calls parent constructor directly public Dog(String name, String breed) { super(name); // resolves conflict by explicitly calling parent constructor this.breed = breed; } // Constructor 2: calls another constructor in the same class using this() public Dog(String name) { this(name, "Unknown"); // delegates to Constructor 1 } // Constructor 3: provides default values public Dog() { this("Unknown", "Unknown"); // also delegates } }
public class Animal {
private String name;
public Animal(String name) { // no default constructor
this.name = name;
}
}
9 Clean
class Parent { void show() { System.out.println("Parent show()"); } void show(String msg) { System.out.println("Parent show: " + msg); } } class Child extends Parent { // Overloading: adds a new version, does not hide parent's overloaded methods void show(int number) { System.out.println("Child show: " + number); } } public class Test { public static void main(String[] args) { Child obj = new Child(); obj.show(); // ✅ Calls Parent's show() obj.show("Hello"); // ✅ Calls Parent's show(String) obj.show(100); // ✅ Calls Child's show(int) } }
10 Override
"The access level of the overriding method must be greater than or equal to the access level of the parent class method."
class Parent { protected void display() { System.out.println("Parent display"); } } class Child extends Parent { @Override public void display() { // ✅ allowed (protected → public) System.out.println("Child display"); } }
class Child2 extends Parent { @Override void display() { // ❌ compilation error (protected → default is not allowed) System.out.println("Child display"); } }
11 final
-
Modify data: a constant that will never change.
-
Modify data: blank final — must be initialized before it is used.
-
Final parameter: the parameter value cannot be modified.
-
Modify reference variables: the reference itself cannot change; the memory address remains the same.
-
Modify methods: a method is declared
finalwhen it must not be overridden. -
All
privatemethods in a class are implicitlyfinal. -
Final class: a class that is not intended to be inherited; it cannot have subclasses.
12 Pitfalls of Overriding
If a parent class method f() is private, and the subclass defines a public method f(), polymorphism will still call the parent's f()
Variables are not overridden
class Parent { String name = "Parent"; } class Child extends Parent { String name = "Child"; // hides parent's name, but not override } public class Test { public static void main(String[] args) { Parent obj = new Child(); System.out.println(obj.name); // Output: Parent (not Child) } }
13 Inheritance and Cleanup
Initialization from top to bottom, destruction from bottom to top — be careful when destroying objects
14 Behavior of Polymorphic Methods Inside Constructors
If the subclass is not fully initialized, the parent class may polymorphically call the subclass's methods
public class Main { public void draw(){ System.out.println("Main draw"); } public Main(){ System.out.println("Main() "); draw(); } public static void main(String [] args){ new Sub(); } } public class Sub extends Main{ private int v = 1; public void draw(){ System.out.println("sub draw() " + v); } Sub(){ System.out.println("Sub() " + v); } }
/*
Main()
sub draw() 0
Sub() 1
*/
Inside constructors, try to avoid using other methods whenever possible. If you must use them, use final or private methods.
15 Abstract Classes and Abstract Methods
- Abstract Classes Cannot Be Instantiated
- Provide common methods, Better extensibility — Define a template for subclasses,Enable polymorphism
- abstract is the key word\
16 Interface
- interface produces a completely abstract class
- Interfaces define a contract between classes
- Fields in Interfaces are static, final, public
public interface Action { void doSth(); void height(); } class Creature implements Action { public void doSth(){ System.out.println("creature doSth"); } public void height(){ System.out.println("creature height"); } } class Human extends Creature{ public void doSth(){ System.out.println("human doSth"); } public static void main(String [] args){ Action a = new Human(); a.doSth(); a.height(); } }
17 Inner Class
- Inner Classes Can Directly Communicate with Outer Class
- Referring to Outer Class: OuterClass.this
- Creating Inner Class: outer.new Inner()
- Cannot Create Inner Class Without Outer Instance
-
If the inner class is private, it cannot be created outside the outer class.
18 (Anonymous Inner Class)
import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class Main { public Contents contents(){ return new Contents(){ private int i = 11; public int value(){return i;} }; } public static void main(String [] args){ Main m = new Main(); Contents c = m.contents(); c.value(); } } interface Contents{ int value(); }
abstract class Base { public Base(int i ){ } public abstract void f(); } class AnonymousConstructor{ public static Base getBase(int i ){ return new Base(i){ public void f(){ } }; } public static void main(String [] args){ Base b = getBase(1); b.f();; } }
Local variables (explicit final)abstract class Base { public Base(final int i ){ } public abstract void f(); } class AnonymousConstructor{ public Base base(final int i ){ return new Base(i){ private int num; { num = 1000; } public void f(){ System.out.println(num); } }; } }
Cannot Extend and Implement Simultaneously
19 Classes inside an interface
In Java, you can define nested classes inside an interface. This is a powerful feature for grouping related functionality together.
20 Type casting
- Upcasting (Automatic, Safe)
- Downcasting (Risky, Requires Explicit Cast) instanceof
21 instanceof & Class
- instanceof for Upcasting, .class and == for Exact Type Comparison
21 Reflection: Runtime Type Information
- Loading Classes Across Network
22 Dynamic Proxy in Java
- The target object must implement at least one interface (Java's java.lang.reflect.Proxy class can only create proxies for interfaces, not classes.) AOP design
23 Generics in Java
- Type Erasure, ArrayList.class is OK, but ArrayList<String>.class is not.
24 Bounds in Generics
- the class must come first, followed by interfaces.
class ColoredDimension<T extends Dimension & HasColor>
- at most one class, can have multiple interfaces
25 The File Class
- Can represent both directories and files
package com.webbuild.controllers; import java.io.File; public class FileTest { public static void main(String [] args){ File f = new File("D:\\"); for(String s : f.list()) System.out.println(s); } }
26 Input and output in Java
-
FileInputStream and Batch Reading
package com.webbuild.controllers; import java.io.File; import java.io.FileInputStream; public class FileTest { public static void main(String [] args) throws Exception{ File f = new File("D:\\ff.txt"); FileInputStream fis = new FileInputStream(f); byte [] readBuf = new byte[512]; int len = fis.read(readBuf); for(int i = 0; i < len; i++){ System.out.println((char)readBuf[i]); } } }
27 Reader and Writer in Java
- Internationalization with Unicode
- BufferedReader可以readLine
public static void main(String [] args) throws Exception{ FileReader fr = new FileReader("D:\\ff.txt"); BufferedReader br = new BufferedReader(fr); String line; while ((line = br.readLine()) != null){ System.out.println(line); } br.close(); fr.close(); }
28. Enums in Java
- Cannot extend classes
- Singleton pattern, each enum constant is a single instance
- Can import enum constants for cleaner code
- Enum constructors are private or package-private
- Enums are final by default
package com.webbuild.controllers; public interface Food { enum Appetizer implements Food{ SALAD, SOUP; } enum Coffee implements Food{ BLACK_COFFEE, LATTE, TEA } }
29 Annotations in Java
- Allowed Element Types: Primitive types, String, Class, Enum, Annotation, Arrays
package com.webbuild.controllers; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Test { }
- @Traget. Where the annotation can be applied
- @Retention. How long the annotation is retained
- @Documented. Include annotation in JavaDoc
- @Inherited. Allow subclasses to inherit the annotation
Four meta-annotations control how annotations behave:
30 Concurrent.
- Parallelism: Multiple processors executing simultaneously
- Concurrency: Multiple tasks making progress in overlapping time periods
- Thread Class, only call start to run thread, if you run run() function, it doestn't execute concurrently
31 Ways to Create Threads in Java
- Extend Thread
- Implement Runnable, no return value
- Implement Callable
Thread Yielding Thread voluntarily gives up CPU to other threads
Thread.yeald();
Thread Pool, don't need to create a thread every time.
- ExecutorService
future blocks until completion
32 Sleep
TimeUnit.SECONDS.sleep()
- Will yield CPU execution rights
- Will not release locks
33 Thread Priority
- Deamon Threads - Threads provide general services in backgroud. They are not essential.
- Non-Deamon Threads - Essential Threads. main()
- Daemon threads do not execute finally blocks when terminating
- t2.join() causes the current thread to pause execution until thread t2 terminates
34 Shared Limited Resources
| Bullets | Description | Code |
| The static keyword represents shared resources |
static means there is only one copy in the program, therefore it is a shared resource |
|
|
boolean is atomic |
It is atomic, requiring only a single machine instruction |
|
|
Increment and decrement operations are not atomic |
||
|
Locking prevents other threads from accessing |
Acquire lock, execute, release lock. This mechanism is often called mutual exclusion or mutex |
|
| synchronized | ||
| Every object automatically contains a lock | ||
|
For a specific object, all synchronized blocks share the same lock |
When a thread executes synchronized f(), no other threads can execute g() |
package learnjava; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class SychronizedTest { public static void main(String [] args) throws InterruptedException{ TaskRunner taskRunner = new TaskRunner(new Object()); ExecutorService service = Executors.newFixedThreadPool(4); for(int i = 0; i < 100; i++){ service.execute(taskRunner); } service.shutdown(); TimeUnit.SECONDS.sleep(1); } } class TaskRunner implements Runnable{ private int count = 0; private Object obj; public TaskRunner(Object obj){ this.obj = obj; } public void run(){ synchronized (obj){ count++; System.out.println(count); } } }
|
|
A synchronized non-static method actually locks on 'this' |
public synchronized void run()
|
|
|
Reentrant Lock |
A task can acquire an object's lock multiple times without needing to compete again. When a thread re-acquires the lock, the counter increments by 1. When a task exits, the counter decrements. Sychronized is reentrant. |
public class ReentrantCounterExample { private final ReentrantLock lock = new ReentrantLock(); public void methodA() { lock.lock(); // First acquisition: hold count = 1 System.out.println("Hold count: " + lock.getHoldCount()); // 1 try { methodB(); // Same thread re-enters // Do work } finally { lock.unlock(); // First release: hold count = 0 } } public void methodB() { lock.lock(); // Second acquisition: hold count = 2 System.out.println("Hold count: " + lock.getHoldCount()); // 2 try { methodC(); // Can re-enter again // Do more work } finally { lock.unlock(); // Second release: hold count = 1 } } public void methodC() { lock.lock(); // Third acquisition: hold count = 3 System.out.println("Hold count: " + lock.getHoldCount()); // 3 try { // Do even more work } finally { lock.unlock(); // Third release: hold count = 2 } } }
|
| The lock for a synchronized static method is not the 'this' lock, but rather the Class object lock (ClassName.class) | Multiple threads running the same class's static synchronized methods: only one thread can execute, BUT synchronized methods (non-static, and locking on different instances) can execute simultaneously |
package com.wn.rest.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class LearnSync extends Thread { private static int count = 0; public LearnSync() { } public synchronized static void out() { System.out.println("Ready to start thread " + Thread.currentThread().getName()); try { while (true) { count++; System.out.println("in static " + Thread.currentThread().getName() + " count " + count); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(4); for (int i = 0; i < 4; i++) { service.execute(new Runnable() { @Override public void run() { LearnSync.out(); } }); } service.shutdown(); } } |
35 Lock
| Bullets | Description | Code |
| Lock | Finer granularity. If something fails inside synchronized, you cannot do finer-grained things, such as performing cleanup work in finally |
package learnjava; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest { public static void main(String [] args){ ExecutorService service = Executors.newFixedThreadPool(10); RunnableTask runnableTask = new RunnableTask(); for(int i = 0; i < 100; i++){ service.execute(runnableTask); } service.shutdown(); } } class RunnableTask implements Runnable{ public int count = 100; private Lock lock = new ReentrantLock(); public void run(){ lock.lock(); //防止执行模块异常 无法释放锁 try { count--; System.out.println("count " + count); } finally { lock.unlock(); } } }
|
| tryLock in Lock attempts to acquire the lock and will continue executing the following code (whether successful or not). lock() will wait indefinitely until the lock is acquired. |
import java.util.concurrent.locks.ReentrantLock; public class TryLockVsLock { private final ReentrantLock lock = new ReentrantLock(); public void useLock() { System.out.println(Thread.currentThread().getName() + " trying to lock"); lock.lock(); // <-- BLOCKS HERE until lock is acquired // Thread waits HERE indefinitely until it gets the lock try { System.out.println(Thread.currentThread().getName() + " got the lock"); Thread.sleep(2000); // Hold lock for 2 seconds } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " released lock"); } } public void useTryLock() { System.out.println(Thread.currentThread().getName() + " trying tryLock"); boolean gotLock = lock.tryLock(); // <-- RETURNS IMMEDIATELY, never blocks! if (gotLock) { try { System.out.println(Thread.currentThread().getName() + " got the lock with tryLock"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " released lock"); } } else { // This code executes IMMEDIATELY if lock is not available System.out.println(Thread.currentThread().getName() + " could NOT get lock, but still executing!"); // Do alternative work } } }
|
36 Atomicity and Volatility
| Bullets | Description | Code |
| Atomicity |
Atomic operations are operations that cannot be interrupted by the thread scheduling mechanism. Once started, they will execute to completion without being interrupted in the middle. This applies to basic operations on primitive types except long and double. The JVM splits 64-bit long and double into two 32-bit operations.
|
|
| Visibility |
Reads occur from main memory, writes are temporarily written to memory |
|
| volatile |
The volatile keyword immediately writes content to main memory. The synchronized keyword can guarantee visibility. If a field is modified by the synchronized keyword, then it does not need to be modified by volatile. Any write operations by a task are visible to that task. It guarantees atomicity and visibility. Both reads and writes should be synchronized. |
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AtomicTest implements Runnable{ private int i = 0; private synchronized void add(){ i++; i++; } public synchronized int get(){ return i; } public void run(){ while (true){ add(); } } public static void main(String [] args){ AtomicTest atomicTest = new AtomicTest(); ExecutorService service = Executors.newFixedThreadPool(10); service.execute(atomicTest); while (true){ int num = atomicTest.get(); if(num % 2 != 0){ System.out.println(num); System.exit(0); } } } }
|
| AtomicInteger | ||
| Thread States: |
|
|
| ThreadLocal |
ThreadLocal provides thread-local variables — each thread accessing such a variable has its own, independently initialized copy of the variable.
Each Thread has its own ThreadLocals, it is a map. So it is thread isolated.
// java.lang.ThreadLocal 类 public void set(T value) { // 1. 获取当前线程 Thread t = Thread.currentThread(); // 2. 获取当前线程的 ThreadLocalMap ThreadLocalMap map = getMap(t); // 3. 如果 map 存在,就把值放进去 if (map != null) // 注意:key 是 this(当前 ThreadLocal 对象) map.set(this, value); else // 第一次调用,创建 map createMap(t, value); } // 获取当前线程的 ThreadLocalMap ThreadLocalMap getMap(Thread t) { return t.threadLocals; // 每个线程自己的 map } // 创建 ThreadLocalMap void createMap(Thread t, T firstValue) { // key 是 this,value 是传入的值 t.threadLocals = new ThreadLocalMap(this, firstValue); }
|
public class ConnectionManager { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { @Override protected Connection initialValue() { return DriverManager.getConnection(DB_URL); } }; public static Connection getConnection() { return connectionHolder.get(); // Each thread gets its own connection } public static void closeConnection() { Connection conn = connectionHolder.get(); if (conn != null) { conn.close(); connectionHolder.remove(); } } } // Usage public class TransactionalService { public void doWork() { Connection conn = ConnectionManager.getConnection(); // Thread-specific // Use connection - no interference from other threads } }
|

浙公网安备 33010602011771号