1. Hello World

2. 变量

在Java中,变量的定义包括变量的声明和初始化。声明是指定义变量的名称和类型,而初始化是指将一个值赋值给变量。

变量声明需要指定变量的数据类型。Java中的数据类型分为两类:基本数据类型和引用数据类型。基本数据类型是Java编程语言中内置的数据类型(如int、boolean、char等),它们有固定的长度和取值范围。引用数据类型是指使用对象来存储数据的数据类型(如字符串、数组、类等),它们实际上是对基本数据类型的封装。

在Java中,变量的声明格式如下:

数据类型 变量名;

例如,声明一个整型变量:

int num; // 声明一个整型变量num

在变量声明之后,可以使用赋值语句来初始化变量。赋值语句使用等号(=)来将右侧的值赋给变量。例如:

int num; // 声明一个整型变量num
num = 10; // 给变量num赋值为10

也可以在声明变量时直接进行初始化,例如:

int num = 10; // 声明一个整型变量num并赋值为10

在使用变量之前,必须先对它进行声明和初始化。如果未对变量进行初始化,它将包含默认值(如数字类型的默认值为0)。

此外,Java还支持常量的定义。常量是指在程序执行期间值不能被改变的变量。在Java中,可以使用关键字final来声明常量。例如:

final double PI = 3.141592653589793; // 定义一个常量PI

当使用关键字final声明变量时,该变量的值一旦被赋值就不能被更改。

3. 条件分支

在Java语言中,条件分支语句用于根据条件来决定程序的执行路径。Java语言中存在两种类型的条件分支语句:if语句和switch语句。

if语句是Java中最基本的条件分支语句,它的语法格式如下:

if (条件) {
    // 如果条件成立,执行的代码
}

其中,条件是一个布尔表达式,如果该条件为true,就会执行后面的代码块中的语句。如果该条件为false,则会跳过代码块并顺序执行后面的语句。如果需要在条件不成立时执行另一组代码,可以使用if-else语句。if-else语句的语法格式如下:

if (条件) {
    // 如果条件成立,执行的代码
} else {
    // 如果条件不成立,执行的代码
}

如果有多个判断条件,可以使用if-else-if语句。if-else-if语句的语法格式如下:

if (条件1) {
    // 如果条件1成立,执行的代码
} else if (条件2) {
    // 如果条件2成立,执行的代码
} else if (条件3) {
    // 如果条件3成立,执行的代码
} else {
    // 如果所有条件都不成立,执行的代码
}

switch语句是一种更灵活的条件分支语句,它允许将多个可能的执行路径表示为不同的case语句,并根据某个表达式的值来选择其中之一。switch语句的语法格式如下:

switch (表达式) {
    case 值1:
        // 如果表达式的值等于值1,执行的代码
        break;
    case 值2:
        // 如果表达式的值等于值2,执行的代码
        break;
    case 值3:
        // 如果表达式的值等于值3,执行的代码
        break;
    default:
        // 如果表达式的值与所有情况都不匹配,执行的代码
        break;
}

其中,表达式通常是一个整型常量、枚举类型或字符常量。当switch语句执行时,会依次检查每个case语句是否匹配表达式的值,如果匹配,就会执行该case语句中的代码块。如果没有匹配的情况,则会执行default语句中的代码块。在switch语句中,每个case语句都应该以break语句结尾,以防止“落入”下一个case中。

4. 循环

Java语言中的循环语句用于重复执行一组代码。在Java语言中,有三种类型的循环语句:for循环、while循环和do-while循环。下面分别介绍这三种循环语句。

  1. for循环

for循环语句用于按照一定次数重复执行一组代码。它的语法格式如下:

for (初始化表达式; 循环条件; 更新表达式) {
    // 循环体
}

其中,初始化表达式是一个初始条件,循环条件是一个布尔表达式,只有当该条件为true时,循环体中的代码才会被执行。每次循环结束,都会执行更新表达式,然后再次检查循环条件是否为true。如果循环条件仍然为true,则继续执行循环体,重复上述步骤,直到循环条件为false。

例如:

for (int i = 0; i < 5; i++) {
    System.out.println("i = " + i);
}

上述代码将会输出:

i = 0
i = 1
i = 2
i = 3
i = 4
  1. while循环

while循环语句用于在循环条件为true的情况下重复执行一组代码。它的语法格式如下:

while (循环条件) {
    // 循环体
}

其中,循环条件是一个布尔表达式,只有当该条件为true时,循环体中的代码才会被执行。每次循环结束,都会检查循环条件是否为true。如果循环条件仍然为true,则继续执行循环体,重复上述步骤,直到循环条件为false。

例如:

int i = 0;
while (i < 5) {
    System.out.println("i = " + i);
    i++;
}

上述代码将会输出:

i = 0
i = 1
i = 2
i = 3
i = 4
  1. do-while循环

do-while循环语句与while循环语句类似,只是它先执行一次循环体中的代码,然后再检查循环条件是否为true。它的语法格式如下:

do {
    // 循环体
} while (循环条件);

其中,循环条件是一个布尔表达式,只有当该条件为true时,循环体中的代码才会被执行。每次循环结束,都会检查循环条件是否为true。如果循环条件仍然为true,则继续执行循环体,重复上述步骤,直到循环条件为false。

例如:

int i = 0;
do {
    System.out.println("i = " + i);
    i++;
} while (i < 5);

上述代码将会输出:

i = 0
i = 1
i = 2
i = 3
i = 4

以上就是Java语言中常用的三种循环语句的使用方法。在实际开发过程中,应根据具体需求选择使用合适的循环语句。

Java语言中的foreach循环是一种简化for循环的语法。foreach循环能够自动迭代数组或集合中的元素。其语法格式如下:

for (元素类型 元素变量 : 数组或集合) {
    // 循环体
}

其中,元素类型表示数组或集合中元素的数据类型,元素变量表示每次迭代时要将当前元素存储在该变量中。数组或集合表示要迭代的数组或集合。

例如,下面的代码将使用foreach循环遍历一个字符串数组:

String[] strArr = {"Hello", "World", "!"};

for (String str : strArr) {
    System.out.println(str);
}

上述代码将会输出:

Hello
World
!

使用foreach循环时,无法直接修改数组或集合中的元素。如果需要修改数组或集合中的元素,可以使用原始的for循环或while循环来实现。

需要注意的是,如果要遍历的数组或集合为null,将会抛出NullPointerException异常。因此,在使用foreach循环前应该判断数组或集合是否为null。

5. 函数

在Java语言中,函数通常称为方法(Method)。方法是执行某个指定任务的部分代码。在Java中,方法必须属于一个类。Java中的方法包括静态方法和非静态方法两种。

  1. 静态方法

静态方法是一种独立于任何对象而存在的方法。可以直接通过类名调用静态方法,而不需要实例化该类。静态方法通常用于实现和对象无关的操作,如数学计算等。在方法定义时,需要使用static关键字来修饰方法。静态方法的语法格式如下:

修饰符 static 返回值类型 方法名 (参数列表) {
    // 方法体
}

例如,下面的代码定义了一个简单的静态方法,用于计算两个数的和:

public static int sum(int a, int b) {
    return a + b;
}
  1. 非静态方法

非静态方法必须属于一个对象,在方法调用时,必须先创建一个对象,然后通过该对象来调用方法。非静态方法通常用于访问或修改对象的属性,以及执行和对象相关的操作。在方法定义时,不需要使用static关键字来修饰方法。非静态方法的语法格式如下:

修饰符 返回值类型 方法名 (参数列表) {
    // 方法体
}

例如,下面的代码定义了一个简单的非静态方法,用于将一个字符串转换为大写:

public String toUpper(String str) {
    return str.toUpperCase();
}
  1. 方法参数

方法参数是用于接收外部数据的变量,可以在调用方法时传递给方法。在Java中,方法参数需要在方法声明时进行定义。方法参数可以是基本数据类型、类类型或数组类型。

例如,下面的代码定义了一个方法,用于计算两个数的乘积:

public static int multiply(int a, int b) {
    return a * b;
}

在调用该方法时,需要传递两个参数,如下所示:

int result = multiply(2, 3);

在调用方法时,参数的传递方式可以是值传递或引用传递。对于基本数据类型,采用的是值传递方式,即方法中对参数进行修改不会影响原有数据;对于对象类型,则采用的是引用传递方式,即方法中对参数所引用的对象进行修改会影响原有数据。

  1. 方法返回值

方法返回值是指方法执行后返回给调用者的结果。在Java中,方法可以有返回值,也可以没有返回值。如果方法有返回值,需要在方法声明时通过返回类型来指定,返回值类型可以是任意数据类型。

例如,下面的代码定义了一个方法,用于计算两个数的除法,返回结果为浮点数:

public static double divide(double a, double b) {
    return a / b;
}

在调用该方法后,可以将返回值保存到一个变量中,如下所示:

double result = divide(10.0, 3.0);

需要注意的是,方法调用时,返回值可以直接输出到控制台,也可以作为方法调用的参数。

6. 包

在Java中,包(package)是一种用于组织类和接口的名字空间。它将类和接口分组,以便更好地管理和维护代码。Java中的包可以嵌套使用,形成层次化的命名空间。可以从Java API库中导入预定义的类和接口,也可以自定义包以实现更复杂的功能。

Java中使用关键字package来定义一个包,每个Java文件都应该属于一个包(如果没有被显式地定义,则默认属于默认包)。

  1. 定义包

定义包可以使用以下语法格式:

语法格式:

package 包名;

例如,下面的代码定义了一个名为com.example的包:

package com.example;

定义包时,可以使用固定的包层级结构,将类和接口组织成一个层次结构。例如,下面的代码将定义一个名为com.example.utils的包:

package com.example.utils;
  1. 导入包

在Java中,为了在一个Java文件中使用另一个包中的类或接口,我们需要使用import语句将其导入到当前文件中。

语法格式:

import 包名.类名;

例如,下面的代码导入了java.util包下的Date类:

import java.util.Date;

还可以使用通配符*来导入指定包中的所有类和接口:

语法格式:

import 包名.*;

例如,下面的代码将导入java.util包下的所有类和接口:

import java.util.*;

需要注意的是,在导入类或接口时,应该尽量避免使用通配符*,而是应该明确地指定需要导入的类或接口,以提高代码的可读性和可维护性。

导入多个包或类时,可以在同一行中用逗号将它们分隔开,例如:

import java.util.Date, java.util.List;
  1. 包名的命名规范

在Java中,包名的命名应该是按照以下规范来进行的:

  • 包名应该全小写。
  • 包名应该以自己的域名反转的形式命名,例如:com.example。
  • 包名中的每个单词都应该是有意义的,不应该使用缩写。
  • 包名中的每个单词之间应该使用.进行分隔。

例如,如果你的网站域名为example.com,那么你可以为你的代码包起名com.example.utils,其中utils是这个包中类和接口的主要功能。

7. 数组

7.1 定长数组

在Java语言中,数组是一种数据结构,用于存储一系列具有相同数据类型的值。Java中的数组是固定长度的,它的大小在创建数组时就已经确定,不能再改变。数组中的元素可以通过下标进行访问和操作。

Java中的数组可以是任意数据类型,包括基本数据类型和引用数据类型。数组变量是一个引用类型,指向数组实际存储的位置。Java中的数组有一些常用的操作,如声明数组、初始化数组、访问数组元素等。

  1. 声明数组

在Java中声明数组时,需要指定数组的数据类型和数组名称,如下所示:

dataType[] arrayName;

其中,dataType表示数组中元素的数据类型,arrayName表示数组的名称。

例如,下面的代码声明了一个名为intArray的整数型数组:

int[] intArray;
  1. 初始化数组

在Java中,可以通过以下方式来初始化数组:

  • 静态初始化:在创建数组时给数组元素赋初值。
  • 动态初始化:先声明数组,再通过循环或指定每个元素来给数组元素赋值。

静态初始化的语法格式如下:

dataType[] arrayName = {value1, value2, ..., valueN};

例如,下面的代码声明并初始化了一个名为intArray的整数型数组:

int[] intArray = {1, 2, 3, 4, 5};

动态初始化的语法格式如下:

dataType[] arrayName = new dataType[length];

其中,length是指数组元素的个数。

例如,下面的代码声明并初始化了一个长度为5的整数型数组:

int[] intArray = new int[5];
  1. 访问数组元素

在Java中,可以使用下标来访问数组元素。下标从0开始,依次递增。例如,要访问数组中的第二个元素,可以使用下标1,如下所示:

int secondNum = intArray[1];

需要注意的是,在访问数组元素时,下标的范围应该在0到数组长度之间,否则将抛出ArrayIndexOutOfBoundsException异常。

  1. 遍历数组

在Java中,可以使用for循环或foreach循环来遍历数组。

使用for循环遍历数组时,需要通过索引来访问数组元素。例如,下面的代码使用for循环遍历了一个整数型数组:

for (int i = 0; i < intArray.length; i++) {
    System.out.println(intArray[i]);
}

使用foreach循环遍历数组时,可以直接访问数组的每个元素,如下所示:

for (int num : intArray) {
    System.out.println(num);
}

需要注意的是,在使用foreach循环遍历数组时,无法直接修改数组元素的值。如果要修改数组元素的值,应该使用for循环并通过索引访问数组元素进行修改。

7.2 可变数组

在Java中,List是一种有序集合,可以存储一系列具有相同数据类型的元素。List是Java Collection框架中最基本的数据结构之一,其中的元素和数组一样可以通过下标进行访问和操作。

Java中的List接口定义了一系列常用的方法,如添加元素、删除元素、获取元素、遍历元素等。List是一个接口,不能直接被实例化,需要使用它的实现类来创建List对象。

常用的List实现类有ArrayList、LinkedList和Vector。其中,ArrayList和LinkedList是最常用的实现类。

  1. List的定义和创建

List是一个接口,可以使用它的实现类来创建List对象。下面是创建List对象的语法格式:

List<dataType> list = new ArrayList<dataType>();

其中,dataType表示List中元素的数据类型,例如下面是创建一个存储整数的List对象的代码:

List<Integer> list = new ArrayList<Integer>();

在Java 7之前,如果没有指定泛型类型,创建List对象时需要显示地指定Object类型,例如:

List list = new ArrayList();
  1. List的基本操作

使用List的常用操作包括添加元素、删除元素、获取元素、遍历元素等。

在List中添加元素使用add()方法,可以在指定位置添加元素或在末尾添加元素。例如,在List的末尾添加一个整数:

list.add(123);

在List的指定位置添加一个元素:

list.add(index, element);

其中,index表示插入位置,element表示插入的元素。

在List中删除元素使用remove()方法,可以删除指定位置的元素或删除指定元素。例如,删除List中的第一个元素:

list.remove(0);

删除List中指定的元素:

list.remove(element);

获取List中的元素使用get()方法,可以获取指定位置的元素。例如,获取List中的第一个元素:

list.get(0);

使用set()方法可以修改List中指定位置的元素。例如,将List中的第一个元素设置为100:

list.set(0, 100);

8. Map

在Java中,Map是一种键值对存储结构,可以根据给定的键查找相应的值。Map是Java Collection框架中最常用的数据结构之一,提供了查找、插入和删除元素的高效方法。Map中的键是唯一的,值可以重复。

Java中的Map有多种实现类,其中最常用的是HashMap和TreeMap。

  1. Map的创建和定义

在Java中,用Map<keyType, valueType>语法定义一个Map对象,其中keyTypevalueType表示Map中键和值的数据类型。例如,我们可以创建一个名为personMap的Map对象,用来存储人名和对应的手机号码:

Map<String, String> personMap = new HashMap<String, String>();

这里的String是指Map中键和值的数据类型都是字符串。

  1. Map的操作
  • 向Map中添加键值对

使用put()方法向Map中添加键值对,示例如下:

personMap.put("Alice", "123456789");
personMap.put("Bob", "234567890");

添加键值对时,如果指定的键已存在,则会覆盖原有值。

  • 获取Map中的值

使用get()方法可以获取指定键对应的值,示例如下:

String phoneNum = personMap.get("Alice");

如果指定的键不存在,则返回null

  • 删除Map中的键值对

使用remove()方法可以删除指定键对应的键值对,示例如下:

personMap.remove("Bob");
  • 判断Map中是否包含指定的键或值

使用containsKey()方法可以判断Map中是否包含指定的键,示例如下:

boolean hasName = personMap.containsKey("Alice");

使用containsValue()方法可以判断Map中是否包含指定的值,示例如下:

boolean hasPhoneNum = personMap.containsValue("123456789");
  • 遍历Map中的所有键值对

使用entrySet()方法可以遍历Map中的所有键值对,示例如下:

for (Map.Entry<String, String> entry : personMap.entrySet()) {
    String name = entry.getKey();
    String phoneNum = entry.getValue();
    System.out.println("Name: " + name + ", Phone Number: " + phoneNum);
}

在上述示例中,entrySet()方法返回一个包含所有键值对的Set集合,其中每个键值对通过一个Map.Entry对象表示。然后使用增强型for循环遍历每个Map.Entry对象,从而遍历所有的键值对。

正如示例所示,我们可以使用getKey()方法获取Map中的键,使用getValue()方法获取Map中的值。

9. 指针

Java语言中没有指针的概念。Java通过引用来操作对象,引用可以看作是一种类似于指针的概念,但是与C/C++指针稍有不同。

在Java中,变量的实际值是存储在内存中的对象的引用,而不是对象本身。在Java中,可以通过使用new关键字来创建对象,并将返回的对象引用赋值给变量。例如:

MyObject obj = new MyObject();

在此示例中,obj是一个MyObject类型的引用,指向存储在堆内存中的MyObject对象。在Java中,对于普通对象,可以通过以下方式进行操作:

  • 对象的创建和初始化:使用new运算符来创建新对象,并将它的引用保存到变量中。
  • 对象的访问:可以通过引用来调用对象的方法或者访问对象的属性。
  • 对象的传递:可以将对象的引用作为参数传递给方法。
  • 对象的销毁:Java有自己的垃圾回收机制,当对象不再被引用时,会自动被销毁。

从上述描述可以看出,Java中引用的使用与指针类似,但是Java中的引用不支持地址运算,而且Java中引用的类型是强类型,即引用类型必须与对象类型相同或是它的子类型。这一点与C/C++指针有所不同,C/C++指针可以声明为void类型,也可以进行指针运算,容易造成内存泄漏和指针越界等问题。因此,Java中没有指针的概念,而是使用安全可控的引用来操作对象。

10. 闭包

闭包是一种函数概念,Java中存在函数式编程语言特性,但是Java本身不支持闭包。闭包通常用于函数式编程中,是指一个函数捕获了外部环境中的变量,并返回一个函数,新函数可以继续访问外层函数中的变量。闭包是一种非常强大的编程工具,可以产生非常精简和简洁的代码,提高编程效率。

Java中的函数式编程是从Java 8版本开始引入的,它引入了Lambda表达式和函数式接口,这些特性允许在Java中使用函数式编程的概念,不过并不涉及到闭包的实现。

Lambda表达式是一种简洁、清晰、灵活的函数表达方式,可以替代匿名类。Lambda表达式可以传递一个函数作为参数,并将其返回,可以用于编写高阶函数和链式处理技术。例如,下面的示例创建了一个Lambda表达式,将一个字符串列表转换为大写格式:

List<String> names = Arrays.asList("apple", "orange", "banana", "blueberry");
List<String> upperCaseNames = names.stream()
  .map(name -> name.toUpperCase())
  .collect(Collectors.toList());

在上述代码中,map()方法接受一个Lambda表达式作为参数,该Lambda表达式用于将每个字符串转换为大写格式。

函数式接口定义了一个抽象方法,可以用Lambda表达式创建该抽象方法的实现。函数式接口典型的示例包括Runnable、Comparator和ActionListener等。Java中的函数式接口可以使用@FunctionalInterface进行标注,用于检查接口是否符合函数接口定义。

总之,虽然Java不支持闭包的概念,但Java8以下版本的Java平台可以使用匿名内部类等技术来实现类似于闭包的功能。而Java8及以后的版本中,通过Lambda表达式和函数式接口,Java引入了函数式编程的特性,可以用一种更加简洁、清晰的方式进行编程。

Lambda表达式是Java 8引入的一个重要特性,它允许以更加简洁的代码实现函数式编程。Lambda表达式本质上是一个匿名函数,可以在需要时直接定义和使用,无需定义成具名函数。Lambda表达式非常适合用于函数接口的实现,可以让代码更加紧凑、易读、易维护。下面是Java中Lambda表达式的一些简单示例:

  1. Lambda表达式定义

Lambda表达式的定义格式为:(参数列表) -> {函数体}。其中,参数列表是表示接受的参数的一系列参数名称,参数可以为空;箭头符号->用于分隔参数列表和函数体,它表明这是一个Lambda表达式;函数体可以是一个语句表达式或一个代码块。例如,下面是一个简单的Lambda表达式定义示例:

(str) -> System.out.println(str)

上述示例中,Lambda表达式表示:接受一个参数str,输出参数值到控制台。

  1. 使用Lambda表达式创建线程

在Java中,可以使用Lambda表达式快速创建一个线程。下面是一个使用Lambda表达式创建线程的示例:

Thread t = new Thread(() -> System.out.println("Hello, world!"));
t.start();

上述示例中,使用Lambda表达式创建了一个新的线程对象,并在该线程中输出一条简单的消息。

  1. Lambda表达式与集合的配合使用

在Java 8中,集合中新增了许多与Lambda表达式配合使用的API,省去了很多冗余的代码。例如,可以使用Lambda表达式对集合中的元素进行过滤、映射、排序等操作。下面是使用Lambda表达式对列表进行排序和输出的示例:

List<String> list = Arrays.asList("banana", "apple", "pear", "orange");
Collections.sort(list, (a, b) -> a.compareTo(b));
list.forEach(str -> System.out.println(str));

上述示例中,使用Lambda表达式对列表进行排序,然后输出结果。

Java的Lambda表达式是Java 8引入的一项新特性,它非常适合编写简洁、清晰和灵活的代码。Lambda表达式可以用来替代匿名类,用于传递一些简单的行为,并且支持函数式接口的自动推导。

下面举例说明Lambda表达式的使用:

假设我们有一个保存人类信息的类Person:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

现在我们需要实现一个将人类列表排序的功能,按照年龄升序排列,如果年龄相等则按照姓名升序排列。传统的排序方式可以使用Comparator接口,下面是传统的Comparator实现方式:

List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 25));
personList.add(new Person("Bob", 30));
personList.add(new Person("Cathy", 20));
personList.sort(new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        if (o1.getAge() == o2.getAge()) {
            return o1.getName().compareTo(o2.getName());
        } else {
            return o1.getAge() - o2.getAge();
        }
    }
});

在Java 8使用Lambda表达式实现同样的排序功能:

personList.sort((o1, o2) -> {
    if (o1.getAge() == o2.getAge()) {
        return o1.getName().compareTo(o2.getName());
    } else {
        return o1.getAge() - o2.getAge();
    }
});

Lambda表达式使用箭头符号(->)将参数列表与Lambda体分隔开来。在上述示例中,(o1, o2)是参数列表,Lambda体部分是方法体。Lambda体可以是一个表达式或一个代码块。当Lambda体只有一行代码时,可以省略花括号和return语句,例如:

personList.sort((o1, o2) -> o1.getAge() - o2.getAge());

在上述示例中,Lambda体只有一行代码,因此可以省略花括号和return语句,并且根据代码自动推导出返回值类型。

Lambda表达式可以结合函数强制类型转换使用,这样可以将Lambda表达式作为方法参数传递。例如,使用Predicate接口的方法,其功能是判断一个人是否成年:

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

public static void checkAge(List<Person> personList, Predicate<Person> predicate) {
    for (Person person : personList) {
        if (predicate.test(person))
            System.out.println(person.getName() + " is an adult");
        else
            System.out.println(person.getName() + " is a child");
    }
}

当使用Lambda表达式作为方法参数时,可以省略Lambda体和参数类型,例如:

checkAge(personList, person -> person.getAge() >= 18);

在上述示例中,Lambda表达式(person -> person.getAge() >= 18)实现了Predicate接口的方法,并作为checkAge()方法的参数传递。

Lambda表达式是Java 8新特性之一,可以简化Java编程语言的语法结构,并提供更加简洁、清晰和灵活的编程方式。Lambda表达式的使用可以提高代码的可读性和可维护性,值得开发者们深入学习。

11. 类

Java中没有结构体(struct)这一概念,但是从使用上来看,可以通过一些其他的方式来代替结构体的功能,例如使用类来表示结构体的字段和方法。

在Java中,我们可以定义一个类来代替一个结构体,并在类中包含一个或多个字段(成员变量)来表示结构体中的不同属性。例如,我们可以定义一个名为Point的类来表示一个点的坐标,定义x和y两个整数类型的字段代表坐标值,如下所示:

public class Point {
    public int x;
    public int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

上面的代码定义了一个Point类,该类包含x和y两个整数类型的成员变量,并有一个构造函数用于初始化这些成员变量。

使用上述类来表示一个点的坐标非常方便,可以进行如下的操作:

Point p = new Point(10, 20);
System.out.println("p.x = " + p.x); // 输出:p.x = 10
System.out.println("p.y = " + p.y); // 输出p.y = 20

除了使用类来代替结构体,Java中也提供了许多其他的数据结构,例如:

  • 数组:使用数组可以很容易地表示一组多个相同类型的数据。
  • 枚举:可以使用枚举来表示一组有限的可能的值,为每个可能的值指定一个枚举常量,从而增强了代码的可读性。
  • 元组:元组是一种特殊的结构体,它包含了多个元素,可以使用Java中的元组库,如javatuples,来实现。

总之,Java中没有结构体这一概念,但是可以通过定义类、使用数组、枚举、元组等方式来实现与结构体相似的功能。

在Java中,类可以被看作是一种代码模板,用于定义对象的属性和行为。可以通过类来表示现实世界中的一些实体,例如人、动物、车等等。

Java类的定义通常包含以下几个部分:

  1. 访问修饰符(Access Modifiers):用来控制其他程序组件是否能够访问该类。

    • public:类可以被任何一个类或者接口访问。
    • protected:类可以被同一包内的所有类和派生类访问。
    • default(即不指定修饰符):类只能被同一包内的类和接口访问。
    • private:类只能被该类内部的方法访问。
  2. Class关键字:用于告诉Java编译器,接下来的代码是一个类的定义。

  3. 类名:以大写字母开头,命名规范通常是使用驼峰命名法,即每个单词首字母大写,单词之间没有下划线。

  4. 继承关系(可选):用extends关键字来指定该类所继承的父类,以获取父类的所有属性和方法。

  5. 实现接口(可选):用implements关键字来指定该类所实现的接口,以获取接口中定义的所有方法。

  6. 类体:用一对花括号"{ }“包含,包括类中定义的属性和方法。

例如,以下是一个Java语言中class的定义实例。

假设我们要定义一个简单的学生类,其中包含学生的姓名(name)、学号(id)、年龄(age)、性别(gender)、所在学校(school)等属性,还有方法可以输出学生信息和修改学生信息等功能。

可以通过如下代码定义这个类:

public class Student {
    // 姓名
    private String name;
    // 学号
    private String id;
    // 年龄
    private int age;
    // 性别
    private String gender;
    // 学校
    private String school;
   
    /**
     * 学生类的构造函数
     * @param name 学生姓名
     * @param id 学生学号
     * @param age 学生年龄
     * @param gender 学生性别
     * @param school 学生所在学校
     */
    public Student(String name, String id, int age, String gender, String school) {
        this.name = name;
        this.id = id;
        this.age = age;
        this.gender = gender;
        this.school = school;
    }

    /**
     * 输出学生信息
     */
    public void showInfo() {
        System.out.println("姓名:" + name);
        System.out.println("学号:" + id);
        System.out.println("年龄:" + age);
        System.out.println("性别:" + gender);
        System.out.println("所在学校:" + school);
    }

    /**
     * 修改学生信息
     * @param name 学生姓名
     * @param age 学生年龄
     * @param gender 学生性别
     * @param school 学生所在学校
     */
    public void modifyInfo(String name, int age, String gender, String school) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.school = school;
    }
}

在上述代码中,我们首先使用class关键字定义了一个名为Student的公共类,并声明了学生的姓名、学号、年龄、性别和所在学校这五个成员变量,均为私有属性,只能通过公共方法进行访问和修改。

然后,在这个类中,我们定义了一个构造函数public Student(String name, String id, int age, String gender, String school),用于对学生对象进行初始化。

接下来,定义了一个共有方法public void showInfo(),用于输出学生的信息,方法中使用了成员变量的值。

最后,定义了一个共有方法public void modifyInfo(String name, int age, String gender, String school),用于修改学生的信息,方法中对成员变量的值进行了修改。

总之,使用class关键字定义一个类非常简单,只需遵循类的命名规范,在类中定义成员变量和方法,即可创建一个自定义的类。然后,我们可以创建对象并使用它的属性和方法进行各种操作。

12. 接口

在Java中,接口(Interface)是一种特殊的抽象类,没有任何实现的方法,仅包含方法声明、常量和嵌套类型。

接口的定义使用关键字interface,其语法如下:

[访问修饰符] interface 接口名 [extends 扩展接口名] {
    // 声明常量
    [访问修饰符] [static] [final] 数据类型 常量名 = 值;

    // 声明方法
    [访问修饰符] [default] [abstract] 返回类型 方法名([参数列表]);

    // 嵌套类型
}

其中:

  • 访问修饰符:可以是public、protected或默认访问修饰符。
  • 接口名:接口的名称,遵循Java标识符规则,采用驼峰式命名法。
  • extends 扩展接口名:可以继承一个或多个接口,用逗号分隔。
  • 常量:使用final修饰符的变量。接口中的常量默认是public、static和final的,因此可以直接通过接口名来访问。
  • 方法:只包含方法的声明,没有实现,使用abstract或default修饰符。接口中的方法默认是public的,不能为方法声明提供实现。
  • 嵌套类型:可以在接口中定义其他类型,包括类、接口和枚举等类型。

Java中的接口有以下特点:

  1. 接口只包含常量和方法的声明,没有方法的实现。
  2. 接口中的方法默认是public,不能为方法声明提供实现。
  3. 接口可以被类实现,一个类可以实现多个接口。
  4. 接口可以继承一个或多个其他接口。
  5. 接口中的方法可以使用default关键字实现默认行为。

以下是一个简单的接口的示例:

public interface Animal {
    int LEGS = 4; // 常量

    void eat(); // 无实现的抽象方法

    default void run() { // 使用default关键字实现默认行为
        System.out.println("跑步");
    }
}

上述接口定义了一个叫做Animal的接口,包含一个常量LEGS和一个抽象方法eat,以及一个使用default关键字实现默认行为的方法run。

在实现该接口时,需要使用implements关键字,类似于继承的语法,如下所示:

public class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public static void main(String[] args) {
        Cat cat = new Cat();
        System.out.println("猫有" + LEGS + "条腿");
        cat.eat();
        cat.run();
    }
}

在上述代码中,我们定义了一个实现了Animal接口的Cat类,并实现了eat方法。在main方法中,我们实例化了一个Cat对象,并调用了它的eat和run方法。

总之,Java中的接口提供了一种机制,用于规范类的行为。通过在接口中定义方法和常量,可以使得实现类按照规范实现相应的功能。同时,接口还可以被继承和实现,用于解决多重继承的问题。

13. WEB

在Java中,Servlet是一种基于服务器的Java编程模型,用于生成动态Web页面。与CGI程序类似,Servlet程序也可以接受HTTP请求并生成动态内容。下面简单介绍一下使用Java的Servlet来实现CGI程序的过程。在中编写Servlet也非常简单,下面提供Spring Boot示例代码来演示如何编写Servlet。

  1. 创建Servlet类

首先,创建一个Servlet类,例如:

@WebServlet(urlPatterns={"/hello"})
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
        // 设置响应内容类型
        resp.setContentType("text/html;charset=UTF-8");

        // 输出响应内容
        PrintWriter out = resp.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.println("<h1>Hello,Servlet!</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

在上述代码中,我们使用@WebServlet注解来标记这个Servlet,设置它的请求路径为”/hello"。然后,重写doGet方法来实现具体的Servlet逻辑,设置响应的内容类型和输出内容。

  1. 配置Servlet

接下来,需要在Spring Boot应用程序中注册和配置这个Servlet。在Spring Boot中,可以通过使用ServletRegistrationBean来注册Servlet,例如:

@Configuration
public class ServletConfig {
    @Bean
    public ServletRegistrationBean<HelloServlet> helloServletRegistrationBean() {
        ServletRegistrationBean<HelloServlet> registrationBean =
            new ServletRegistrationBean<>(new HelloServlet(), "/hello");
        return registrationBean;
    }
}

在上述配置中,我们定义了一个名为helloServletRegistrationBean的注册Bean,将HelloServlet注册到"/hello"路径下,并返回一个ServletRegistrationBean对象。

  1. 运行应用程序

在完成上述两个步骤后,启动Spring Boot应用程序,访问http://localhost:8080/hello即可访问HelloServlet。

总之,在Spring Boot中,通过使用ServletRegistrationBean来注册和配置Servlet,可以快速地进行Servlet的开发和部署。同时,也可以使用过滤器(Filter)、监听器(Listener)等来扩展Servlet的功能。

14. RESTful API

在Java语言中,实现REST API需要依赖于Web框架或者REST框架。下面以Spring Boot为例,简单介绍一下如何使用Java语言实现REST API。

  1. 创建Spring Boot项目

使用Spring Initializr创建一个Spring Boot项目,选择对应的项目类型和依赖库,例如选择Web和Spring Boot DevTools等依赖库。

  1. 编写Controller

在Spring Boot中,使用@Controller或@RestController注解来标记控制器类,然后在类中使用@RequestMapping注解来定义请求的映射路径和HTTP方法,例如:

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping
    public List<User> findAll() {
        return userRepository.findAll();
    }

    @PostMapping
    public User save(@RequestBody User user) {
        return userRepository.save(user);
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> findById(@PathVariable long id) {
        return userRepository.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> update(@PathVariable long id, @RequestBody User newUser) {
        return userRepository.findById(id)
                .map(user -> {
                    user.setName(newUser.getName());
                    user.setEmail(newUser.getEmail());
                    return ResponseEntity.ok(userRepository.save(user));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable long id) {
        userRepository.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}

在上述代码中,我们定义了一个名为UserController的RestController类,并对用户对象进行增删改查的操作。通过@GetMapping、@PostMapping、@PutMapping、@DeleteMapping等注解来定义REST API的请求方法和映射路径。

  1. 数据库操作

在Spring Boot中,可以使用Spring Data JPA等框架来简化数据库操作,例如:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // add custom query methods
}

在上述代码中,通过JpaRepository接口来定义用户数据的增删改查操作,无需实现,Spring Boot会自动根据方法名和参数来生成SQL语句和执行代码。

  1. 运行应用程序

在完成上述操作后,启动Spring Boot应用程序,访问http://localhost:8080/api/users即可访问REST API接口。

总之,在Spring Boot中,通过使用RestController、RequestMapping、GetMapping、PostMapping、PutMapping、DeleteMapping等注解,结合Spring Data JPA等框架,可以快速实现REST API的开发和部署。