Java 101:从零到高手课程
介绍:
你的引言引人入胜,为博客营造了友好的氛围。以下是更正后的版本,为清晰起见,进行了一些细微调整:
欢迎来到 Java 101,我将带您踏上我的 Java 学习之旅。在这篇内容全面的博文中,我们将涵盖 Java 语言所需的一切知识,从设置开发环境到深入学习面向对象编程,再到探索高级概念。
Java 是一种功能强大、用途广泛的编程语言,从构建 Web 应用程序到开发移动应用程序和企业系统,应用范围十分广泛。正因如此,它在我心中占据着特殊的地位。
那么,准备好踏上这段冒险之旅吧,因为这将是我写过的最长的博客文章之一。我的结构如下:
- 第 1 部分:基础知识(变量、数据类型、流控制、逻辑运算符……)
- 第 2 部分:面向对象编程(类和对象、继承、多态、封装、抽象、接口……)
- 第 3 部分:高级 Java 主题(异常、泛型、集合、函数式编程、并发、多线程)
让我们一起深入探索 Java 的世界吧!
第 1 部分 | 语言基础知识
当然!让我们以一种简单易懂的方式分解数据类型的各个部分。
原始数据类型
原始数据类型是 Java 中最基本的数据类型。它们表示没有内部结构的单个值。以下是一些常见的原始数据类型:
- byte:表示 [-128, 127] 范围内的 1 字节整数。
- short:表示 [-32,768, 32,767] 范围内的 2 字节整数。
- int:表示一个 4 字节的大范围内的整数。
- long:表示范围很广的8字节整数。
- float:表示4字节浮点数,适用于实数的近似表示。
- double:表示一个 8 字节的浮点数,与 float 相比提供更高的精度。
- boolean:表示真值或假值。
- char:表示单个字符,如“A”、“b”、“%”。
让我们看一些例子:
byte age = 25;
short population = 32000;
int distance = 150000;
long globalPopulation = 7760000000L; // Note the 'L' suffix for long literals
float temperature = 20.5f; // Note the 'f' suffix for float literals
double height = 5.9;
boolean isSunny = true;
char grade = 'A';
在本节中,我们概述了 Java 中各种原始数据类型的大小和范围,并提供了演示其用法的示例。此外,我们还介绍了float
用于表示近似精度浮点数的数据类型。
引用数据类型
引用数据类型指的是 Java 中的对象。与原始数据类型不同,它们具有复杂的结构,并且动态存储在内存中。以下是一些引用数据类型的示例:
- 字符串:表示字符序列,如“Hello, World!”。
- 数组:表示同一类型的元素的集合。
让我们看看如何使用它们:
String name = "Alice";
int[] numbers = {1, 2, 3, 4, 5};
这里,name
是一个存储名称“Alice”的字符串,numbers
是一个整数数组。
输入阅读技巧
在 Java 中,我们可以使用该类读取用户的输入Scanner
。以下是如何使用它读取整数和字符串:
import java.util.Scanner;
public class InputExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.print("Enter your name: ");
String name = scanner.next();
System.out.println("Hello, " + name + "! You are " + age + " years old.");
scanner.close(); // Don't forget to close the scanner to release resources.
}
}
运行此程序时,它会提示你输入年龄和姓名。然后,它会打印一条包含你输入值的问候消息。
就是这样!以上就是 Java 数据类型的基础知识,并以简单易懂的方式进行了讲解。欢迎尝试这些示例,加深您的理解!
当然!为了更好地理解,让我们通过代码示例来分解控制流的各个概念:
比较运算符
比较运算符用于比较两个值并返回布尔值。以下是一些常见的比较运算符:
- 等于 (
==
):如果两个值相等则返回 true。 - 不等于(
!=
):如果两个值不相等,则返回 true。 - 大于(
>
):如果左操作数大于右操作数,则返回 true。 - 大于或等于(
>=
):如果左操作数大于或等于右操作数,则返回 true。 - 小于(
<
):如果右操作数大于左操作数,则返回 true。 - 小于或等于(
<=
):如果左操作数小于或等于右操作数,则返回 true。
int x = 5;
int y = 10;
System.out.println(x == y); // Outputs: false
System.out.println(x != y); // Outputs: true
System.out.println(x > y); // Outputs: false
System.out.println(x < y); // Outputs: true
System.out.println(x >= y); // Outputs: false
System.out.println(x <= y); // Outputs: true
逻辑运算符
逻辑运算符用于对布尔表达式执行逻辑运算。以下是常见的逻辑运算符:
- AND (
&&
):如果两个操作数都为真,则返回真。 - 或(
||
):如果至少有一个操作数为真,则返回真。 - NOT (
!
):返回操作数的布尔值的反面。
boolean isSunny = true;
boolean isWarm = false;
System.out.println(isSunny && isWarm); // Outputs: false
System.out.println(isSunny || isWarm); // Outputs: true
System.out.println(!isSunny); // Outputs: false
条件语句(if、else-if、else)
条件语句用于根据特定条件执行不同的代码块。
int age = 20;
if (age >= 18) {
System.out.println("You are an adult.");
} else if (age >= 13) {
System.out.println("You are a teenager.");
} else {
System.out.println("You are a child.");
}
三元运算符
三元运算符是编写 if-else 语句的简写方式。
int num = 10;
String result = (num % 2 == 0) ? "even" : "odd";
System.out.println(result); // Outputs: even
Switch 语句
Switch 语句允许我们根据变量的值执行不同的代码块。
int day = 3;
String dayName;
switch (day) {
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
// ...
default:
dayName = "Invalid day";
}
System.out.println("Today is " + dayName);
迭代语句
迭代语句用于重复执行一段代码。
For 循环
for (int i = 1; i <= 5; i++) {
System.out.println("Count: " + i);
}
增强的 For Each 循环
int[] numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
System.out.println(num);
}
While 循环
int i = 1;
while (i <= 5) {
System.out.println("Count: " + i);
i++;
}
Do-While 循环
int j = 1;
do {
System.out.println("Count: " + j);
j++;
} while (j <= 5);
锻炼
现在,我们完成了 Java 基础知识的学习,让我们把目前学到的所有知识打包成一个漂亮、简单、基本的计算器
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Welcome to the Simple Calculator!");
System.out.println("Please enter the first number:");
double num1 = scanner.nextDouble();
System.out.println("Please enter the second number:");
double num2 = scanner.nextDouble();
System.out.println("Select operation:");
System.out.println("1. Addition (+)");
System.out.println("2. Subtraction (-)");
System.out.println("3. Multiplication (*)");
System.out.println("4. Division (/)");
int choice = scanner.nextInt();
double result = 0;
switch (choice) {
case 1:
result = num1 + num2;
break;
case 2:
result = num1 - num2;
break;
case 3:
result = num1 * num2;
break;
case 4:
if (num2 != 0) {
result = num1 / num2;
} else {
System.out.println("Error! Division by zero is not allowed.");
return;
}
break;
default:
System.out.println("Invalid choice!");
return;
}
System.out.println("Result: " + result);
scanner.close();
}
}
第 2 部分 | Java 中的面向对象编程
Java 确实是一种多功能的编程语言,它支持多种编程范式,包括过程式、函数式和面向对象编程 (OOP)。然而,OOP 范式是 Java 中的主要范式,因为它专注于将现实世界的实体建模为具有属性(数据)和行为(方法)的对象。
让我们一起深入了解 Java 中 OOP 世界的不同概念和方面。
当然!让我们用简单的语言、类比和大量的代码示例来分解每个主题。
理解类和对象
可以将类想象成一张蓝图,将对象想象成基于该蓝图构建的事物。例如,“汽车”类定义了汽车是什么(包括颜色、品牌、型号等属性,以及驾驶和鸣笛等行为),而对象则是基于该蓝图构建的一辆具体的汽车。
创建和实例化类
要创建类,您需要定义其属性和行为。要创建对象,您需要使用类蓝图。以下是一个类的示例以及如何从中创建对象:
// Class definition
class Car {
String color;
String make;
String model;
void drive() {
System.out.println("The car is driving.");
}
}
// Creating an object
Car myCar = new Car();
封装
封装就像把你的东西放在一个盒子里,只允许特定的人访问。在 Java 中,你可以隐藏类的内部工作原理,只允许通过特定的方法(例如 getter 和 setter 方法)进行访问。
class BankAccount {
private double balance;
// Getter method
public double getBalance() {
return balance;
}
// Setter method
public void setBalance(double amount) {
balance = amount;
}
}
抽象
抽象就像驾驶汽车,但无需了解引擎的工作原理。你可以通过汽车(对象)的接口(方法)与其交互,而无需了解其内部实现。
构造函数
构造函数就像一个用来创建对象的特殊配方。它们在创建对象时初始化对象的状态。以下是一个例子:
class Dog {
String breed;
// Constructor
public Dog(String dogBreed) {
breed = dogBreed;
}
}
多态性
多态就像一个变形器。一个对象可以根据其上下文呈现不同的形态。方法重载就是一个例子:
class MathOperations {
// Method overloading
public int add(int x, int y) {
return x + y;
}
public double add(double x, double y) {
return x + y;
}
}
遗产
继承就像将特征从父类传递给子类。子类会从其超类继承属性和行为。例如:
class Animal {
void eat() {
System.out.println("The animal is eating.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("The dog is barking.");
}
}
静态成员
静态成员就像类中所有对象共享的资源。它们属于类本身,而不是任何特定的对象。例如:
class Circle {
static final double PI = 3.14;
static double calculateArea(double radius) {
return PI * radius * radius;
}
}
当然!让我们通过详细的解释、代码示例和类比来深入探讨 Java 继承的各个方面。
继承概述
继承就像将父母的特性传递给孩子。在 Java 中,它允许一个类(子类)从另一个类(超类)继承属性和行为。这促进了代码重用,并有助于组织和管理相关的类。
Object类及其核心方法
在 Java 中,每个类都隐式地扩展了该类Object
。Object
该类提供了一些所有类都可用的核心方法。其中一些方法包括:
toString()
:返回对象的字符串表示形式。equals(Object obj)
:表示其他对象是否“等于”该对象。hashCode()
:返回对象的哈希码值。
class MyClass {
int value;
// toString method override
@Override
public String toString() {
return "Value: " + value;
}
}
MyClass obj = new MyClass();
obj.value = 10;
System.out.println(obj.toString()); // Outputs: Value: 10
对象比较
Java 提供了equals()
比较对象相等性的方法。默认情况下,它比较内存引用。但是,您可以在类中重写此方法,以提供自定义的比较逻辑。
class Person {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
}
方法覆盖
方法重写允许子类提供其超类中已定义方法的特定实现。这对于提供特定行为非常有用。
class Animal {
void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Dog barks");
}
}
抽象类
抽象类就像其他类的蓝图。它们本身不能被实例化,但可以具有必须由子类实现的抽象方法。
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
double radius;
@Override
double area() {
return Math.PI * radius * radius;
}
}
最终课程
Final 类就像成品一样,无法修改或扩展。您无法创建 Final 类的子类。
final class FinalClass {
// Class definition
}
// Error: Cannot inherit from final class
class SubClass extends FinalClass {
}
Java中的接口
可以将接口视为类必须遵循的契约或一组规则。它定义了实现类必须提供的方法列表,但本身不包含任何实现。
// Interface definition
interface Animal {
void makeSound();
void eat();
}
// Implementing class
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
@Override
public void eat() {
System.out.println("Dog eats bones");
}
}
在这个例子中,Animal
接口定义了两个方法:makeSound()
和eat()
。Dog
类根据接口指定的契约来实现这些方法Animal
。
主要功能和使用场景
接口提供了几个关键功能,通常用于各种场景:
- 多重继承:与类不同,Java 类可以实现多个接口。这允许类从多个来源继承行为。
interface Flyable {
void fly();
}
class Bird implements Animal, Flyable {
// Implement methods from both Animal and Flyable interfaces
}
- 多态性:接口支持多态行为,允许将对象视为其接口类型的实例。这提高了灵活性和代码可重用性。
void performAction(Animal animal) {
animal.makeSound();
animal.eat();
}
- 松耦合:接口有助于系统组件之间的松耦合。类之间通过接口而不是具体的实现进行交互,从而使系统更加模块化,更易于维护。
interface DataAccess {
void saveData(String data);
}
class DatabaseAccess implements DataAccess {
@Override
public void saveData(String data) {
// Save data to the database
}
}
class FileAccess implements DataAccess {
@Override
public void saveData(String data) {
// Save data to a file
}
}
在这个例子中,不同的类可以实现DataAccess
接口来提供不同的数据保存方式,例如保存到数据库或文件。
接口是 Java 编程中强大的工具,它提供了定义契约、实现多态行为以及促进组件之间松散耦合的方法。接口对于构建模块化、灵活且易于维护的软件系统至关重要。
锻炼
使用我们在本节中学到的有关 Java 中的 OOP 的所有知识,让我们以面向对象的风格重建我们的计算器:
// Interface for basic calculator operations
interface Calculator {
double calculate(double num1, double num2);
}
// Addition operation
class Addition implements Calculator {
@Override
public double calculate(double num1, double num2) {
return num1 + num2;
}
}
// Subtraction operation
class Subtraction implements Calculator {
@Override
public double calculate(double num1, double num2) {
return num1 - num2;
}
}
// Multiplication operation
class Multiplication implements Calculator {
@Override
public double calculate(double num1, double num2) {
return num1 * num2;
}
}
// Division operation
class Division implements Calculator {
@Override
public double calculate(double num1, double num2) {
if (num2 != 0) {
return num1 / num2;
} else {
throw new IllegalArgumentException("Error! Division by zero is not allowed.");
}
}
}
// Calculator class encapsulating calculator operations
class BasicCalculator {
private Calculator calculator;
public BasicCalculator(Calculator calculator) {
this.calculator = calculator;
}
public double performCalculation(double num1, double num2) {
return calculator.calculate(num1, num2);
}
}
public class CalculatorApp {
public static void main(String[] args) {
BasicCalculator calculator = new BasicCalculator(new Addition());
double result = calculator.performCalculation(10, 5);
System.out.println("Addition Result: " + result);
calculator = new BasicCalculator(new Subtraction());
result = calculator.performCalculation(10, 5);
System.out.println("Subtraction Result: " + result);
calculator = new BasicCalculator(new Multiplication());
result = calculator.performCalculation(10, 5);
System.out.println("Multiplication Result: " + result);
calculator = new BasicCalculator(new Division());
result = calculator.performCalculation(10, 5);
System.out.println("Division Result: " + result);
}
}
第 3 部分 | 高级 Java 主题
异常处理?
异常是指 Java 程序运行时可能发生的意外事件。就像你在玩游戏时突然发生意外事件,例如断电或控制器电池耗尽。
检查异常:
这些就像是你可以预见的警告信号。就像知道如果你在室内玩球,它可能会损坏某些东西。所以,你会通过更加小心地玩来应对。在 Java 中,你必须处理这类异常,要么捕获它们,要么声明你的方法可能会抛出它们。
未经检查的异常:
这些是你始料未及的意外惊喜。就像赤脚走路时不小心踩到乐高积木一样。哎哟!这些异常并非强制显式处理,但你仍然应该尝试处理它们,以确保程序安全。
Try-Catch 块:
想象一下你正在接一个球。你伸出双手,试图接住它,如果接不住,球就会掉到地上。在 Java 中,你会尝试try
执行一些可能引发异常的操作,catch
如果发生异常,你就会抛出异常,就像接住一个球以防止它掉到地上一样。
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}
最后阻止:
这就像一张安全网。无论发生什么,这段代码总是会运行。就像玩完玩具后要清理一下一样。在 Java 中,它用来finally
确保某些代码无论是否发生异常都会被执行。
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
} finally {
// Code that always runs
}
投掷和投掷:
有时你想成为引发异常的人。这就像说:“我不玩了,我要把球扔回去。” 在 Java 中,你习惯于throw
手动抛出异常。throws
这就像把责任推卸给别人。你声明你的方法可能会抛出某种类型的异常,然后留给调用者去处理。
void myMethod() throws MyException {
// Code that might throw MyException
}
// Somewhere else in the code
try {
myMethod();
} catch (MyException e) {
// Handle MyException
}
泛型:
Java 中的泛型就像神奇的容器,可以容纳任何类型的数据。它们为您的代码提供了灵活性和类型安全性,确保您可以无缝地处理不同类型的数据。让我们深入探索泛型的神奇世界!
类中的泛型:
想象一下,一个宝箱里可以装下各种宝藏——金币、珍贵宝石或古代文物。在 Java 中,你可以使用 创建泛型类<T>
,其中T
表示类型参数。
public class TreasureChest<T> {
private T treasure;
public void store(T item) {
this.treasure = item;
}
public T retrieve() {
return this.treasure;
}
}
方法中的泛型:
现在,设想一根魔杖可以对任何物体施法。在 Java 中,您可以创建操作不同类型数据的泛型方法,从而增强代码的可重用性和灵活性。
public class Magic {
public <T> void castSpell(T target) {
// Perform magic on the target
}
}
通配符:
Java 泛型中的通配符就像特殊的透镜,能让你从不同的视角审视代码。让我们深入泛型的丛林,揭开通配符的秘密!
上限通配符 ( <? extends T>
):
想象一下一张神奇的网,可以捕获所有具有特定特征的生物。在 Java 中,<? extends T>
可以捕获所有 子类型的对象T
,从而让您能够处理各种各样的数据。
public void feedHerbivores(List<? extends Animal> herbivores) {
// Feed the herbivores
}
下界通配符(<? super T>
):
现在,想象一下一道抵御特定危险的防护屏障。在 Java 中,<? super T>
为通配符指定下限,并捕获所有 的超类对象T
,从而确保代码的安全。
public void protectAgainstPredators(List<? super Lion> protections) {
// Set up protections against predators
}
通用方法:
就像熟练的魔术师可以用一根魔杖表演各种魔术一样,Java 中的泛型方法可以对不同类型的数据进行操作,从而增强代码的灵活性和多功能性。
public <T> void performAction(T item) {
// Perform action on the item
}
具有多个类型参数的泛型类:
想象一下一张藏宝图,上面有多个线索,指向隐藏的宝藏。在 Java 中,你可以创建具有多个类型参数的泛型类,从而可以同时处理各种类型的数据。
public class TreasureMap<X, Y> {
private X clue1;
private Y clue2;
// Constructor, getters, and setters
}
收藏:
想象一下,你正在执行一项任务,收集散落在魔法王国的稀世珍宝。Java 集合就像你值得信赖的背包,配备了特殊的隔层来存储和整理你的珍宝。无论是闪闪发光的宝石、古老的文物还是神秘的药水,Java 中的集合都提供了一种灵活的方式来管理和操作你的数据。
集合只是接口!:
在 Java 中,集合由各种接口表示,每个接口都有其独特的特性和功能。可以把接口想象成不同类型的背包的蓝图,每个背包都有其特定的用途。
List<String> backpack = new ArrayList<>(); // A backpack for storing a list of treasures
Set<Integer> pouch = new HashSet<>(); // A pouch for storing unique treasures
Map<String, Integer> chest = new HashMap<>();// A chest for storing treasures with keys
收藏类型:
列表:
想象一下,一串珍宝整齐地排列成一排,就像书架上的书一样。在 Java 中,列表允许你按特定顺序存储元素集合,以便于访问和操作它们。
List<String> backpack = new ArrayList<>();
backpack.add("Golden Sword");
backpack.add("Enchanted Ring");
backpack.add("Magic Potion");
套:
现在想象一下一组独一无二的宝藏,就像一组稀有宝石。在 Java 中,集合确保每个元素都是唯一的,从而防止重复并提供快速检索。
Set<String> pouch = new HashSet<>();
pouch.add("Ruby");
pouch.add("Emerald");
pouch.add("Sapphire");
地图:
最后,设想一张藏宝图,上面有线索指向隐藏的宝藏。在 Java 中,地图将键与值关联起来,这样你就可以根据它们的唯一标识符来检索宝藏。
Map<String, Integer> chest = new HashMap<>();
chest.put("Gold Coins", 100);
chest.put("Silver Bars", 50);
chest.put("Diamonds", 10);
迭代集合:
就像探索王国的广阔景观一样,您可以使用迭代器遍历集合,沿途发现宝藏。
for (String treasure : backpack) {
System.out.println("Found: " + treasure);
}
对集合进行排序:
想象一下,你把你的宝藏按价值从低到高排列起来。在 Java 中,你可以使用比较器对集合进行排序,确保你的宝藏得到高效的整理。
Collections.sort(backpack);
操作集合:
现在设想将两个集合合并起来,创建一个更大的宝藏集合。在 Java 中,你可以使用各种方法来操作集合,例如合并、过滤和转换。
List<String> additionalTreasures = new ArrayList<>();
additionalTreasures.add("Magic Wand");
backpack.addAll(additionalTreasures);
函数式编程:
想象一下,你是一位魔法王国的巫师,挥舞着强大的法术,操控着自然的力量。Java 中的函数式编程就像掌握了古老的施法技艺,让你能够轻松地对数据进行强大的转换。
Lambda 表达式:
在 Java 中,lambda 表达式就像魔法咒语,允许您封装行为并将函数作为参数传递给其他方法。
// Traditional way of defining a Runnable
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello, world!");
}
};
// Using lambda expression
Runnable runnable = () -> {
System.out.println("Hello, world!");
};
供应商:
想象一下,一位神秘的店主,他能凭空变出你想要的任何物品。在 Java 中,供应商就像这位店主一样,提供了一种在需要时延迟生成或提供值的方法。
Supplier<Integer> randomNumber = () -> (int) (Math.random() * 100);
System.out.println(randomNumber.get()); // Output: A random number between 0 and 100
谓词:
想象一下,你是一位睿智的巫师,一眼就能辨别真假。在 Java 中,谓词就像你的魔眼,可以让你测试条件,并根据条件过滤元素。
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // Output: true
System.out.println(isEven.test(5)); // Output: false
消费者:
现在,想象一下一位仁慈的仙女,她会消除你的烦恼,给你留下一片宁静。在 Java 中,消费者就像这位仙女一样,接受值并执行操作,但不返回任何值。
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
printUpperCase.accept("magic"); // Output: MAGIC
功能:
最后,想象一下一位神奇的炼金术士,能将一种物质转化为另一种物质。在 Java 中,函数就像这位炼金术士,接受一个输入,并根据某种变换产生另一个输出。
Function<Integer, String> convertToString = num -> "Number: " + num;
System.out.println(convertToString.apply(42)); // Output: Number: 42
Java 流:
在 Java 中,流是元素序列,支持各种方法来对这些元素执行操作。可以将它们想象成流经数据的神奇管道,允许你对流经的每个元素执行操作。
流中的函数式接口
流使用函数式接口来执行其工作。这些接口(例如消费者、谓词、供应商和函数)为可传递给流操作的行为提供了蓝图。
流中的消费者:
消费者就像神奇的观察者,接受单个输入并执行某些操作而不返回任何内容。在流中,消费者用于执行终端操作,即消费流中的元素。
List<String> ingredients = Arrays.asList("Eye of newt", "Wing of bat", "Tooth of wolf");
// Printing each ingredient using a consumer
ingredients.stream()
.forEach(System.out::println);
流中的谓词:
谓词就像神奇的过滤器,可以测试条件并返回 true 或 false。在流中,谓词用于根据特定条件过滤元素。
// Filtering ingredients that contain "bat"
ingredients.stream()
.filter(ingredient -> ingredient.contains("bat"))
.forEach(System.out::println);
流中的供应商:
供应商就像神奇的提供者,在需要时惰性生成或提供值。在流中,供应商并不常用,但它们在某些流操作中发挥着作用。
// Generating a stream of random numbers using a supplier
Stream<Integer> randomNumberStream = Stream.generate(() -> (int) (Math.random() * 100));
流中的函数:
函数就像神奇的变压器,接受一个输入,并根据某种转换产生另一个输出。在流中,函数用于将元素映射到另一种形式。
// Converting ingredients to uppercase using a function
ingredients.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
并发和多线程:
并发是程序同时执行多个任务的能力,允许它一次执行多个任务。
什么是线程?
线程就像船上的独立水手,每个水手负责执行一项特定的任务。在 Java 中,你可以创建和管理线程来并发执行任务。
创建线程:
在 Java 中,可以通过扩展 Thread 类或实现 Runnable 接口来创建线程。让我们创建一个打印消息的简单线程。
class MyThread extends Thread {
public void run() {
System.out.println("Hello from MyThread!");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Start the thread
}
}
实现 Runnable:
或者,您可以实现 Runnable 接口并将其传递给 Thread 对象。
class MyRunnable implements Runnable {
public void run() {
System.out.println("Hello from MyRunnable!");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // Start the thread
}
}
同步:
想象一下,你的水手们试图同时访问一个共享资源,比如一个宝箱。Java 中的同步机制确保同一时间只有一个线程可以访问代码的关键部分,从而避免冲突并确保线程安全。
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
执行者:
可以将执行器视为管理者,负责监督一组水手(线程)并高效地为他们分配任务。执行器为管理线程和异步执行任务提供了更高级别的抽象。
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new MyTask());
executor.shutdown();
结论
在本指南中,我们深入讲解了 Java 编程的基本概念,探索了面向对象编程 (OOP) 的复杂性,并深入探讨了能够充分释放 Java 潜力的高级主题。从设置开发环境到掌握控制流、类、对象、继承、接口等,您已经对 Java 的核心原理和特性有了深入的理解。
随着我们结束对 Java 101 的探索,很明显,你在成为一名熟练的 Java 程序员的道路上已经取得了长足的进步。掌握了这些知识,你将能够应对现实世界中的编码挑战,并满怀信心地开展激动人心的项目。
但旅程并未就此结束。在接下来的冒险中,我们将深入探索数据结构和算法的迷人世界——它们是计算机科学和软件开发的基石。我们将携手揭开数据组织、算法效率和问题解决技巧的奥秘,将您的编程技能提升到新的高度。
所以,敬请期待我们的下一章,我们将继续探索编程和软件开发领域的精髓。在此之前,请继续编码,继续学习,让你对 Java 的热情点燃你迈向卓越的旅程!
鏂囩珷鏉ユ簮锛�https://dev.to/louaiboumediene/java-101-zero-to-hero-course-4jna