Java 核心语法

📅 2026/7/12 9:47:17 👁️ 阅读次数 📝 编程学习
Java 核心语法

01 Java 核心语法

这一章解决“Java 代码读写不费力”的基础问题。

1. Java 程序基本结构

packagecom.example.demo;importjava.util.List;publicclassUserService{privatefinalUserRepositoryrepository;publicUserService(UserRepositoryrepository){this.repository=repository;}publicList<User>loadUsers(){returnrepository.getUsers();}}

必须理解:

  • package:类的命名空间,和目录结构通常对应。
  • import:引入其他包里的类,不改变类本身归属。
  • public class UserService:一个公开类,类名通常和文件名一致。
  • 字段:对象持有的状态。
  • 构造器:对象创建时初始化依赖。
  • 方法:对象暴露的行为。

Android 中的对应场景:

  • ActivityServiceBroadcastReceiver都是类。
  • View.OnClickListenerRunnable是接口。
  • R.javaBuildConfig是构建时生成的类。

2. 基本类型和引用类型

Java 类型分两大类。

类型例子存储含义
基本类型intlongbooleandoublechar变量直接表示值
引用类型StringUserList<User>、数组变量保存对象引用

基本类型:

类型常用场景注意点
byte二进制、协议、文件范围小,容易溢出
short少见一般不用
int计数、索引、状态码默认整数类型
long时间戳、数据库 id字面量加L
float图形、坐标字面量加f
double普通小数计算默认浮点类型
char单个 UTF-16 code unit不等于完整 Unicode 字符概念
boolean条件判断只能是true/false

引用类型重点:

Usera=newUser("Tom");Userb=a;b.setName("Jerry");// a 和 b 指向同一个对象,所以 a.getName() 也是 Jerry

你必须形成这个直觉:引用变量不是对象本身,它像一个指向对象的句柄。方法传参时传的是“引用的副本”,不是对象副本。

3. 装箱和拆箱

intcount=10;Integerboxed=count;// 自动装箱intraw=boxed;// 自动拆箱

容易踩坑:

Integervalue=null;intcount=value;// NullPointerException

Android 常见场景:

  • Bundle、数据库字段、JSON 解析可能返回包装类型。
  • IntegerLong可以是nullintlong不可以。
  • 做 UI 绑定前要明确是否允许空值。

建议:

  • 业务状态必须有值时用基本类型。
  • 数据来源可能缺失时用包装类型,并在边界处理空值。
  • 不要用==比较包装对象的值,使用equals或拆成基本类型。

4. 类型转换

longa=100;// int 自动提升为 longintb=(int)a;// long 转 int 需要强转

强转不是“安全转换”,只是告诉编译器允许转换,运行时仍可能出错或丢数据。

Objectobj="hello";Stringtext=(String)obj;// 可以Objectvalue=123;Stringwrong=(String)value;// ClassCastException

安全写法:

if(objinstanceofString){Stringtext=(String)obj;}

Android 常见场景:

  • findViewById返回具体 View 类型时可能需要转换。
  • Intentextra、BundleRecyclerView.ViewHolder都经常涉及类型边界。
  • 反射、系统服务、AIDL 返回值更要检查类型。

5. 字符串

String是不可变对象。

Strings="a";s=s+"b";

这里不是把原对象改成"ab",而是创建了新字符串并让s指向新对象。

常见规则:

  • 内容比较用equals
  • 常量在左侧可避免 NPE:"ok".equals(status)
  • 大量拼接用StringBuilder
  • 日志拼接在高频路径要注意额外对象创建。
StringBuilderbuilder=newStringBuilder();for(Stringitem:items){builder.append(item).append(',');}Stringresult=builder.toString();

Android 常见场景:

  • UI 文案用资源,不要硬编码。
  • 多语言不要用字符串拼接句子,优先使用格式化资源。
  • 日志里不要打印隐私字段、token、手机号完整值。

6. 数组

int[]numbers=newint[3];numbers[0]=10;String[]names={"Tom","Jerry"};

特点:

  • 长度固定。
  • 可以按索引快速访问。
  • 越界会抛ArrayIndexOutOfBoundsException
  • 数组是对象。

数组和集合选择:

需求选择
固定长度、性能敏感、基础数据数组
长度变化、增删多、业务列表List
唯一性Set
key-value 查询Map

Android 中业务层一般优先用集合,底层图像、音频、协议、Parcel、数据库游标处理时数组更多。

7. 控制流

if(isLogin){showHome();}else{showLogin();}
switch(status){case0:showLoading();break;case1:showContent();break;default:showError();break;}

注意:

  • Java 传统switch需要break,否则会继续执行后面的 case。
  • 条件复杂时,优先提取成有名字的方法。
  • 状态多时,考虑 enum、状态对象或策略模式,避免巨型if/else

8. 方法和参数传递

publicvoidrename(Useruser){user.setName("Tom");}publicvoidreplace(Useruser){user=newUser("Jerry");}

Java 只有值传递。引用类型传递的是引用值的副本。

  • rename修改的是同一个对象的内部状态,外部能看到变化。
  • replace只是让方法内部的局部变量指向新对象,外部引用不变。

这个点非常重要,很多 Android bug 来自“以为传进去会替换外部对象”。

9. 重载

voidlog(Stringmessage){}voidlog(Stringtag,Stringmessage){}voidlog(Throwableerror){}

重载由参数列表决定,不由返回值决定。

intgetValue(){return1;}// String getValue() { return "1"; } // 只改返回值不能构成重载

建议:

  • 重载过多会降低可读性。
  • 参数含义相近但业务差异大时,使用不同方法名。
  • 多个 boolean 参数是坏味道,容易调用错。

10. 构造器和初始化顺序

publicclassUser{privatefinalStringname;publicUser(Stringname){this.name=name;}}

初始化顺序简化记忆:

  1. 父类静态字段/静态代码块
  2. 子类静态字段/静态代码块
  3. 父类实例字段/实例代码块
  4. 父类构造器
  5. 子类实例字段/实例代码块
  6. 子类构造器

Android 场景:

  • Activity不要在构造器里做业务初始化,生命周期还没开始。
  • 依赖Context的初始化通常放在onCreate或注入框架里。
  • 静态初始化不要做重 IO、反射扫描、数据库打开,容易拖慢启动。

11.static

static属于类,不属于某个对象。

publicclassConstants{publicstaticfinalintMAX_COUNT=100;}

常见用途:

  • 常量
  • 工具方法
  • 静态工厂方法
  • 单例持有者

Android 风险:

publicclassBadStore{publicstaticActivitycurrentActivity;}

静态字段持有Activity很容易内存泄漏。Activity生命周期结束后,如果还有静态引用指向它,GC 无法回收。

12.final

final可以修饰变量、方法、类。

finalintcount=1;// 不能重新赋值finalList<String>list=items;// 引用不能换,但 list 内容仍可变
publicfinalclassImmutableUser{privatefinalStringname;}

理解重点:

  • final修饰引用,不等于对象不可变。
  • 真正不可变对象需要字段私有、构造后不变、不暴露可变内部对象。
  • 并发场景下,不可变对象更容易保证线程安全。

13. 访问控制

修饰符同类同包子类任意位置
privateyesnonono
package-privateyesyesnono
protectedyesyesyesno
publicyesyesyesyes

没有写修饰符就是 package-private。

建议:

  • 默认尽量小权限。
  • 字段优先private
  • 对外暴露稳定方法,不直接暴露可变字段。
  • Android module 边界清晰时,包可见能力很好用。

14. 注解

常见注解:

@OverridepublicStringtoString(){return"User";}

Android 常见注解:

  • @NonNull@Nullable
  • @MainThread@WorkerThread
  • @UiThread
  • @IntDef@StringDef
  • @SuppressWarnings

注解本身不一定改变运行行为,但可以帮助编译器、lint、IDE、框架做检查或生成代码。

15. 本章自测

  1. intInteger的区别是什么?什么时候会发生 NPE?
  2. String a = "x"; a += "y";是否修改了原字符串?
  3. Java 方法传对象时,是值传递还是引用传递?
  4. static final List<String>是否表示列表内容不可变?
  5. private、默认访问、protectedpublic的边界是什么?
  6. 为什么 Android 中不建议静态持有Activity
  7. ==equals分别比较什么?
  8. 数组和List的核心差异是什么?