Appearance
基础语法
你好,Java!写出第一行代码,从变量到方法,从原理到面试 🚀
🎯 场景:第一次运行 Java
┌─────────────────────────────────────────────────────────────────┐
│ 你好,Java 世界! │
├─────────────────────────────────────────────────────────────────┤
│ │
│ public class HelloWorld { │
│ public static void main(String[] args) { │
│ System.out.println("Hello, World!"); │
│ } │
│ } │
│ │
│ 编译:javac HelloWorld.java → HelloWorld.class │
│ 运行:java HelloWorld → Hello, World! │
│ │
└─────────────────────────────────────────────────────────────────┘这段代码告诉我们什么?
- Java 是编译型语言,需要先编译后运行
main方法是程序入口System.out.println是输出语句- 所有代码都要写在类里面(面向对象思想)
💡 实战场景:为什么 Java 能"一次编写,到处运行"?
- 因为有 JVM!编译后的 .class 文件在任何装有 JVM 的机器上都能运行
- 这就是 Java 的平台无关性!
变量与数据类型
基本数据类型
💡 实战场景:为什么需要不同的数据类型?
想象一下内存是停车场:
- byte 就是小型车位,只能停自行车(-128 ~ 127)
- int 是标准车位,大部分车都能停
- long 是大型车位,大巴车才需要
- float/double 是计时车位,精确到秒
用对数据类型,省空间又高效!
Java 有 8 种基本数据类型,分为四大类:
| 类别 | 类型 | 占用空间 | 取值范围 | 默认值 | 面试点 |
|---|---|---|---|---|---|
| 整数 | byte | 1 字节 | -128 ~ 127 | 0 | 范围计算 |
| 整数 | short | 2 字节 | -32768 ~ 32767 | 0 | 很少使用 |
| 整数 | int | 4 字节 | -2³¹ ~ 2³¹-1 | 0 | 高频面试 |
| 整数 | long | 8 字节 | -2⁶³ ~ 2⁶³-1 | 0L | 金额计算用 BigDecimal |
| 浮点 | float | 4 字节 | -3.4e38 ~ 3.4e38 | 0.0f | 精度问题 |
| 浮点 | double | 8 字节 | -1.7e308 ~ 1.7e308 | 0.0d | 最常用 |
| 字符 | char | 2 字节 | 0 ~ 65535 | '\u0000' | Unicode |
| 布尔 | boolean | 1 位 | true/false | false | 面试常问 |
💡 实战提示:金额计算不要用 float/double,用 BigDecimal!
java
// ❌ 错误:浮点数精度问题
System.out.println(0.1 + 0.2); // 0.30000000000000004
// ✅ 正确:使用 BigDecimal
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 0.3引用数据类型
java
// 字符串 - 面试高频考点
String s1 = "hello"; // 字面量,存在字符串常量池
String s2 = new String("hello"); // new 对象,堆中创建
// 数组
int[] arr = {1, 2, 3};
String[] names = new String[5];
// 类和接口
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();💡 面试点:String 为什么不可变?字符串常量池了解吗?
java
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1 == s2); // true - 指向常量池同一对象
System.out.println(s1 == s3); // false - 堆中新建对象
System.out.println(s1.equals(s3)); // true - 内容相同运算符
算术运算符
💡 实战场景:点外卖时的价格计算
java
// 场景:购物车结算
double originalPrice = 99.9; // 原价
int discount = 8; // 8折
double finalPrice = originalPrice * discount / 10; // 79.92
// 积分计算
int points = 1000;
int extraPoints = points % 100; // 取余,够100积分的零头java
int a = 10, b = 3;
System.out.println(a + b); // 13
System.out.println(a - b); // 7
System.out.println(a * b); // 30
System.out.println(a / b); // 3 (整数除法)
System.out.println(a % b); // 1 (取余)
System.out.println(a++); // 10 (先取值后加1)
System.out.println(++a); // 12 (先加1后取值)关系运算符
💡 实战场景:用户年龄验证
java
int age = 20;
// if 条件判断
if (age >= 18) {
System.out.println("成年人");
} else {
System.out.println("未成年");
}java
System.out.println(5 > 3); // true
System.out.println(5 == 5); // true
System.out.println(5 != 3); // true逻辑运算符
💡 实战场景:登录校验
java
// 场景:用户登录条件判断
String username = "admin";
String password = "123456";
int failedAttempts = 3;
// && 短路与:用户名对 AND 密码对 AND 失败次数少于5
if (username.equals("admin") && password.equals("123456") && failedAttempts < 5) {
System.out.println("登录成功!");
}java
// && 和 & 的区别
int x = 5;
if (x > 3 && x++ > 0) { } // 短路与,x++不执行,x=5
if (x > 3 & x++ > 0) { } // 非短路与,x++执行,x=6
// || 和 | 的区别同理💡 面试点:&& 和 & 的区别?什么情况下不能用 &&?
位运算符
java
int a = 6; // 二进制: 110
int b = 3; // 二进制: 011
System.out.println(a & b); // 2 (110 & 011 = 010)
System.out.println(a | b); // 7 (110 | 011 = 111)
System.out.println(a ^ b); // 5 (110 ^ 011 = 101)
System.out.println(~a); // -7 (按位取反)
System.out.println(a << 1); // 12 (左移1位,相当于乘2)
System.out.println(a >> 1); // 3 (右移1位,相当于除2)💡 实战应用:用位运算判断奇偶数,比 % 更高效
java
// ❌ 用 % 判断
if (n % 2 == 1) { ... }
// ✅ 用位运算判断 (n & 1) == 1
if ((n & 1) == 1) { ... } // 奇数控制流程
条件语句
💡 实战场景:电商网站的优惠活动
java
// 场景:双十一优惠活动
double totalAmount = 888.0;
// 普通顾客
double discount = 0.9; // 9折
if (totalAmount >= 500) {
discount = 0.8; // 满500打8折
}
if (totalAmount >= 1000) {
discount = 0.7; // 满1000打7折
}
System.out.println("实付:" + totalAmount * discount);if-else 简化写法(三元运算符)
java
// ❌ 啰嗦写法
int max;
if (a > b) {
max = a;
} else {
max = b;
}
// ✅ 简洁写法
int max = (a > b) ? a : b;💡 面试点:三元运算符表达式1和表达式2类型不一致怎么办?
java
Object o = true ? new Integer(1) : new Double(2.0);
// 输出: 1.0 - 自动类型提升为 Doubleswitch 表达式(Java 14+)
java
// 传统 switch
switch (day) {
case 1:
case 2:
case 3:
System.out.println("工作日");
break;
case 4:
case 5:
System.out.println("工作日");
break;
default:
System.out.println("周末");
}
// 新版 switch (Java 14+)
String result = switch (day) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "周末";
default -> "无效日期";
};循环语句
for 循环的几种形式
java
// 普通 for 循环
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 增强 for 循环 (for-each) - 面试常问
int[] arr = {1, 2, 3, 4, 5};
for (int num : arr) {
System.out.println(num);
}
// 带标签的循环 (break 外层)
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break outer; // 跳出外层循环
}
System.out.println(i + "," + j);
}
}💡 面试点:for-each 和普通 for 循环的区别?什么时候不能用 for-each?
java
// ❌ for-each 无法修改数组元素
for (int num : arr) {
num = num * 2; // 修改的是局部变量,不影响原数组
}
// ❌ for-each 无法获取索引
for (int num : arr) {
System.out.println(num); // 不知道当前是第几个元素
}
// ✅ 需要修改元素或获取索引时,用普通 for
for (int i = 0; i < arr.length; i++) {
arr[i] *= 2;
}循环控制技巧
java
// 跳过当前迭代 (continue)
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
System.out.println(i); // 打印奇数
}
// 双重循环标志位
boolean found = false;
for (int i = 0; i < 100 && !found; i++) {
for (int j = 0; j < 100; j++) {
if (arr[i][j] == target) {
found = true;
break;
}
}
}方法
方法定义与调用
💡 实战场景:计算电商订单总价
java
public class OrderCalculator {
// 场景:计算订单总价(含折扣、优惠券)
public double calculateTotal(double originalPrice, int quantity, double discount) {
// 基础价格 * 数量 * 折扣
return originalPrice * quantity * discount;
}
// 场景:判断是否包邮
public boolean isFreeShipping(double totalPrice) {
return totalPrice >= 99.0; // 满99包邮
}
// 可变参数方法 - 灵活计算多个商品总价
public double sumPrices(double... prices) {
double total = 0;
for (double price : prices) {
total += price;
}
return total;
}
}java
public class MethodDemo {
// 无返回值方法
public void printMessage(String msg) {
System.out.println(msg);
}
// 有返回值方法
public int add(int a, int b) {
return a + b;
}
// 可变参数方法 (Java 5+)
public int sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
// 方法重载 - 参数个数、类型或顺序不同
public void print(int num) { }
public void print(String str) { }
public void print(int num, String str) { }
}💡 面试点:方法重载和重写的区别?
| 区别 | 重载 (Overload) | 重写 (Override) |
|---|---|---|
| 发生位置 | 同一个类 | 父子类之间 |
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须不同 | 必须相同 |
| 返回类型 | 可以不同 | 必须相同或子类型 |
| 访问修饰符 | 可以不同 | 不能更严格 |
| 抛出异常 | 可以不同 | 不能抛出新异常 |
值传递还是引用传递?
💡 面试高频题:Java 是值传递还是引用传递?
java
public class PassByValue {
public void changePrimitive(int num) {
num = 100; // 只改变局部变量
}
public void changeString(String str) {
str = "changed"; // 局部变量指向新对象
}
public void changeArray(int[] arr) {
arr[0] = 100; // 改变了原数组内容
arr = new int[]{999}; // 局部变量指向新数组
}
public static void main(String[] args) {
PassByValue demo = new PassByValue();
int num = 10;
demo.changePrimitive(num);
System.out.println(num); // 10 - 原值不变
String str = "original";
demo.changeString(str);
System.out.println(str); // original - 原值不变
int[] arr = {1, 2, 3};
demo.changeArray(arr);
System.out.println(arr[0]); // 100 - 数组内容被修改
}
}结论:Java 永远是值传递。引用类型传递的是引用的副本(地址值)。
数组
数组声明与初始化
java
// 声明方式
int[] arr1; // 推荐写法
int arr2[]; // C 风格,不推荐
// 初始化方式
int[] arr1 = new int[5]; // 默认值 0
int[] arr2 = new int[]{1, 2, 3}; // 指定初始值
int[] arr3 = {1, 2, 3, 4, 5}; // 简写(静态初始化)
String[] names = {"Alice", "Bob", "Carol"};数组常用操作
java
int[] arr = {64, 25, 12, 22, 11};
// 获取长度
int length = arr.length; // 5
// 遍历数组
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 查找元素 (线性查找)
int find = 22;
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == find) {
index = i;
break;
}
}
// 排序 (Arrays 工具类)
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [11, 12, 22, 25, 64]
// 二分查找 (前提:已排序)
int index = Arrays.binarySearch(arr, 22); // 2二维数组
java
// 定义方式
int[][] matrix = new int[3][4]; // 3行4列
int[][] arr = {{1,2}, {3,4}, {5,6}}; // 静态初始化
// 遍历
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}关键字总结
static 关键字
💡 面试高频点:static 关键字的作用?
java
public class StaticDemo {
// 1. 静态变量 - 所有对象共享
private static int count = 0;
// 2. 静态方法 - 可直接通过类名调用
public static int getCount() {
return count;
}
// 3. 静态代码块 - 类加载时执行一次
static {
System.out.println("类加载时执行");
// 初始化静态资源
}
// 4. 静态内部类
public static class Inner {
public void show() {
System.out.println("静态内部类方法");
}
}
}
// 调用方式
int count = StaticDemo.getCount(); // 无需创建对象
StaticDemo.Inner inner = new StaticDemo.Inner();static 内存图解:
┌─────────────────────────────────────────┐
│ 堆内存 │
│ ┌─────────────────────────────────┐ │
│ │ 对象1 (count=1) │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ 对象2 (count=2) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 方法区 (Method Area) │
│ ┌─────────────────────────────────┐ │
│ │ static count = 2 (共享) │ │
│ │ static getCount() │ │
│ │ static {} 代码块 │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘final 关键字
java
// 1. final 变量 - 常量,赋值后不能改变
final int NUM = 100;
// NUM = 200; // 编译错误
// 2. final 方法 - 不能被重写
public final void method() { }
// 3. final 类 - 不能被继承
public final class String { }
// 4. final 参数 - 方法内不能修改
public void test(final int num) {
// num = 100; // 编译错误
}
// 面试点:final 修饰 String 有什么效果?
// String 被 final 修饰,不能被继承,保证安全性总结
基础语法核心知识点:
| 知识点 | 面试频率 | 实战重要性 |
|---|---|---|
| 基本数据类型 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 运算符 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 控制流程 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 方法参数传递 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 数组 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| static 关键字 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| final 关键字 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
⚠️ 易错点提醒:
- 浮点数比较不用
==,用BigDecimal - switch 支持 String (Java 7+)
- for-each 不能修改元素和获取索引
- Java 永远是值传递
- String 是不可变对象