These are the 60 Java viva questions examiners ask most often, in the order an oral exam usually moves: the language basics, object-oriented programming, exceptions, collections, threads, and JDBC. Where an answer is a behaviour, the question has a short program and its real output, so you can show the examiner what happens rather than recite a definition.
Tested on OpenJDK 21.0.12. Every output line on this page comes from running JavaVivaDemo.java (basics to threads), JdbcVivaDemo.java (JDBC, run against H2 2.5.252 in memory) and CheckedDemo.java (thejavacerrors). Definitions are from the Java Language Specification and the API documentation. Run the first withjavac JavaVivaDemo.java && java JavaVivaDemo; for JDBC add the H2 jar to the classpath. The one unstable number is the thread race in question 49.
| If the viva is about… | Questions |
|---|---|
| Basics, strings, references | 1 to 10 |
| OOP, initialisation order, immutability | 11 to 24 |
| Exceptions and the compiler rules | 25 to 32 |
| Collections and maps | 33 to 44 |
| Threads, synchronisation, virtual threads | 45 to 54 |
| JDBC and transactions | 55 to 60 |
Basics: JVM, types, strings and references
These ten open most Java vivas. Each answer shows the behaviour, not just the definition.
1. What are the JDK, JRE and JVM?
The JVM runs bytecode. The JRE is the JVM plus the standard class libraries. The JDK is the JRE plus the developer tools (javac, jar, javadoc, jshell). Oracle stopped shipping a separate JRE with Java 11, so you normally install a JDK. You compile with the JDK and run on any JVM of a compatible version.
Q01 java.specification.version=21, vm=OpenJDK 64-Bit Server VMSource: JavaVivaDemo.java, section q01.
2. Why is Java called platform independent?
javac compiles source to bytecode (.class files), not to machine code. Each platform has its own JVM that turns that same bytecode into native instructions. The program is portable; the JVM is not. That is also why “write once, run anywhere” holds only when the target has a JVM at a compatible version.
3. What are the primitive types and their sizes?
Eight: byte (8 bits), short (16), char (16, unsigned), int (32), long (64), float (32), double (64) and boolean (size not fixed by the spec). Integer arithmetic wraps silently on overflow, as the second line shows.
Q03 byte=8 short=16 char=16 int=32 long=64 float=32 double=64 (bits)
Q03 int max=2147483647, max+1=-2147483648Source: JavaVivaDemo.java, section q03.
4. What are the default values of fields and local variables?
Fields get defaults: 0 for numbers, false, '\u0000' for char, and null for references. Local variables get no default: reading one before assigning is a compile error.
Q04 int=0 boolean=false String=null double=0.0 char=0Source: JavaVivaDemo.java, section q04.
5. What is the difference between == and equals()?
== compares references for objects (and values for primitives). equals() compares content, if the class overrides it. Object.equals itself is the same as ==. Two separate new String("java") objects are equals but not ==.
Q05 a == b: false, a.equals(b): trueSource: JavaVivaDemo.java, section q05.
6. Why is String immutable, and what is the string pool?
A String cannot change after creation, so it is safe as a HashMap key, safe to share between threads, and its hash can be cached. String literals live in the string pool (on the heap since Java 7), so equal literals are one object; new String(...) forces a separate object and intern() returns the pooled one. Methods like toUpperCase() return a new string and leave the original alone. More string questions: 30 Java string programs for interviews.
Q06 s1 == s2: true, s1 == s3: false, s1 == s3.intern(): true
Q06 after t.toUpperCase() t is still abcSource: JavaVivaDemo.java, section q06.
7. What is the difference between String, StringBuilder and StringBuffer?
String is immutable. StringBuilder is a mutable character buffer, not thread-safe, and the right choice in almost all code. StringBuffer is the older, synchronized version of the same API; its locking is rarely what you want. Concatenating in a loop with + creates a new string each time, so build with StringBuilder instead.
8. Why is Integer 127 == 127 true but 128 == 128 false?
Integer.valueOf (used by autoboxing) caches instances for -128 to 127, so two boxed 127s are the same object. 128 creates two objects, and == compares references. Always compare boxed numbers with equals.
Q08 127 == 127: true, 128 == 128: false, 128 equals 128: trueSource: JavaVivaDemo.java, section q08.
9. Is Java pass by value or pass by reference?
Always pass by value. For objects, the value passed is a copy of the reference. The method can change the object the reference points to (sb grew), but it cannot change the caller’s variable (n and arr are unchanged, because the reassignment only changed the copy).
Q09 n=1 sb=hi! arr[0]=1Source: JavaVivaDemo.java, section q09.
10. What does static mean, and why is main static?
A static member belongs to the class, not to any object: one copy, accessible without an instance. main is static so the JVM can call it before any object exists. A static method cannot use this or touch instance fields directly. Static fields are shared by all instances, which makes them a common source of thread-safety bugs.
Object-oriented programming
Oral exams push on the why: why this call, why this order. Run the example, then explain the output.
11. What are the four pillars of OOP?
Encapsulation (hide state behind methods), inheritance (reuse and extend a class), polymorphism (one call, many behaviours) and abstraction (expose what, hide how). A longer treatment is in OOP concepts in Java.
12. What is the difference between a class and an object?
A class is a blueprint: fields and methods. An object is an instance of it, created with new, with its own copy of the instance fields. If you write no constructor, the compiler adds a no-argument default constructor; as soon as you write any constructor, it does not.
13. How does constructor chaining work?
this(...) calls another constructor of the same class; super(...) calls the parent constructor. One of them must be the first statement. The parent constructor completes before the child constructor body runs, as the order below shows. Here B() calls super(), which delegates with this("x").
Q13 A(String) x
Q13 A()
Q13 B()Source: JavaVivaDemo.java, section q13.
14. What is the difference between method overloading and overriding?
Overloading: same name, different parameters, in the same class; the compiler picks the version from the declared argument types. Overriding: a subclass redefines an inherited method with the same signature; the JVM picks the version from the runtime type of the object. In the output add(1,2) reaches the override, add(1,2.0) picks the double overload, and a String falls to Object.
Q14 add(1,2)=overridden int,int, add(1,2.0)=double,double, add("s")=ObjectSource: JavaVivaDemo.java, section q14.
15. What is runtime polymorphism, and are fields polymorphic?
A call on a superclass reference runs the subclass version of an overridden method (dynamic dispatch). Fields are not polymorphic: field access uses the declared type. That is why a.name is animal although the object is a Dog.
Q15 a.speak()=woof (runtime type), a.name=animal (declared type)Source: JavaVivaDemo.java, section q15.
16. Abstract class or interface?
An abstract class can hold state, constructors and partially implemented methods, and a class can extend only one. An interface defines a contract; a class can implement many. Since Java 8 interfaces can have default and static methods (see Java 8 features), and since Java 9 private methods, but still no instance state. Use an interface for a capability, an abstract class when subclasses share code and fields.
17. In what order do static blocks, instance blocks and constructors run?
Static initialisers run once, when the class is first initialised, parent before child. For each new: parent instance initialisers and constructor, then child instance initialisers and constructor. The second object skips the static blocks.
Q17 Base static block
Q17 Derived static block
Q17 Base instance block
Q17 Base constructor
Q17 Derived instance block
Q17 Derived constructor
Q17 -- second object --
Q17 Base instance block
Q17 Base constructor
Q17 Derived instance block
Q17 Derived constructorSource: JavaVivaDemo.java, section q17.
18. What is the difference between final, finally and finalize?
final: a variable that cannot be reassigned, a method that cannot be overridden, or a class that cannot be extended. finally: a block that runs after try/catch whatever happens. finalize(): an old Object hook called by the garbage collector; it is deprecated for removal (since Java 18). Use try-with-resources or Cleaner instead. Note final on a reference does not make the object immutable.
19. How do you make a class immutable?
Make the class and fields final, set everything in the constructor, expose no setters, and copy mutable inputs and outputs. Since Java 16 a record does most of that for you and generates equals, hashCode and toString; a compact constructor can validate.
Q19 Point[x=1, y=2], equals=true, hashCode equal=true
Q19 compact constructor rejects: x < 0Source: JavaVivaDemo.java, section q19.
20. What is the equals and hashCode contract?
Equal objects must have equal hash codes. If you override equals but not hashCode, hash-based collections treat equal objects as different: the set below holds two “equal” objects. See HashMap internal working in Java for why the bucket is chosen by hash first.
Q20 equals without hashCode: set size 2; with hashCode: set size 1Source: JavaVivaDemo.java, section q20.
21. What is the difference between shallow and deep copy?
A shallow copy (the default clone()) copies the fields but shares the objects they refer to. A deep copy duplicates the referenced objects too. After changing the original’s array, the shallow copy sees the change and the deep copy does not.
Q21 after a.data[0]=99: shallow copy sees 99, deep copy sees 1Source: JavaVivaDemo.java, section q21.
22. What are the kinds of nested classes?
Static nested (no outer instance), inner (holds a reference to an outer instance), local (declared in a method) and anonymous (an unnamed one-off subclass; lambdas replace most uses for functional interfaces). An inner class keeps its outer object alive, a classic memory-leak source.
23. What are pattern matching for instanceof, sealed types and pattern switch?
instanceof with a binding variable (Java 16) removes the cast. sealed interfaces (Java 17) list exactly which classes may implement them. switch over types with guards (when) is final in Java 21; with a sealed hierarchy the compiler can check that you covered every case. See Java 21 features.
Q23 instanceof pattern: HELLO
Q23 circle r=2.0 | big circle | square 3.0 | string of length 3 | something elseSource: JavaVivaDemo.java, section q23.
24. Why does Java not allow multiple inheritance of classes?
To avoid the diamond problem: two parents with the same method and no rule for which to inherit. Interfaces allow multiple inheritance of type, and with default methods a class that inherits two conflicting defaults must override the method and choose (A.super.m()) or the code does not compile.
Exceptions
Exceptions are asked about for their rules, and the rules are enforced by the compiler, so two answers show the real javac messages.
25. What is the difference between checked and unchecked exceptions?
Checked exceptions (subclasses of Exception but not RuntimeException) must be caught or declared with throws; the compiler enforces it. Unchecked ones (RuntimeException, Error) are not checked. Calling a method that throws IOException without handling it is a compile error, shown for real below.
import java.io.*;
public class CheckedDemo {
static void read() throws IOException { throw new IOException("disk"); }
public static void main(String[] args) {
read(); // checked exception not handled
try {
read();
} catch (Exception e) { // too general, caught first
} catch (IOException e) { // unreachable
}
}
}CheckedDemo.java:11: error: exception IOException has already been caught
} catch (IOException e) { // unreachable
^
CheckedDemo.java:7: error: unreported exception IOException; must be caught or declared to be thrown
read(); // checked exception not handled
^
2 errorsSource: CheckedDemo.java, section q25.
26. How do try, catch and finally interact? What if finally has a return?
finally runs whether or not an exception occurs. If the try block returns a value, the value is fixed first; a later change in finally does not alter it. A return inside finally replaces the try’s return (and swallows exceptions), which is why it is a code smell.
Q26 finally { return 2 } overrides try { return 1 }: 2
Q26 finally runs after the return value is fixed, x=5
Q26 try { return x } with finally changing x returns 1
Q26 caught ClassCastException
Q26 finally always runsSource: JavaVivaDemo.java, section q26.
27. What is try-with-resources?
Any AutoCloseable declared in the parentheses is closed automatically, in reverse order of opening, before the catch runs, even if the body throws. It replaces finally blocks that close resources and keeps suppressed exceptions.
Q27 open A
Q27 open B
Q27 body
Q27 close B
Q27 close A
Q27 catch boomSource: JavaVivaDemo.java, section q27.
28. What is the difference between throw and throws?
throw is a statement that throws one exception object (throw new IllegalStateException()). throws is part of a method signature and lists the checked exceptions the method may propagate.
29. Does the order of catch blocks matter? What is multi-catch?
Yes: a subclass must be caught before its superclass. Catching Exception first makes a later catch (IOException) unreachable, and the compiler rejects it (see the first error in the javac output of question 25). Multi-catch (catch (A | B e), Java 7) handles unrelated exceptions in one block; the alternatives must not be subclasses of each other.
The real compiler message for this mistake is the first error: line in the CheckedDemo.java output under question 25.
30. How do you write a custom exception?
Extend Exception for a checked one (the caller must react) or RuntimeException for an unchecked one (a programming or unrecoverable error). Provide constructors taking a message and a cause. Prefer unchecked exceptions in modern application code: checked ones leak into every signature up the stack.
31. What is the difference between Error and Exception?
Both extend Throwable. Exception signals conditions an application might handle. Error (OutOfMemoryError, StackOverflowError) signals JVM-level problems; catching them is rarely useful. Unbounded recursion ends in StackOverflowError.
Q31 caught StackOverflowError, depth reached > 1000: true
Q31 StackOverflowError is an Error: true, Exception: falseSource: JavaVivaDemo.java, section q31.
32. What is exception chaining?
Passing the original exception as the cause when you wrap it, so the stack trace shows both. Without the cause you lose the root problem, a very common mistake.
Q32 config invalid <- caused by NumberFormatException: For input string: "abc"Source: JavaVivaDemo.java, section q32.
Collections
Collections questions test whether you know the contract behind the class, so most answers pair a rule with a run.
33. What is the Java Collections Framework?
A set of interfaces (Collection, List, Set, Queue, Deque, and Map separately) and implementations. Map does not extend Collection. The full interview set is in Top 40 Java Collections interview questions.
34. ArrayList or LinkedList?
ArrayList is a resizable array: O(1) random access, O(n) insert or remove in the middle, compact memory. LinkedList is a doubly linked list: O(1) insert at a known node, but O(n) to reach it and heavy per-element overhead. ArrayList is the right default. See Top 40 Java Collections interview questions.
35. How does HashMap work and does it allow nulls?
It hashes the key to pick a bucket, then uses equals within the bucket; since Java 8 a bucket with many collisions can turn into a tree. One null key and any number of null values are allowed. Full internals: HashMap internal working in Java.
Q35 HashMap allows a null key and null value: {null=1, a=null}Source: JavaVivaDemo.java, section q35.
36. HashMap vs Hashtable vs ConcurrentHashMap?
HashMap: not thread-safe, allows nulls. Hashtable: legacy, every method synchronized, no nulls. ConcurrentHashMap: thread-safe with fine-grained concurrency, no null keys or values. Prefer ConcurrentHashMap when threads share a map; see Top 40 Java concurrency interview questions.
Q36 Hashtable.put(null, 1) -> NullPointerException
Q36 ConcurrentHashMap.put("k", null) -> NullPointerExceptionSource: JavaVivaDemo.java, section q36.
37. HashSet vs LinkedHashSet vs TreeSet?
HashSet: no ordering guarantee, O(1). LinkedHashSet: insertion order. TreeSet: sorted order (natural or a Comparator), O(log n). All reject duplicates; the duplicate “apple” appears once.
Q37 HashSet=[banana, apple, pear, fig] LinkedHashSet=[pear, apple, fig, banana] TreeSet=[apple, banana, fig, pear]Source: JavaVivaDemo.java, section q37.
38. What is a fail-fast iterator?
Most collection iterators throw ConcurrentModificationException if the collection is structurally modified during iteration, except through the iterator itself. Use Iterator.remove(), removeIf, or iterate over a copy.
Q38 removing inside for-each -> ConcurrentModificationException
Q38 Iterator.remove() is safe: [1, 3]Source: JavaVivaDemo.java, section q38.
39. Comparable or Comparator?
Comparable gives a class one natural order (compareTo). A Comparator is a separate, reusable ordering you can chain, and is how you sort by several fields. More in Comparable vs Comparator.
Q39 by age then name: [Emp[name=Amy, age=25], Emp[name=Bob, age=30], Emp[name=Zed, age=30]]
Q39 by name descending: [Emp[name=Zed, age=30], Emp[name=Bob, age=30], Emp[name=Amy, age=25]]Source: JavaVivaDemo.java, section q39.
40. Why does add fail on Arrays.asList and List.of?
Arrays.asList is a fixed-size view over the array: you can set but not change the size. List.of is fully immutable. Wrap in new ArrayList<>(...) for a modifiable copy.
Q40 Arrays.asList: set works [9, 2, 3], add -> UnsupportedOperationException
Q40 List.of(...).set -> UnsupportedOperationExceptionSource: JavaVivaDemo.java, section q40.
41. What happens if you mutate a HashMap key?
The entry stays in the bucket for the old hash, so lookups with either the mutated or a fresh equal key miss, and the entry is effectively lost. Use immutable keys.
Q41 after mutating the key: get(k)=null, get(new Key(1))=null, size=1Source: JavaVivaDemo.java, section q41.
42. Does a PriorityQueue iterate in sorted order?
No. It is a binary heap: only the head is guaranteed to be the smallest. poll() returns elements in order; toString() and iteration do not.
Q42 toString (heap order, not sorted): [1, 2, 4, 5, 3]
Q42 poll() order: 1 2 3 4 5Source: JavaVivaDemo.java, section q42.
43. What is the difference between Iterator and ListIterator?
Iterator goes forward and can remove. ListIterator works on lists only, goes both ways, and can add, set and report indexes.
44. What is the difference between Collection and Collections?
Collection is the root interface of lists, sets and queues. Collections is a utility class of static helpers (sort, unmodifiableList, synchronizedList). For stream-based processing of collections see Top 50 Java Stream API coding interview questions.
Threads and concurrency
Thread questions reward demonstrations: a race you can reproduce is worth three definitions.
45. What is the difference between a process and a thread?
A process has its own address space; a thread is a unit of execution inside a process and shares its heap with other threads, so threads are cheaper but need synchronisation. Each thread has its own stack.
46. How do you create a thread?
Pass a Runnable to a Thread, or (better) submit a Runnable or Callable to an ExecutorService. Callable returns a value and may throw a checked exception. Extending Thread ties the task to the thread; avoid it.
Q46 Runnable lambda on worker-1
Q46 Callable via executor returned 42Source: JavaVivaDemo.java, section q46.
47. What is the difference between start() and run()?
start() creates a new thread that runs run(). Calling run() directly executes it on the calling thread like any method. The first line is the calling thread, main; the second is T.
Q47 body runs on main
Q47 body runs on TSource: JavaVivaDemo.java, section q47.
48. What are the thread states?
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED. The demo shows a thread before start (NEW), after finishing (TERMINATED), and parked inside Object.wait() (WAITING).
Q48 new=NEW, after join=TERMINATED, inside wait()=WAITINGSource: JavaVivaDemo.java, section q48.
49. What is a race condition and how does synchronized fix it?
count++ is read, add, write: two threads can interleave and lose updates. synchronized lets one thread at a time through; AtomicInteger does the update as one atomic operation. Two threads added 200,000 each: the plain int lost updates, the other two did not. The plain-int figure changes on every run; only the correct totals are stable.
Q49 expected 400000: plain int++=397582, AtomicInteger=400000, synchronized=400000Source: JavaVivaDemo.java, section q49. The unsynchronized total differs from run to run.
50. What does volatile do, and is it enough?
volatile guarantees that a write is visible to other threads and forbids reordering around it. It does not make count++ atomic. Use it for flags (stop), and use atomics or locks for read-modify-write.
51. sleep() vs wait()?
Thread.sleep pauses the current thread and keeps any locks it holds. Object.wait must be called inside synchronized, releases that monitor, and waits for notify/notifyAll. Always call wait in a loop that rechecks the condition.
52. What is a deadlock?
Two or more threads each hold a lock the other needs and wait forever. It needs mutual exclusion, hold-and-wait, no preemption and circular wait. Prevent it by always acquiring locks in the same global order, or use timeouts with tryLock. More: Top 40 Java concurrency interview questions.
53. Why use an ExecutorService?
It reuses threads, bounds concurrency and separates submitting work from running it. Always shut it down, or the JVM may not exit.
Q53 invokeAll results in submission order: [task1, task2, task3], terminated=trueSource: JavaVivaDemo.java, section q53.
54. What are virtual threads?
Cheap threads managed by the JVM (final in Java 21). Blocking in a virtual thread parks it without holding an OS thread, so one JVM can run tens of thousands of blocking tasks. They are always daemon threads. The demo starts ten thousand virtual threads that each sleep 10 ms and collects all their results. See Top 40 Java concurrency interview questions and Virtual Threads on Spring Boot 4.1: The Benchmarks, Re-Run, and the Pinning Advice That Expired.
Q54 virtual=true, daemon=true
Q54 10,000 virtual threads sleeping 10 ms each finished, sum=49995000Source: JavaVivaDemo.java, section q54.
JDBC
JDBC questions check you know the sequence and the safe defaults. These answers ran against H2 (an in-memory database), not MySQL, so SQL dialect details may differ.
55. What are the steps to connect to a database with JDBC?
Get a Connection (DriverManager or a DataSource), create a Statement or PreparedStatement, execute, read the ResultSet, and close everything (try-with-resources). Modern drivers register themselves, so Class.forName is no longer needed. The demo runs on an in-memory H2 database; with MySQL or PostgreSQL only the URL, user and driver jar change.
Q55 row: 2 Ravi
Q55 row: 3 Meera
Q55 driver=H2, autoCommit default=trueSource: JdbcVivaDemo.java, section q55.
56. Statement vs PreparedStatement: which is safer and why?
PreparedStatement sends the SQL and the parameters separately, so input is never parsed as SQL: that prevents SQL injection and lets the database reuse the plan. Concatenating input into a Statement lets x' OR '1'='1 match every row.
Q56 input "x' OR '1'='1": Statement returned 3 rows, PreparedStatement returned 0Source: JdbcVivaDemo.java, section q56.
57. How do transactions work in JDBC?
Connections start in auto-commit mode: every statement commits. Call setAutoCommit(false), run the statements, then commit() or rollback(). The rollback restored both salaries; the commit applied both. In Spring you use @Transactional instead; see @Transactional in Spring: Propagation, Isolation, and the Six Ways It Silently Does Nothing.
Q57 after rollback salaries are 50000 and 60000
Q57 after commit salaries are 49000 and 61000Source: JdbcVivaDemo.java, section q57.
58. What is batch processing in JDBC?
addBatch() queues parameter sets and executeBatch() sends them together, returning one update count per statement. It cuts round-trips for bulk inserts.
Q58 executeBatch returned [1, 1, 1, 1, 1]
Q58 rows now: 8Source: JdbcVivaDemo.java, section q58.
59. What are the ResultSet types?
TYPE_FORWARD_ONLY (default), TYPE_SCROLL_INSENSITIVE and TYPE_SCROLL_SENSITIVE, combined with CONCUR_READ_ONLY or CONCUR_UPDATABLE. A scrollable result set lets you move with first(), last() and absolute(); support varies by driver.
Q59 scrollable ResultSet: first=Asha, last=temp14Source: JdbcVivaDemo.java, section q59.
60. What is connection pooling and what does Spring Boot use?
Opening a database connection is slow, so a pool keeps a set of open connections and lends them out. Spring Boot uses HikariCP by default when it is on the classpath. In a Spring Boot app you do not call DriverManager; you configure spring.datasource.* and inject a DataSource. See the Spring Boot CRUD with MySQL post.
Common interview questions
Which topics are asked most in a Java viva?
The JVM and string pool, OOP and polymorphism, exceptions, collections (especially HashMap) and threads. Questions 5, 14, 20, 26, 35 and 49 here are the usual ones.
How do I prepare for a Java oral exam?
Run each example, change one line, and predict the output before running it again. An examiner who sees you explain a changed result trusts the rest.
Is this enough for a Java interview?
It covers the language. For interviews also practise Top 40 Java Collections interview questions, Top 40 Java concurrency interview questions and Top 50 Java Stream API coding interview questions.
Common mistakes
- Memorising definitions without a demo. The follow-up question is always “what happens if…”.
- Saying Java passes objects by reference. It passes a copy of the reference (question 9).
- Overriding
equalswithouthashCode(question 20). - Calling
run()instead ofstart()(question 47). - Concatenating user input into SQL (question 56).
FAQ
Where can I download the programs?
Each answer links the Java file it came from: JavaVivaDemo.java, JdbcVivaDemo.java and CheckedDemo.java.
Which Java version is this for?
Java 21 syntax (records, pattern switch, virtual threads). Questions 1 to 22 also work on older versions where noted.
Do the JDBC answers apply to MySQL?
The JDBC API is the same. Only the URL and driver differ; this page ran on H2, so database-specific behaviour was not tested.
Further reading
- JavaVivaDemo.java and JdbcVivaDemo.java
- Top 60 8086 viva questions and answers
- Top 40 Java Collections interview questions
- Top 40 Java concurrency interview questions
- Top 50 Java Stream API coding interview questions
- 30 Java string programs for interviews
- HashMap internal working in Java
- Comparable vs Comparator
- OOP concepts in Java
- Number programs in Java
- Pattern programs in Java
- Array programs in Java
- Spring Boot tutorial for beginners
No Comments yet!