Ubuntu入门学习教程,从入门到精通,Ubuntu 22.04中的Java与Android开发环境 (20)

Ubuntu 22.04中的Java与Android开发环境 - 详细知识点总结

1. Java开发

1.1 Java的特点

平台无关性

  • Java程序编译成字节码(.class文件)
  • 通过JVM(Java虚拟机)在不同平台上运行相同的字节码
  • "一次编写,到处运行"(Write Once, Run Anywhere)

面向对象

  • 封装:将数据和操作数据的方法绑定在一起
  • 继承:子类继承父类的特性和行为
  • 多态:同一操作作用于不同对象产生不同行为

内存管理

  • 自动垃圾回收(GC)机制
  • 开发者无需手动释放内存
  • 减少内存泄漏风险

丰富的标准库

  • 集合框架(Collections Framework)
  • 并发工具包(java.util.concurrent)
  • I/O和NIO
  • 网络编程API
  • 反射机制

安全性

  • 沙箱安全模型
  • 字节码验证
  • 安全管理器
  • 加密API

多线程支持

  • 内置多线程API
  • 同步机制
  • 线程池
  • Future/Promise模式

1.2 Java体系

组件 描述 用途
JDK (Java Development Kit) Java开发工具包 编写、编译和运行Java程序
JRE (Java Runtime Environment) Java运行环境 仅运行Java程序
JVM (Java Virtual Machine) Java虚拟机 执行Java字节码
Java SE (Standard Edition) 标准版 桌面和服务器应用开发
Java EE (Enterprise Edition) 企业版 企业级Web应用和分布式系统
Java ME (Micro Edition) 微型版 嵌入式和移动设备开发

JDK主要组件:

  • javac: Java编译器,将.java源文件编译成.class字节码
  • java: Java启动器,运行编译后的Java程序
  • javadoc: 生成API文档
  • jar: 打包Java类文件
  • jdb: Java调试器
  • jconsole: 监控JVM性能
  • jvisualvm: 可视化性能分析工具

1.3 安装JDK

1.3.1 OpenJDK安装 (推荐)
bash 复制代码
# 1. 更新软件包列表
sudo apt update

# 2. 安装OpenJDK 17 (Ubuntu 22.04默认版本)
sudo apt install openjdk-17-jdk -y

# 3. 验证安装
java -version
# 预期输出:
# openjdk version "17.0.8" 2023-07-18
# OpenJDK Runtime Environment (build 17.0.8+7-Ubuntu-122.04)
# OpenJDK 64-Bit Server VM (build 17.0.8+7-Ubuntu-122.04, mixed mode, sharing)

javac -version
# 预期输出: javac 17.0.8
1.3.2 Oracle JDK安装 (可选)
bash 复制代码
# 1. 添加Oracle JDK PPA
sudo add-apt-repository ppa:linuxuprising/java
sudo apt update

# 2. 安装Oracle JDK 17
sudo apt install oracle-java17-installer -y

# 3. 接受许可协议 (自动)
sudo apt install oracle-java17-set-default -y

# 4. 验证安装
java -version
# 预期输出应显示Oracle JDK版本
1.3.3 配置环境变量

Ubuntu 22.04通常自动配置JDK环境变量,但可以手动验证或修改:

bash 复制代码
# 1. 查找Java安装路径
sudo update-alternatives --config java
# 输出示例: /usr/lib/jvm/java-17-openjdk-amd64/bin/java

# 2. 设置JAVA_HOME (通常已自动设置,可验证)
echo $JAVA_HOME
# 如果为空,编辑~/.bashrc或/etc/environment
# 添加: export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

-- 对于大数据环境,设置 JAVA_HOME 非常重要。您可以将以下行添加到您的 ~/.bashrc 或 ~/.profile 文件中来设置它:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

# 3. 使配置生效
source ~/.bashrc
# 或
source /etc/environment

# 4. 验证JAVA_HOME
echo $JAVA_HOME
# 预期输出: /usr/lib/jvm/java-17-openjdk-amd64

1.4 管理Java版本

1.4.1 安装多个Java版本
bash 复制代码
# 1. 安装OpenJDK 8
sudo apt install openjdk-8-jdk -y

# 2. 安装OpenJDK 11
sudo apt install openjdk-11-jdk -y

# 3. 验证所有已安装版本
update-java-alternatives --list
# 输出示例:
# java-1.11.0-openjdk-amd64      1111       /usr/lib/jvm/java-1.11.0-openjdk-amd64
# java-1.17.0-openjdk-amd64      1711       /usr/lib/jvm/java-1.17.0-openjdk-amd64
# java-1.8.0-openjdk-amd64       1081       /usr/lib/jvm/java-1.8.0-openjdk-amd64
1.4.2 切换Java版本
bash 复制代码
# 1. 交互式选择Java版本
sudo update-alternatives --config java
# 将显示所有Java版本列表,输入对应数字选择

# 2. 设置默认javac版本
sudo update-alternatives --config javac

# 3. 批量切换 (使用update-java-alternatives)
# 切换到Java 17
sudo update-java-alternatives --set java-1.17.0-openjdk-amd64

# 切换到Java 11
sudo update-java-alternatives --set java-1.11.0-openjdk-amd64

# 切换到Java 8
sudo update-java-alternatives --set java-1.8.0-openjdk-amd64
1.4.3 项目级Java版本管理

使用sdkman管理多版本:

bash 复制代码
# 1. 安装sdkman
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

# 2. 列出可用Java版本
sdk list java

# 3. 安装特定版本
sdk install java 17.0.8-open
sdk install java 11.0.19-open
sdk install java 8.0.372-open

# 4. 为特定目录设置Java版本
# 创建~/.sdkmanrc文件
echo "java=17.0.8-open" > ~/.sdkmanrc
# 或使用别名
sdk use java 11.0.19-open

Maven项目中的Java版本配置:

xml 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <source>17</source> <!-- 源代码使用的Java版本 -->
                <target>17</target> <!-- 生成的字节码目标版本 -->
                <release>17</release> <!-- Java 9+ 的等效配置 -->
            </configuration>
        </plugin>
    </plugins>
</build>

Gradle项目中的Java版本配置:

groovy 复制代码
// build.gradle
plugins {
    id 'java'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

tasks.withType(JavaCompile).configureEach {
    options.release = 17
}

1.5 在Ubuntu 22.04上安装IntelliJ IDEA开发Java项目

1.5.1 通过JetBrains Toolbox安装 (推荐)
bash 复制代码
# 1. 下载Toolbox
wget https://download.jetbrains.com/toolbox/jetbrains-toolbox-1.27.3.14802.tar.gz
tar -xzf jetbrains-toolbox-*.tar.gz
rm jetbrains-toolbox-*.tar.gz

# 2. 运行Toolbox安装程序
cd jetbrains-toolbox-*/
./jetbrains-toolbox

# 3. 在UI界面中选择IntelliJ IDEA Community或Ultimate版本安装
# 4. 安装完成后,可从应用菜单启动IntelliJ IDEA
1.5.2 通过Snap安装 (简单方式)
bash 复制代码
# 1. 安装IntelliJ IDEA Community版本
sudo snap install intellij-idea-community --classic

# 2. (可选) 安装Ultimate版本
sudo snap install intellij-idea-ultimate --classic

# 3. 启动IDE
intellij-idea-community
# 或通过应用菜单启动
1.5.3 手动安装
bash 复制代码
# 1. 下载IntelliJ IDEA (社区版)
wget https://download.jetbrains.com/idea/ideaIC-2023.1.3.tar.gz

# 2. 解压到/opt目录
sudo tar -xzf ideaIC-*.tar.gz -C /opt/
sudo mv /opt/idea-IC-* /opt/idea-community

# 3. 创建启动脚本
sudo ln -s /opt/idea-community/bin/idea.sh /usr/local/bin/idea

# 4. 创建桌面快捷方式
cat > ~/.local/share/applications/intellij-idea.desktop <<EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=IntelliJ IDEA Community Edition
Icon=/opt/idea-community/bin/idea.png
Exec="/opt/idea-community/bin/idea.sh" %f
Comment=Develop with pleasure!
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-idea-ce
EOF

# 5. 更新桌面数据库
update-desktop-database ~/.local/share/applications

# 6. 启动IDE
idea
1.5.4 配置IntelliJ IDEA
  1. 首次启动配置:

    • 选择UI主题 (推荐Darcula暗色主题)
    • 配置插件 (建议安装Maven、Gradle、Git、Lombok等)
    • 配置JDK路径 (自动检测或手动指定)
    • 配置Maven/Gradle设置
  2. 关键配置:

    • File > Settings > Editor > Code Style: 配置代码风格
    • File > Settings > Build, Execution, Deployment > Build Tools: 配置构建工具
    • File > Settings > Tools > Terminal: 配置终端,可设置默认shell为bash或zsh
    • File > Settings > Keymap: 自定义快捷键方案
  3. 重要快捷键:

    • Ctrl+Shift+N: 快速打开文件
    • Ctrl+Space: 基本代码补全
    • Ctrl+Shift+Space: 智能类型感知补全
    • Alt+Enter: 显示上下文操作
    • Ctrl+P: 显示参数信息
    • Ctrl+Q: 快速文档查询
    • Shift+F6: 重命名
    • Ctrl+Alt+L: 格式化代码

1.6 开发Java应用程序

1.6.1 创建简单Java应用

示例1: 基本控制台应用 (Hello World)

java 复制代码
/**
 * HelloWorld.java
 * 一个简单的Java应用程序,演示基本语法和结构
 */
public class HelloWorld {
    /**
     * 程序入口点
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 打印Hello World到控制台
        System.out.println("Hello, World!");
        
        // 调用自定义方法
        greetUser("Java Developer");
        
        // 演示基本变量
        int number = 42;
        double pi = 3.14159;
        boolean isJavaFun = true;
        char grade = 'A';
        String language = "Java";
        
        // 格式化输出
        System.out.printf("Number: %d, Pi: %.2f, Language: %s%n", number, pi, language);
        
        // 条件语句示例
        if (isJavaFun) {
            System.out.println("Java is fun!");
        } else {
            System.out.println("Try harder to enjoy Java!");
        }
        
        // 循环示例
        System.out.println("Counting from 1 to 5:");
        for (int i = 1; i <= 5; i++) {
            System.out.println("Count: " + i);
        }
    }
    
    /**
     * 问候用户的方法
     * @param name 用户名
     */
    public static void greetUser(String name) {
        System.out.println("Hello, " + name + "! Welcome to Java programming.");
    }
}

编译运行:

bash 复制代码
# 1. 保存上面代码到HelloWorld.java
# 2. 编译
javac HelloWorld.java

# 3. 运行
java HelloWorld

# 预期输出:
# Hello, World!
# Hello, Java Developer! Welcome to Java programming.
# Number: 42, Pi: 3.14, Language: Java
# Java is fun!
# Counting from 1 to 5:
# Count: 1
# Count: 2
# Count: 3
# Count: 4
# Count: 5
1.6.2 Java核心语法知识点

数据类型:

java 复制代码
// 基本数据类型
byte smallNumber = 127;             // 8位有符号整数
short mediumNumber = 32767;         // 16位有符号整数
int largeNumber = 2147483647;       // 32位有符号整数
long hugeNumber = 9223372036854775807L; // 64位有符号整数,需要L后缀

float floatValue = 3.14f;           // 32位浮点数,需要f后缀
double doubleValue = 3.1415926535;  // 64位浮点数(默认)

char character = 'A';               // 16位Unicode字符
boolean flag = true;                // 布尔值(true/false)

// 引用类型
String text = "Hello Java";         // 字符串
Integer wrappedInt = Integer.valueOf(42); // 包装类
Object obj = new Object();          // 通用对象

控制结构:

java 复制代码
// if-else语句
int score = 85;
if (score >= 90) {
    System.out.println("Grade: A");
} else if (score >= 80) {
    System.out.println("Grade: B"); // 这行会被执行
} else if (score >= 70) {
    System.out.println("Grade: C");
} else {
    System.out.println("Grade: F");
}

// switch语句 (Java 17支持)
String day = "Monday";
switch (day) {
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> 
        System.out.println("Weekday");
    case "Saturday", "Sunday" -> 
        System.out.println("Weekend");
    default -> 
        System.out.println("Invalid day");
}

// for循环
System.out.println("For loop:");
for (int i = 0; i < 5; i++) {
    System.out.println("Iteration: " + i);
}

// 增强型for循环
String[] fruits = {"Apple", "Banana", "Cherry"};
System.out.println("Enhanced for loop:");
for (String fruit : fruits) {
    System.out.println("Fruit: " + fruit);
}

// while循环
int count = 0;
System.out.println("While loop:");
while (count < 3) {
    System.out.println("Count: " + count);
    count++;
}

// do-while循环
int num = 5;
System.out.println("Do-while loop:");
do {
    System.out.println("Number: " + num);
    num--;
} while (num > 0);

面向对象编程:

java 复制代码
/**
 * Employee.java
 * 演示Java的面向对象特性:封装、继承、多态
 */

// 基类
class Person {
    // 封装:私有字段
    private String name;
    private int age;
    
    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getter和Setter方法
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        }
    }
    
    // 方法
    public void introduce() {
        System.out.println("Hi, I'm " + name + ", " + age + " years old.");
    }
}

// 子类:继承Person
class Employee extends Person {
    private String employeeId;
    private double salary;
    
    // 构造函数
    public Employee(String name, int age, String employeeId, double salary) {
        super(name, age); // 调用父类构造函数
        this.employeeId = employeeId;
        this.salary = salary;
    }
    
    // 重写父类方法(多态)
    @Override
    public void introduce() {
        super.introduce(); // 调用父类方法
        System.out.println("Employee ID: " + employeeId + ", Salary: $" + salary);
    }
    
    // 特定于Employee的方法
    public void work() {
        System.out.println(getName() + " is working hard.");
    }
    
    public double getAnnualBonus() {
        return salary * 0.1; // 10% bonus
    }
}

// 接口
interface Workable {
    void startWork();
    void endWork();
}

// 实现接口
class Manager extends Employee implements Workable {
    private int teamSize;
    
    public Manager(String name, int age, String employeeId, double salary, int teamSize) {
        super(name, age, employeeId, salary);
        this.teamSize = teamSize;
    }
    
    @Override
    public void introduce() {
        super.introduce();
        System.out.println("Manages a team of " + teamSize + " people.");
    }
    
    // 实现接口方法
    @Override
    public void startWork() {
        System.out.println(getName() + " starts managing the team.");
    }
    
    @Override
    public void endWork() {
        System.out.println(getName() + " ends the work day.");
    }
    
    // 重写获取奖金方法
    @Override
    public double getAnnualBonus() {
        return super.getAnnualBonus() + (teamSize * 1000); // 额外团队奖金
    }
}

// 测试类
public class OOPDemo {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person("Alice", 30);
        Employee employee = new Employee("Bob", 35, "E12345", 75000.0);
        Manager manager = new Manager("Charlie", 45, "M54321", 120000.0, 8);
        
        // 多态:父类引用指向子类对象
        Person[] people = {person, employee, manager};
        
        System.out.println("=== Demonstrating Polymorphism ===");
        for (Person p : people) {
            p.introduce(); // 根据实际对象类型调用相应方法
            System.out.println("---");
        }
        
        // 使用接口
        System.out.println("\n=== Demonstrating Interface ===");
        Workable workableManager = manager; // Manager is-a Workable
        workableManager.startWork();
        workableManager.endWork();
        
        // 访问特定方法
        System.out.println("\n=== Specific Methods ===");
        employee.work();
        System.out.println("Employee's annual bonus: $" + employee.getAnnualBonus());
        
        manager.work(); // 继承自Employee
        System.out.println("Manager's annual bonus: $" + manager.getAnnualBonus());
    }
}

异常处理:

java 复制代码
import java.io.*;
import java.util.*;

/**
 * ExceptionDemo.java
 * 演示Java异常处理机制
 */
public class ExceptionDemo {
    
    /**
     * 演示检查型异常 (checked exceptions)
     */
    public static void readFile(String filename) {
        try {
            // 检查型异常:必须处理或声明抛出
            FileReader fileReader = new FileReader(filename);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
            
            bufferedReader.close();
        } catch (FileNotFoundException e) {
            // 处理文件未找到异常
            System.err.println("Error: File not found - " + filename);
            e.printStackTrace();
        } catch (IOException e) {
            // 处理IO异常
            System.err.println("Error reading file: " + filename);
            e.printStackTrace();
        } finally {
            // 无论是否发生异常,都会执行
            System.out.println("File reading attempt completed.");
        }
    }
    
    /**
     * 演示非检查型异常 (unchecked exceptions)
     */
    public static void processArray(int[] array, int index) {
        try {
            // 非检查型异常:不需要强制处理
            System.out.println("Value at index " + index + ": " + array[index]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.err.println("Error: Invalid array index " + index);
        } catch (NullPointerException e) {
            System.err.println("Error: Array is null");
        } catch (Exception e) {
            // 捕获其他可能的异常
            System.err.println("An unexpected error occurred");
            e.printStackTrace();
        }
    }
    
    /**
     * 演示自定义异常
     */
    static class InsufficientFundsException extends Exception {
        private double amount;
        
        public InsufficientFundsException(String message, double amount) {
            super(message);
            this.amount = amount;
        }
        
        public double getAmount() {
            return amount;
        }
    }
    
    public static void withdraw(double balance, double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException("Insufficient funds for withdrawal", amount - balance);
        }
        System.out.println("Withdrawal successful: $" + amount);
    }
    
    /**
     * 使用try-with-resources (Java 7+)
     */
    public static void readWithResources(String filename) {
        // 资源会在try块结束时自动关闭
        try (FileReader fileReader = new FileReader(filename);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
            
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("Error with resources: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        System.out.println("=== Checked Exceptions Demo ===");
        readFile("nonexistent.txt");
        
        System.out.println("\n=== Unchecked Exceptions Demo ===");
        int[] numbers = {1, 2, 3};
        processArray(numbers, 1);  // 有效索引
        processArray(numbers, 5);  // 无效索引
        processArray(null, 0);     // 空数组
        
        System.out.println("\n=== Custom Exceptions Demo ===");
        try {
            withdraw(100.0, 150.0);  // 余额不足
        } catch (InsufficientFundsException e) {
            System.err.println(e.getMessage());
            System.err.println("Shortfall amount: $" + e.getAmount());
        }
        
        try {
            withdraw(200.0, 150.0);  // 有效取款
        } catch (InsufficientFundsException e) {
            System.err.println(e.getMessage());
        }
        
        System.out.println("\n=== Try-with-Resources Demo ===");
        // 创建示例文件
        try (FileWriter writer = new FileWriter("example.txt")) {
            writer.write("Line 1\nLine 2\nLine 3");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        readWithResources("example.txt");
        
        // 清理
        new File("example.txt").delete();
    }
}

Java 17新特性示例:

java 复制代码
/**
 * Java17Features.java
 * 演示Java 17 (LTS版本) 的一些关键新特性
 */
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Java17Features {
    
    // 1. 密封类 (Sealed Classes) - 控制继承
    public sealed class Shape permits Circle, Rectangle, Triangle {
        public abstract double area();
    }
    
    // 子类必须是final、sealed或non-sealed
    final class Circle extends Shape {
        private final double radius;
        
        public Circle(double radius) {
            this.radius = radius;
        }
        
        @Override
        public double area() {
            return Math.PI * radius * radius;
        }
        
        @Override
        public String toString() {
            return "Circle[radius=" + radius + ", area=" + area() + "]";
        }
    }
    
    final class Rectangle extends Shape {
        private final double width;
        private final double height;
        
        public Rectangle(double width, double height) {
            this.width = width;
            this.height = height;
        }
        
        @Override
        public double area() {
            return width * height;
        }
        
        @Override
        public String toString() {
            return "Rectangle[width=" + width + ", height=" + height + ", area=" + area() + "]";
        }
    }
    
    non-sealed class Triangle extends Shape {
        private final double base;
        private final double height;
        
        public Triangle(double base, double height) {
            this.base = base;
            this.height = height;
        }
        
        @Override
        public double area() {
            return 0.5 * base * height;
        }
        
        @Override
        public String toString() {
            return "Triangle[base=" + base + ", height=" + height + ", area=" + area() + "]";
        }
        
        // Triangle可以被进一步继承
        final class RightTriangle extends Triangle {
            private final double hypotenuse;
            
            public RightTriangle(double base, double height) {
                super(base, height);
                this.hypotenuse = Math.sqrt(base * base + height * height);
            }
            
            @Override
            public String toString() {
                return "RightTriangle[base=" + base + ", height=" + height + 
                       ", hypotenuse=" + hypotenuse + ", area=" + area() + "]";
            }
        }
    }
    
    // 2. 模式匹配 (Pattern Matching)
    public static String describeShape(Object obj) {
        // Java 17中的模式匹配简化instanceof检查
        if (obj instanceof Circle c) {
            return "This is a circle with radius " + c.radius;
        } else if (obj instanceof Rectangle r) {
            return "This is a rectangle with dimensions " + r.width + "x" + r.height;
        } else if (obj instanceof Triangle t) {
            return "This is a triangle with base " + t.base + " and height " + t.height;
        } else {
            return "Unknown shape";
        }
    }
    
    // 3. 文本块 (Text Blocks) - Java 15引入,17继续支持
    public static String getJsonExample() {
        return """
               {
                 "name": "John Doe",
                 "age": 30,
                 "address": {
                   "street": "123 Main St",
                   "city": "Anytown",
                   "country": "USA"
                 },
                 "phones": ["123-456-7890", "987-654-3210"]
               }
               """;
    }
    
    // 4. Records - 简化的不可变数据类
    public record PersonRecord(String name, int age, String email) {
        // 自动获得构造函数、getter、equals、hashCode、toString
        // 可以添加额外方法
        public boolean isAdult() {
            return age >= 18;
        }
    }
    
    public static void main(String[] args) {
        System.out.println("=== Java 17 Features Demo ===\n");
        
        // 1. 密封类示例
        System.out.println("1. Sealed Classes:");
        Shape[] shapes = {
            new Circle(5.0),
            new Rectangle(4.0, 6.0),
            new Triangle(3.0, 4.0),
            new Triangle.RightTriangle(3.0, 4.0) // 使用non-sealed的子类
        };
        
        for (Shape shape : shapes) {
            System.out.println(shape);
        }
        System.out.println();
        
        // 2. 模式匹配示例
        System.out.println("2. Pattern Matching:");
        for (Shape shape : shapes) {
            System.out.println(describeShape(shape));
        }
        System.out.println();
        
        // 3. 文本块示例
        System.out.println("3. Text Blocks:");
        System.out.println(getJsonExample());
        System.out.println();
        
        // 4. Records示例
        System.out.println("4. Records:");
        PersonRecord person1 = new PersonRecord("Alice", 25, "alice@example.com");
        PersonRecord person2 = new PersonRecord("Bob", 17, "bob@example.com");
        
        System.out.println("Person 1: " + person1);
        System.out.println("Is adult? " + person1.isAdult());
        
        System.out.println("Person 2: " + person2);
        System.out.println("Is adult? " + person2.isAdult());
        
        // Records自动实现equals
        PersonRecord person3 = new PersonRecord("Alice", 25, "alice@example.com");
        System.out.println("person1 equals person3? " + person1.equals(person3));
        
        // 使用Stream API和Records
        List<PersonRecord> people = List.of(person1, person2, person3);
        Map<Boolean, List<PersonRecord>> adultsGrouping = people.stream()
            .collect(Collectors.partitioningBy(PersonRecord::isAdult));
        
        System.out.println("\nAdults: " + adultsGrouping.get(true));
        System.out.println("Minors: " + adultsGrouping.get(false));
    }
}

2. Android开发环境

2.1 Android简介

Android系统架构:

  • Linux内核层: 硬件抽象、内存管理、进程管理、网络堆栈
  • 硬件抽象层(HAL): 提供标准接口访问硬件功能
  • Android运行时(ART): 执行DEX字节码,取代早期的Dalvik VM
  • 原生C/C++库: 系统组件如SSL、SQLite、OpenGL等
  • Java API框架: 提供UI、资源管理、通知等高级API
  • 系统应用: 预装的核心应用(电话、联系人、浏览器等)

Android版本演进:

  • Android 13 (Tiramisu, API 33): 2022年发布,增强隐私控制,通知权限
  • Android 12 (Snow Cone, API 32-31): 2021年发布,Material You设计语言
  • Android 11 (Red Velvet Cake, API 30): 2020年发布,对话通知,一次性权限
  • Android 10 (Quince Tart, API 29): 2019年发布,系统级暗黑模式,作用域存储

Android应用组件:

  • Activity: 用户界面的单个屏幕
  • Service: 在后台执行长时间运行的操作
  • BroadcastReceiver: 响应系统级广播事件
  • ContentProvider: 管理共享应用数据
  • Fragment: 可重用的UI组件,可以组合成多面板UI
  • ViewModel: 以生命周期方式管理UI相关数据
  • Intent: 组件间通信的消息对象

2.2 Android开发工具

核心工具:

  • Android Studio: 官方IDE,基于IntelliJ IDEA
  • Android SDK: 软件开发工具包,包含API库、工具、模拟器
  • Android NDK: 本地开发工具包,用于C/C++开发
  • Gradle: 构建系统,管理依赖、编译、打包
  • ADB (Android Debug Bridge): 与设备通信的命令行工具
  • Fastboot: 低级设备引导工具
  • Logcat: 系统和应用日志查看器
  • Profiler: 性能分析工具(CPU、内存、网络、能耗)

辅助工具:

  • Layout Inspector: 检查UI布局层次
  • Database Inspector: 查看和修改应用数据库
  • APK Analyzer: 分析APK内容和大小
  • Emulator: 虚拟设备,模拟各种Android设备
  • Device File Explorer: 访问设备文件系统
  • Layout Editor: 可视化设计UI布局
  • Vector Asset Studio: 将SVG转换为Android矢量图形
  • Profiler: 监控应用性能

2.3 安装部署Android Studio

2.3.1 系统要求检查
bash 复制代码
# 1. 检查系统架构
uname -m
# 预期输出: x86_64 (Android Studio需要64位系统)

# 2. 检查RAM和交换空间
free -h
# 推荐: 8GB+ RAM,2GB+ 交换空间

# 3. 检查可用磁盘空间
df -h /home
# 推荐: 10GB+ 空闲空间 (SDK、模拟器、缓存)

# 4. 检查Java版本 (需要JDK 11或更高)
java -version
# 预期: openjdk version "11.0.18" 或更高
2.3.2 安装Android Studio

方法1: 通过snap安装 (最简单)

bash 复制代码
# 1. 安装Android Studio
sudo snap install android-studio --classic

# 2. 启动Android Studio
android-studio

# 3. (可选) 创建桌面快捷方式
# 通常snap会自动创建,在应用菜单中查找"Android Studio"

方法2: 通过官方安装包安装 (推荐,更多控制)

bash 复制代码
# 1. 安装依赖
sudo apt update
sudo apt install -y libc6 libncurses5 libstdc++6 lib32z1 libbz2-1.0 libgl1-mesa-glx

# 2. 下载Android Studio (最新版本)
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2022.3.1.16/android-studio-2022.3.1.16-linux.tar.gz

# 3. 解压到/opt目录
sudo tar -xzf android-studio-*.tar.gz -C /opt/
sudo mv /opt/android-studio-* /opt/android-studio

# 4. 创建启动脚本
sudo ln -s /opt/android-studio/bin/studio.sh /usr/local/bin/android-studio

# 5. 创建桌面快捷方式
cat > ~/.local/share/applications/android-studio.desktop <<EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=Android Studio
Icon=/opt/android-studio/bin/studio.png
Exec="/opt/android-studio/bin/studio.sh" %f
Comment=Develop with pleasure!
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-studio
EOF

# 6. 更新桌面数据库
update-desktop-database ~/.local/share/applications

# 7. 清理下载文件
rm android-studio-*.tar.gz

# 8. 启动Android Studio
android-studio
2.3.3 配置Android SDK

首次启动Android Studio会进行SDK配置:

  1. 欢迎屏幕:

    • 选择"Standard"安装类型
    • 选择UI主题(Dark或Light)
  2. SDK组件选择:

    • Android SDK Platform (最新稳定版,如Android 13/API 33)
    • Android SDK Build-Tools
    • Android SDK Platform-Tools
    • Android SDK Tools
    • Android Emulator
    • Intel x86_64或ARM系统映像 (用于模拟器)
  3. SDK路径配置:

    • 默认位置: ~/Android/Sdk
    • 确保有足够磁盘空间
  4. 代理设置 (如果在公司网络或中国):

    • 可配置HTTP代理
    • 或选择离线安装包
  5. 验证安装:

    • 在终端执行以下命令验证SDK安装
    bash 复制代码
    # 检查adb
    adb --version
    # 预期: Android Debug Bridge version 1.0.41
    
    # 检查sdkmanager
    sdkmanager --list
2.3.4 配置KVM加速 (重要,用于模拟器性能)
bash 复制代码
# 1. 检查CPU虚拟化支持
egrep -c '(vmx|svm)' /proc/cpuinfo
# 输出>0表示支持硬件虚拟化

# 2. 安装KVM
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager

# 3. 将当前用户添加到kvm和libvirt组
sudo usermod -aG kvm $USER
sudo usermod -aG libvirt $USER

# 4. 验证安装
systemctl is-active libvirtd
# 预期: active

# 5. 检查KVM设备权限
ls -la /dev/kvm
# 预期: crw-rw----+ 1 root kvm ...

# 6. (可选) 重启系统使组权限生效
sudo reboot
2.3.5 配置环境变量
bash 复制代码
# 1. 编辑~/.bashrc或~/.zshrc
echo 'export ANDROID_HOME=$HOME/Android/Sdk' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/emulator' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/platform-tools' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/tools' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/tools/bin' >> ~/.bashrc

# 2. 使配置生效
source ~/.bashrc

# 3. 验证配置
echo $ANDROID_HOME
adb devices
emulator -list-avds

2.4 基于Android Studio开发Android应用

2.4.1 创建第一个Android应用

步骤:

  1. 启动Android Studio
  2. 点击"New Project"
  3. 选择"Empty Activity"模板
  4. 配置项目:
    • Name: MyFirstApp
    • Package name: com.example.myfirstapp
    • Save location: 选择项目目录
    • Language: Java (或Kotlin)
    • Minimum API level: API 24 (Android 7.0) - 覆盖约90%设备
  5. 点击"Finish",等待Gradle同步完成
2.4.2 项目结构解析
复制代码
MyFirstApp/
├── app/                          # 应用模块
│   ├── build.gradle              # 应用构建配置
│   ├── libs/                     # 第三方库
│   └── src/
│       ├── androidTest/          # 仪器化测试
│       ├── main/
│       │   ├── AndroidManifest.xml  # 应用配置文件
│       │   ├── java/com/example/myfirstapp/  # Java源代码
│       │   │   ├── MainActivity.java  # 主Activity
│       │   │   └── MainActivity2.java
│       │   └── res/              # 资源文件
│       │       ├── drawable/     # 图像资源
│       │       ├── layout/       # UI布局
│       │       │   └── activity_main.xml
│       │       ├── mipmap/       # 应用图标
│       │       ├── values/       # 值资源
│       │       │   ├── colors.xml
│       │       │   ├── strings.xml
│       │       │   └── themes.xml
│       │       └── ...
│       └── test/                 # 本地单元测试
├── gradle/                       # Gradle wrapper
├── build.gradle                  # 项目级构建配置
├── gradle.properties             # Gradle属性
├── gradlew                       # Gradle wrapper for Linux/Mac
├── gradlew.bat                   # Gradle wrapper for Windows
└── settings.gradle               # 项目模块设置
2.4.3 核心组件与代码示例

示例1: 基本UI与事件处理

MainActivity.java:

java 复制代码
package com.example.myfirstapp;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    
    // UI组件引用
    private EditText editTextName;
    private Button buttonSubmit;
    private TextView textViewGreeting;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化UI组件
        initViews();
        
        // 设置按钮点击事件
        setupButtonClick();
    }
    
    /**
     * 初始化UI组件
     */
    private void initViews() {
        editTextName = findViewById(R.id.editTextName);
        buttonSubmit = findViewById(R.id.buttonSubmit);
        textViewGreeting = findViewById(R.id.textViewGreeting);
    }
    
    /**
     * 设置按钮点击事件处理
     */
    private void setupButtonClick() {
        buttonSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handleButtonClick();
            }
        });
    }
    
    /**
     * 处理按钮点击事件
     */
    private void handleButtonClick() {
        // 获取输入框内容
        String name = editTextName.getText().toString().trim();
        
        // 验证输入
        if (name.isEmpty()) {
            // 显示Toast提示
            Toast.makeText(this, "Please enter your name", Toast.LENGTH_SHORT).show();
            return;
        }
        
        // 更新文本视图
        String greeting = getString(R.string.greeting_message, name);
        textViewGreeting.setText(greeting);
        
        // 清空输入框
        editTextName.setText("");
        
        // 显示成功Toast
        Toast.makeText(this, "Greeting updated!", Toast.LENGTH_SHORT).show();
    }
    
    /**
     * 保存实例状态
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // 保存文本视图内容
        outState.putString("greeting_text", textViewGreeting.getText().toString());
    }
    
    /**
     * 恢复实例状态
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        // 恢复文本视图内容
        String savedGreeting = savedInstanceState.getString("greeting_text", "");
        if (!savedGreeting.isEmpty()) {
            textViewGreeting.setText(savedGreeting);
        }
    }
}

activity_main.xml:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <!-- 标题文本 -->
    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_title"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"/>

    <!-- 名称输入提示 -->
    <TextView
        android:id="@+id/textViewPrompt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/name_prompt"
        android:textSize="16sp"
        app:layout_constraintTop_toBottomOf="@id/textViewTitle"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginTop="32dp"
        android:layout_marginStart="8dp"/>

    <!-- 名称输入框 -->
    <EditText
        android:id="@+id/editTextName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="@string/name_hint"
        android:inputType="textPersonName"
        android:autofillHints="name"
        app:layout_constraintTop_toBottomOf="@id/textViewPrompt"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"/>

    <!-- 提交按钮 -->
    <Button
        android:id="@+id/buttonSubmit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/submit_button"
        app:layout_constraintTop_toBottomOf="@id/editTextName"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="24dp"/>

    <!-- 问候文本 -->
    <TextView
        android:id="@+id/textViewGreeting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/default_greeting"
        android:textSize="18sp"
        android:textAlignment="center"
        app:layout_constraintTop_toBottomOf="@id/buttonSubmit"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"
        android:padding="16dp"
        android:background="@drawable/greeting_background"/>

</androidx.constraintlayout.widget.ConstraintLayout>

strings.xml:

xml 复制代码
<resources>
    <string name="app_name">My First App</string>
    <string name="app_title">Welcome to My App</string>
    <string name="name_prompt">Enter your name:</string>
    <string name="name_hint">Your name</string>
    <string name="submit_button">Submit</string>
    <string name="default_greeting">Hello there!</string>
    <string name="greeting_message">Hello, %1$s!</string>
</resources>

greeting_background.xml (在res/drawable目录):

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#E3F2FD" />
    <corners android:radius="8dp" />
    <stroke
        android:width="1dp"
        android:color="#90CAF9" />
</shape>

示例2: 多活动导航与隐式Intent

SecondActivity.java:

java 复制代码
package com.example.myfirstapp;

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class SecondActivity extends AppCompatActivity {
    
    private TextView textViewMessage;
    private Button buttonOpenWeb;
    private Button buttonCallNumber;
    private static final String PHONE_NUMBER = "1234567890";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        
        // 初始化UI组件
        initViews();
        
        // 设置按钮点击事件
        setupButtonClicks();
        
        // 处理传入的Intent
        handleIncomingIntent();
    }
    
    /**
     * 初始化UI组件
     */
    private void initViews() {
        textViewMessage = findViewById(R.id.textViewMessage);
        buttonOpenWeb = findViewById(R.id.buttonOpenWeb);
        buttonCallNumber = findViewById(R.id.buttonCallNumber);
    }
    
    /**
     * 设置按钮点击事件处理
     */
    private void setupButtonClicks() {
        buttonOpenWeb.setOnClickListener(v -> openWebsite());
        buttonCallNumber.setOnClickListener(v -> callPhoneNumber());
    }
    
    /**
     * 打开网站
     */
    private void openWebsite() {
        try {
            // 创建隐式Intent打开网页
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse("https://www.android.com"));
            startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(this, "No browser app found", Toast.LENGTH_SHORT).show();
        }
    }
    
    /**
     * 拨打电话
     */
    private void callPhoneNumber() {
        try {
            // 创建隐式Intent拨打电话
            Intent intent = new Intent(Intent.ACTION_DIAL);
            intent.setData(Uri.parse("tel:" + PHONE_NUMBER));
            startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(this, "No phone app found", Toast.LENGTH_SHORT).show();
        }
    }
    
    /**
     * 处理传入的Intent
     */
    private void handleIncomingIntent() {
        Intent intent = getIntent();
        if (intent != null) {
            String message = intent.getStringExtra("EXTRA_MESSAGE");
            if (message != null && !message.isEmpty()) {
                textViewMessage.setText(getString(R.string.received_message, message));
            } else {
                textViewMessage.setText(R.string.no_message_received);
            }
        }
    }
    
    /**
     * 返回按钮处理
     */
    @Override
    public void onBackPressed() {
        // 创建返回结果
        Intent resultIntent = new Intent();
        resultIntent.putExtra("RESULT_MESSAGE", "Back from Second Activity");
        setResult(RESULT_OK, resultIntent);
        super.onBackPressed();
    }
}

activity_second.xml:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".SecondActivity">

    <TextView
        android:id="@+id/textViewHeader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/second_activity_title"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"/>

    <TextView
        android:id="@+id/textViewMessage"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/no_message_received"
        android:textSize="18sp"
        android:gravity="center"
        android:padding="16dp"
        android:background="@drawable/message_background"
        app:layout_constraintTop_toBottomOf="@id/textViewHeader"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"/>

    <Button
        android:id="@+id/buttonOpenWeb"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/open_website_button"
        app:layout_constraintTop_toBottomOf="@id/textViewMessage"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="48dp"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"/>

    <Button
        android:id="@+id/buttonCallNumber"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/call_number_button"
        app:layout_constraintTop_toBottomOf="@id/buttonOpenWeb"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

修改MainActivity.java添加导航:

java 复制代码
// 在MainActivity类中添加以下方法
private void navigateToSecondActivity() {
    // 获取输入的名称
    String name = editTextName.getText().toString().trim();
    
    if (name.isEmpty()) {
        Toast.makeText(this, "Please enter your name first", Toast.LENGTH_SHORT).show();
        return;
    }
    
    // 创建显式Intent
    Intent intent = new Intent(this, SecondActivity.class);
    
    // 传递数据
    intent.putExtra("EXTRA_MESSAGE", name);
    
    // 启动活动并等待结果
    startActivityForResult(intent, 1);
}

// 在setupButtonClick方法中添加第二个按钮
private Button buttonSecondActivity;

private void initViews() {
    // ... 原有代码
    buttonSecondActivity = findViewById(R.id.buttonSecondActivity);
}

private void setupButtonClick() {
    buttonSubmit.setOnClickListener(...); // 原有代码
    
    // 添加第二个按钮点击处理
    buttonSecondActivity.setOnClickListener(v -> navigateToSecondActivity());
}

// 处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    
    if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
        String resultMessage = data.getStringExtra("RESULT_MESSAGE");
        if (resultMessage != null) {
            Toast.makeText(this, "Result: " + resultMessage, Toast.LENGTH_LONG).show();
        }
    }
}

添加按钮到activity_main.xml:

xml 复制代码
<!-- 在按钮Submit下方添加 -->
<Button
    android:id="@+id/buttonSecondActivity"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Go to Second Activity"
    app:layout_constraintTop_toBottomOf="@id/buttonSubmit"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"/>

示例3: RecyclerView实现列表

创建用户模型类User.java:

java 复制代码
package com.example.myfirstapp.model;

public class User {
    private String name;
    private String email;
    private int age;
    
    public User(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public String getEmail() {
        return email;
    }
    
    public int getAge() {
        return age;
    }
}

创建适配器UserAdapter.java:

java 复制代码
package com.example.myfirstapp.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.myfirstapp.R;
import com.example.myfirstapp.model.User;
import java.util.List;

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    
    private List<User> userList;
    private OnUserClickListener listener;
    
    // 点击事件接口
    public interface OnUserClickListener {
        void onUserClick(User user);
    }
    
    public UserAdapter(List<User> userList, OnUserClickListener listener) {
        this.userList = userList;
        this.listener = listener;
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_user, parent, false);
        return new UserViewHolder(view);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        User user = userList.get(position);
        holder.bind(user);
        
        // 设置点击事件
        holder.itemView.setOnClickListener(v -> {
            if (listener != null) {
                listener.onUserClick(user);
            }
        });
    }
    
    @Override
    public int getItemCount() {
        return userList.size();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private TextView textViewName;
        private TextView textViewEmail;
        private TextView textViewAge;
        
        public UserViewHolder(@NonNull View itemView) {
            super(itemView);
            textViewName = itemView.findViewById(R.id.textViewName);
            textViewEmail = itemView.findViewById(R.id.textViewEmail);
            textViewAge = itemView.findViewById(R.id.textViewAge);
        }
        
        public void bind(User user) {
            textViewName.setText(user.getName());
            textViewEmail.setText(user.getEmail());
            textViewAge.setText(String.valueOf(user.getAge()));
        }
    }
}

创建列表项布局item_user.xml (在res/layout目录):

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    app:cardCornerRadius="8dp"
    app:cardElevation="2dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/textViewName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"/>

        <TextView
            android:id="@+id/textViewEmail"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="#666666"/>

        <TextView
            android:id="@+id/textViewAge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:layout_marginTop="4dp"/>

    </LinearLayout>

</androidx.cardview.widget.CardView>

创建UserListActivity.java:

java 复制代码
package com.example.myfirstapp;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Toast;
import com.example.myfirstapp.adapter.UserAdapter;
import com.example.myfirstapp.model.User;
import java.util.ArrayList;
import java.util.List;

public class UserListActivity extends AppCompatActivity {
    
    private RecyclerView recyclerViewUsers;
    private UserAdapter userAdapter;
    private List<User> userList = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_list);
        
        // 初始化视图
        initViews();
        
        // 准备数据
        prepareUserData();
        
        // 设置RecyclerView
        setupRecyclerView();
    }
    
    private void initViews() {
        recyclerViewUsers = findViewById(R.id.recyclerViewUsers);
    }
    
    private void prepareUserData() {
        // 模拟用户数据
        userList.add(new User("Alice Johnson", "alice@example.com", 28));
        userList.add(new User("Bob Smith", "bob.smith@example.com", 35));
        userList.add(new User("Charlie Brown", "charlie@example.com", 42));
        userList.add(new User("Diana Prince", "diana.p@example.com", 31));
        userList.add(new User("Edward Norton", "edward.n@example.com", 29));
        userList.add(new User("Fiona Gallagher", "fiona@example.com", 33));
        userList.add(new User("George Wilson", "george.w@example.com", 45));
        userList.add(new User("Hannah Baker", "hannah.b@example.com", 27));
    }
    
    private void setupRecyclerView() {
        // 设置布局管理器
        recyclerViewUsers.setLayoutManager(new LinearLayoutManager(this));
        
        // 创建并设置适配器
        userAdapter = new UserAdapter(userList, user -> {
            // 处理用户点击
            showUserDetails(user);
        });
        recyclerViewUsers.setAdapter(userAdapter);
    }
    
    private void showUserDetails(User user) {
        Toast.makeText(this, 
                "User Details:\nName: " + user.getName() + 
                "\nEmail: " + user.getEmail() + 
                "\nAge: " + user.getAge(),
                Toast.LENGTH_SHORT).show();
    }
}

创建activity_user_list.xml:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UserListActivity">

    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/user_list_title"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewUsers"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:padding="8dp"
        app:layout_constraintTop_toBottomOf="@id/textViewTitle"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:scrollbars="vertical"/>

</androidx.constraintlayout.widget.ConstraintLayout>

strings.xml中添加:

xml 复制代码
<string name="user_list_title">User List</string>

AndroidManifest.xml中注册新Activity:

xml 复制代码
<activity
    android:name=".UserListActivity"
    android:label="User List"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity" />
</activity>
2.4.4 调试与部署

调试技巧:

  1. Logcat:

    java 复制代码
    import android.util.Log;
    
    // 在代码中添加日志
    Log.d("MainActivity", "Button clicked");
    Log.i("MainActivity", "User data loaded");
    Log.e("MainActivity", "Error loading data", exception);
  2. 断点调试:

    • 在代码行号左侧单击添加断点
    • 点击Debug按钮启动调试
    • 使用调试工具栏控制执行流程
    • 查看变量值、调用栈、线程状态
  3. 布局检查:

    • 使用Layout Inspector检查UI层次
    • 使用Layout Validation查看不同屏幕尺寸的预览
    • 使用Pixel Perfect工具精确检查UI元素位置

部署到设备:

  1. 物理设备:

    • 启用开发者选项 (设置 > 关于手机 > 连续点击版本号7次)
    • 在开发者选项中启用USB调试
    • 通过USB连接设备
    • 在Android Studio中选择设备并点击Run
  2. 模拟器:

    • 在AVD Manager中创建虚拟设备
    • 选择设备定义、系统映像、配置
    • 启动模拟器
    • 在Android Studio中选择模拟器并点击Run

发布准备:

gradle 复制代码
// app/build.gradle
android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
    
    signingConfigs {
        release {
            storeFile file("my-release-key.jks")
            storePassword "password"
            keyAlias "my-key-alias"
            keyPassword "password"
        }
    }
}

3. 本章小结

3.1 重点回顾

  1. Java开发环境:

    • OpenJDK是Ubuntu上的推荐选择
    • 使用update-alternatives管理多版本JDK
    • IntelliJ IDEA提供强大的Java开发体验
    • Java 17引入了密封类、模式匹配等现代特性
  2. Android开发环境:

    • Android Studio是官方IDE,提供完整工具链
    • SDK Manager管理Android平台和工具版本
    • 模拟器需要KVM加速获得良好性能
    • Gradle是Android的构建系统
  3. Android应用开发:

    • Activity是应用的基本构建块
    • UI通过XML布局文件定义,Java/Kotlin提供逻辑
    • Intent实现组件间通信
    • RecyclerView高效显示大型数据集
    • 生命周期管理是Android开发核心概念

3.2 最佳实践

  1. Java开发最佳实践:

    • 使用try-with-resources自动管理资源
    • 采用记录类(Records)简化数据类
    • 使用密封类(Sealed Classes)控制继承层次
    • 优先使用不可变对象
    • 遵循命名和代码风格规范
  2. Android开发最佳实践:

    • 将字符串、尺寸等资源外部化
    • 为不同屏幕尺寸提供替代资源
    • 使用ViewModel管理UI相关数据
    • 避免在主线程执行耗时操作
    • 使用约束布局(ConstraintLayout)创建灵活UI
    • 实现适当的状态保存和恢复
  3. 性能优化:

    • 减小APK大小 (资源压缩、代码混淆)
    • 优化内存使用 (避免内存泄漏)
    • 最小化主线程工作
    • 使用适当的图片格式和尺寸
    • 实现分页加载大型数据集

3.3 学习资源推荐

  1. Java学习资源:

  2. Android学习资源:

  3. 工具和社区:

    • Stack Overflow
    • GitHub开源项目
    • Android Dev Summit视频
    • JetBrains官方博客

通过本章学习,您已掌握在Ubuntu 22.04环境下配置Java和Android开发环境的完整流程,以及开发基础应用程序的技能。持续实践这些知识,并探索更高级的主题,将帮助您成长为一名熟练的Java/Android开发者。

相关推荐
GHL2842710903 小时前
调用通义千问(qwen-plus)模型demo-学习
学习·ai·ai编程
阿达King哥3 小时前
在Windows11下编译openjdk 21
java·jvm
shark-chili3 小时前
从操作系统底层浅谈程序栈的高效性
java
不知疲倦的仄仄4 小时前
第二天:深入理解 Selector:单线程高效管理多个 Channel
java·nio
期待のcode4 小时前
Java虚拟机栈
java·开发语言·jvm
珂朵莉MM4 小时前
全球校园人工智能算法精英大赛-产业命题赛-算法巅峰赛 2025年度画像
java·人工智能·算法·机器人
芒克芒克4 小时前
本地部署SpringBoot项目
java·spring boot·spring
cute_ming4 小时前
关于基于nodeMap重构DOM的最佳实践
java·javascript·重构
sww_10264 小时前
Netty原理分析
java·网络
小突突突4 小时前
Spring框架中的单例bean是线程安全的吗?
java·后端·spring