JAVA程序设计

目录

基础:

命令行操作

命名规范

第三章:数据运算、流控制和数组

3.1数据类型

3.2注释

3.3逻辑运算符

3.4位运算符

​编辑

​编辑 3.5条件运算符

 3.6数组

3.7BufferedReader

3.8字符串与整数等的转换

3.9GUI组件

3.10包装类

3.11instanceof

第四章:类、包和接口

4.1类

 4.2构造方法与对象的创建

4.3方法的重载

4.4this的使用

4.5类的继承

4.6super的使用

4.7类的访问控制符

​编辑

4.8.1包

4.8.2import语句

 4.8.3成员的访问控制符

 4.8.4setter与getter

4.8.5非访问控制符 

4.9abstract类和方法

4.10接口

 第五章深入理解Java语言

第六章异常处理

6.1Error和Exception

Error类

Exception类

6.2自定义异常 

6.3捕获和处理异常

 6.4多异常处理

6.5finally语句

6.6抛出异常

6.7断言assert

第七章工具类及常用算法

7.1包装类

7.2String类

7.3StringBuilder类

7.4StringBuffer 类

7.5集合类

Collection接口

Map接口

常用集合类和方法

7.6枚举Enumeration

7.7接口

7.8抽象类

 7.9数组类

第八章Java的多线程

线程的实现

Thread类

Runnable接口

Callable和Future

线程的状态与生命周期

同步

synchronized方法

synchronized块

其他方法

异步

线程调度和优先级

 挂起线程

 检查线程

结束线程

线程组与守护线程

线程池

死锁

  第九章流

9.1字节流与字符流

9.2节点流与处理流

9.3文件流

FileInputStream和FileOutputStream

FileReader和FileWriter

9.4缓冲流

9.1Scanner类

9.2matches方法(正则表达式)

​编辑

9.4序列化和反序列化 

ObjectOutputStream

ObjectInputStream

第十章图形用户界面

第十一章网络编程

11.1网络编程

11.1.1URL

11.1.2Socket编程

第十二章JDBC编程

注解

泛型

基础:

命令行操作

Java-version

dir列出当前路径所有的文件和文件夹

cd进入路径

del删除

.为当前路径 ..为上一级路径

命名规范

项目名:小写。

包:小写,用.隔开。

类、接口、方法:驼峰,大小写,第一个单词为小写。

第三章:数据运算、流控制和数组

3.1数据类型

字符型:char占用2字节

标识符:由字母、数字、下划线、美元符号组成

必须以字母、下划线、美元符号开头,不能以数字开头

3.2注释

注释主要是为支持JDK工具而采用的。对于有@标记的注释,javadoc在生成有关程序的文档时,会自动地识别它们,并生成相应的文档。

@see:引用其他类
@version:版本信息
@author:作者信息
@param:参数名信息
@return:说明
@exception:完整类名说明

3.3逻辑运算符

37c040f5c23b42ef86a0e58b24c6f8bc.png

357f1b3f8e4e4225836719dbef041dd4.png

对于&&、||运算可能只计算左边的表达式而不计算右边的表达式,即对于&&,只要左边表达式为false,就不计算右边表达式,则整个表达式为false。

3.4位运算符

eea1b49f230f4891878b80383d024a77.png

c7d178878e46461c8a5246b252c4b1e8.png 36d9c0ce7c4242c4a520f19337e619e8.png

df70638d5ff04bd78841f8e7faf60e78.png b9e3cb3d3df64818b30564fd6f9aa05a.png

dd5dadb94c0f423bb3cc8d7a15900786.png 3.5条件运算符

z=a>0 ? a : -a;

 3.6数组

int [] score = new int[2020];
int c[][] = new int[2020][2020];
c[0] = new int[2];
c[1] = new int[3];
c[2] = new int[9];
score.length//指明score的长度
System.copyarray(src,src_position,dst,dst_position,length);//从src复制到dst,从第src_position个元素到dst的第dst_position位置,复制元素的个数为length。

3.7BufferedReader

BufferedReader 类提供了多种读取数据的方法,如 read()readLine() 等。其中,read() 方法用于读取单个字符,readLine() 方法用于读取一行文本。这些方法都可以从底层输入流中读取数据,并将其存储在缓冲区中,可以大大提高读取数据的效率。

import java.util.*;
import java.io.*;
public class Main {
    public static  void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
    }
}

3.8字符串与整数等的转换

String str = "123";  
try {  
    int number = Integer.parseInt(str);  
    System.out.println("转换后的整数: " + number);  
} catch (NumberFormatException e) {  
    System.out.println("字符串不是一个有效的整数格式");  
}
int number = 123;  
String str = Integer.toString(number);  
System.out.println("转换后的字符串: " + str);

3.9GUI组件

用户交互

3.10包装类

数组相关操作

目录后面有

3.11instanceof

用于测试一个对象是否是指定类型的实例或其子类的实例。它返回一个布尔值,如果对象是给定类或其子类的实例,则返回 true,否则返回 false

String s = "Hello";  
if (s instanceof String) {  
    System.out.println("s 是 String 类型的一个实例");  
}

第四章:类、包和接口

4.1类

class Person{
    String name;
    int age;
    void sayHello(){
        System.out.println("Hello!");
    }
}

 4.2构造方法与对象的创建

构造方法的方法名与类名相同。

构造方法没有返回类型,也不能写void。

构造方法的主要作用是完成对类对象的初始化工作。

构造方法一般不能由编程人员显式地直接调用,而是用new来调用。

在创建一个类的新对象的同时,系统会自动调用该类的构造方法为新对象初始化。

如果class前面有public修饰符,则默认构造方法前面也是public的。

//实例化:
public class Person{
    String name;
    int age;
    Person(String n,int a){
        name = n;
        age = a;
    }
}
public static void main(String[] args){
    Person p = new Person("Liming",20);
}

4.3方法的重载

多个方法享有相同的名字,但是这些方法的参数列表中:参数个数不同、参数类型不同,参数类型的顺序不同。

方法重载时,返回值的类型可以相同,也可以不同。

在调用方法时,若没有找到类型匹配的方法,编译器会找可以兼容的类型来进行调用,如,int类型可以找到使用double类型参数的方法。若不能找到则编译出错。

4.4this的使用

在方法中使用this来表示这个对象本身。详细地说,在普通方法中,this表示调用这个方法的对象;在构造方法中,this表示新创建的对象。 

在所有的非static方法中,都隐含了一个参数this。而static方法中,不能使用this。

4.5类的继承

Java不支持多重继承,一个类只能有一个直接父类。

class Student extends Person{
    String school;
    int score;
}

4.6super的使用

使用super访问父类的属性和方法。

父类Person有一个属性age,在子类Student中用age,this.age,super.age来访问是完全一样的。

super不能访问子类中添加的属性和方法。

 super调用父类的构造方法。使用时,super()必须放在第一句。

Student(String name,int age,String school){
    super(name,age);
    this.school = school;
}

4.7类的访问控制符

8f434d7c4fab4457a6434160d5415679.png

public class Person{
}

4.8.1包

由于Java编译器为每个类生成一个字节码文件,且文件名与public的类名相同,因此同名的类有可能发生冲突。为了解决这一问题,Java提供包来管理类名空间。

package java.awt.image;//指定这个包中的文件存储在目录java/awt/image下

4.8.2import语句

为了能使用Java中已提供的类,需要用import语句引入所需要的类。

import java.util.*;
import java.util.Date;

 4.8.3成员的访问控制符

66c6a5d7eb2048cea78f26f05014ba7b.png

 4.8.4setter与getter

只提供get方法,而不提供set方法,可以保证属性是只读的。

class Person2{
    private int age;
    public void setAge(int age){
        if(age>0&&age<200) this.age = age;
    }
    public int getAge(){
        return age;
    }
}

4.8.5非访问控制符 

f4ad78e47fd84b9bad3c67c9b9e5a17a.png static方法只能调用static方法和static域;不能使用this或super

final修饰的类不能被继承,即不可能有子类。(也就是方法等不能被改写 )

所有已被private修饰符限定为私有的方法,以及所有包含在final类中的方法,都被默认是final的。因为这些方法不可能被子类继承,所有不可能被重载,自然是final最终的方法。

final定义不能缺省

4.9abstract类和方法

抽象类不能用new来实例化,但抽象类可以有构造函数,构造函数可以被子类的构造函数所调用。

被abstract所修饰的方法称为抽象方法;抽象类中可以包含抽象方法,也可以不包含抽象方法。

抽象方法在子类必须被实现,否则子类仍然是抽象的。

abstract不能与final并列修饰同一类;abstract不能与private,static,final或native并列修饰同一方法;abstract方法必须位于abstract类中 

4.10接口

它定义了若干个抽象方法和常量,其主要作用是可以帮助实现类似于类的多重继承的功能。

接口中的域实际上是常量,修饰符默认为public static final。

接口中的方法都是抽象方法,修饰符默认为public abstract

// 定义一个名为Animal的接口  
public interface Animal {  
    // 接口中定义的方法默认都是public abstract的,可以省略这些修饰符  
    int age=10;
    void eat(); // 动物吃东西的方法  
    void sleep(); // 动物睡觉的方法  
    void makeSound(); // 动物发出声音的方法  
}
// Dog类实现了Animal接口  
public class Dog implements Animal {  
    // 实现Animal接口中定义的方法  
    @Override  
    public void eat() {  
        System.out.println("Dog is eating.");  
    }  
    @Override  
    public void sleep() {  
        System.out.println("Dog is sleeping.");  
    }  
    @Override  
    public void makeSound() {  
        System.out.println("Dog is barking.");  
    }  
}
public class Main {  
    public static void main(String[] args) {  
        Dog myDog = new Dog();  
        myDog.eat(); // 输出: Dog is eating.  
        myDog.sleep(); // 输出: Dog is sleeping.  
        myDog.makeSound(); // 输出: Dog is barking.  
    }  
}

 第五章深入理解Java语言

第六章异常处理

6.1Error和Exception

异常处理是通过特定的类来实现的,这些类都是java.lang.Throwable类的子类。Throwable类有两个主要的子类:ErrorException

Error类

Error类及其子类通常表示严重的问题,这些问题是Java虚拟机(JVM)无法或不应该尝试捕获的。例如,OutOfMemoryError表示JVM内存不足,StackOverflowError表示栈溢出等。这些错误通常是程序本身无法恢复的,因此通常不需要在程序中显式地处理它们。

Exception类

Exception类及其子类表示程序运行过程中可以预期和处理的异常。这些异常通常是由于程序员的错误或环境问题导致的,比如文件找不到、无效的参数等。

Exception类进一步分为两类:已检查异常(Checked Exceptions)和未检查异常(Unchecked Exceptions)。

已检查异常(Checked Exceptions)

已检查异常是那些在编译时必须处理的异常。这意味着,如果一个方法可能会抛出一个已检查异常,那么调用该方法的代码要么必须处理这个异常(使用try-catch块),要么必须声明它也可能抛出这个异常(通过在方法签名中使用throws关键字)。常见的已检查异常包括IOExceptionClassNotFoundException等。

未检查异常(Unchecked Exceptions)

未检查异常是RuntimeException类及其子类的实例。这些异常通常是程序员的编程错误导致的,比如空指针访问、数组越界等。未检查异常在编译时不需要显式处理,但是最佳实践是仍然应该捕获并适当处理这些异常,以避免程序意外终止或产生不可预测的行为。

Java定义了很多异常类,每个异常类都代表了一种运行错误,类中包含了该运行错误的信息和处理错误的方法。Java的异常类都是java.lang.Throwable的子类。它派生了两个子类:Error(错误)和Exception(违例)。

a9d7cc9d0fa246288f721a8e2b5a2da7.png

6.2自定义异常 

用户自定义异常,是由Exception或其子类派生出来的类。

自定义异常类

你也可以创建自己的异常类,通过继承Exception或其子类(如RuntimeException)来实现。自定义异常类通常用于表示特定于应用程序的问题或错误情况。

下面是一个简单的自定义异常类的示例:

public class CustomException extends Exception {  
      
    public CustomException() {  
        super();  
    }  
      
    public CustomException(String message) {  
        super(message);  
    }  
      
    public CustomException(String message, Throwable cause) {  
        super(message, cause);  
    }  
      
    public CustomException(Throwable cause) {  
        super(cause);  
    }  
}

你可以像使用任何其他异常类一样使用这个自定义异常类:

public class ExceptionExample {  
      
    public static void main(String[] args) {  
        try {  
            // 假设这里有个条件,如果满足则抛出自定义异常  
            boolean condition = true;  
            if (condition) {  
                throw new CustomException("This is a custom exception.");  
            }  
        } catch (CustomException e) {  
            // 处理自定义异常  
            System.out.println("Caught a custom exception: " + e.getMessage());  
        }  
    }  
}

 在这个示例中,我们定义了一个名为CustomException的自定义异常类,并在main方法中抛出了这个异常。然后,我们使用try-catch块来捕获并处理这个异常。

6.3捕获和处理异常

1、Java程序的执行过程中如出现异常,会自动生成一个异常类对象交给Java运行时系统,这个过程称为抛出异常。抛出异常可由程序强制进行。

2、当Java在运行时系统接收到异常对象,会寻找能处理这一异常的代码并把当前异常对象交其处理,这个过程称为捕获异常。

3、Java找不到可以处理的方法,则运行时系统将会终止。

public class ExceptionHandlingExample {  
    public static void main(String[] args) {  
        try {  
            // 尝试执行可能抛出异常的代码  
            int dividend = 10;  
            int divisor = 0;  
            int result = dividend / divisor; // 这将抛出ArithmeticException  
            System.out.println("The result is: " + result);  
        } catch (ArithmeticException e) {  
            // 捕获到ArithmeticException异常后,执行这里的代码  
            System.out.println("Error: Division by zero is not allowed!");  
        } catch (Exception e) {  
            // 捕获到其他所有异常后,执行这里的代码  
            System.out.println("An unexpected error occurred: " + e.getMessage());  
        } finally {  
            // 无论是否发生异常,最后都会执行这里的代码  
            System.out.println("This is the end of the try-catch block.");  
        }  
    }  
}
  • 第一个catch块专门用来捕获ArithmeticException,并输出一条错误消息。
  • 第二个catch块是一个通用的异常处理器,用来捕获所有其他类型的异常,并输出异常的消息。
  • finally块包含的代码无论是否发生异常都会执行,通常用于释放资源或执行清理任务。

 6.4多异常处理

会有多个catch语句块。

try中出现的异常对象会在catch语句块中顺序匹配处理,如果所有的catch块都不能匹配,程序将调用该方法的上层方法,仍旧无法解决则继续回溯更上层的方法。如果所有的方法都找不到合适的catch块将会中止程序并在标准输出打印相关的异常信息。

若将子类异常的catch()放在父类的后面,则编译不能通过。

try {  
    // 可能抛出SubException或ParentException的代码  
    throw new SubException(); // 假设SubException是ParentException的子类  
} catch (ParentException e) {  
    // 这个catch块将总是被执行,因为它可以捕获所有ParentException和它的子类  
    System.out.println("Caught ParentException");  
} catch (SubException e) {  
    // 这个catch块将永远不会被执行,因为上面的ParentException catch块已经捕获了异常  
    System.out.println("Caught SubException");  
}

在这个例子中,无论try块中抛出的是SubException还是ParentException,都只有第一个catch块(捕获ParentException的块)会被执行。这是因为SubExceptionParentException的子类,所以它可以被ParentException类型的catch块捕获。 

6.5finally语句

不管try块是否产生了异常对象,finally都会执行。

try后至少要有一个catch或一个finally。(也就是可以没有finally块或catch块)

finally块经常用于对一些资源做清理工作,如关闭打开的文件。

6.6抛出异常

子类方法不能抛出比父类更多种类的异常(子类异常应该是具体的父类)

import java.util.*;
import java.io.*;
public class Main {
    public static  void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
    }
}

6.7断言assert

class Assertion{
    public static void main(String[] args){
        assert xiebian(3,4)==5:"算法不正确";
    }
    static double xiebian(double x,double y){
        return Math.sqrt(x*x+y*y);
    }
}

如果xiebian函数写错了,则程序运行到assert语句时,这个断言不满足,则程序会异常终止,并显示出“算法不正确”的信息。

第七章工具类及常用算法

7.1包装类

 包装类(Wrapper Classes)是一组特殊的类,它们用于将基本数据类型(如intdoublechar等)转换为对象,以便能够使用对象的方法和特性。包装类不仅提供了基本数据类型到对象的转换,还提供了很多实用的方法和常量。

Java为每种基本数据类型都提供了一个对应的包装类:

  • Byte:对应byte类型
  • Short:对应short类型
  • Integer:对应int类型
  • Long:对应long类型
  • Float:对应float类型
  • Double:对应double类型
  • Character:对应char类型
  • Boolean:对应boolean类型

包装类的主要用途包括:

  1. 自动装箱和拆箱:从Java 5开始,Java引入了自动装箱(autoboxing)和拆箱(unboxing)功能。这意味着你可以在需要对象的地方使用基本数据类型,反之亦然。例如,你可以将一个int值传递给一个期望Integer对象的方法,Java会自动将int值转换为Integer对象。

  2. 类型转换:包装类提供了方法来进行类型转换,例如Integer.parseInt(String)可以将字符串转换为整数。

  3. 常量和方法:包装类提供了一些有用的常量和方法。例如,Integer.MAX_VALUE表示int类型的最大值,Integer.compare(int x, int y)用于比较两个int值。

  4. 缓存:某些包装类(如IntegerByteShortCharacter)对于-128到127之间的值提供了缓存,以避免频繁的内存分配和垃圾回收。

  5. Null 安全:基本数据类型不能为null,但是它们的包装类可以为null。这使得包装类在表示可能为空的值时更加灵活。

  6. 集合类中的使用:因为集合类(如ArrayListHashSet等)只能存储对象,所以当你需要在集合中存储基本数据类型时,必须使用它们的包装类。

以下是一个使用包装类的简单示例: 

Integer myInteger = 100; // 自动装箱,Java 将 int 转换为 Integer 对象  
int myInt = myInteger;   // 自动拆箱,Java 将 Integer 转换为 int  
  
// 使用包装类的方法  
String intAsString = Integer.toString(myInteger);  
int parsedInt = Integer.parseInt(intAsString);  
  
// 使用常量  
int maxValue = Integer.MAX_VALUE;  
  
// 使用缓存特性  
Integer cachedOne = Integer.valueOf(1);  
Integer anotherOne = Integer.valueOf(1);  
System.out.println(cachedOne == anotherOne); // 输出 true,因为缓存了值 1  
  
// 包装类可以为 null  
Integer nullableInteger = null;

7.2String类

处理字符串的主要类是String类,它位于java.lang包中。String类是不可变的,这意味着一旦创建了String对象,就不能修改它的内容。每次对String对象进行所谓的“修改”操作,实际上是创建了一个新的String对象。

除了String类,Java还提供了一些其他类来辅助字符串处理,如StringBuilderStringBuffer。这些类是可变的,意味着你可以修改它们的内容而不需要创建新的对象。

String str = "Hello, World!";  
  
// 连接字符串  
String concatenated = str + ", Java!";  
  
// 查找子字符串  
int index = str.indexOf("World");  
  
// 替换子字符串  
String replaced = str.replace("World", "Java");  
  
// 转换大小写  
String lowerCase = str.toLowerCase();  
String upperCase = str.toUpperCase();  
  
// 比较字符串  
boolean isEqual = str.equals("Hello, World!");  
boolean isNotEqual = !str.equals("Goodbye, World!");  
  
// 判断字符串是否以特定序列开始或结束  
boolean startsWithHello = str.startsWith("Hello");  
boolean endsWithWorld = str.endsWith("World!");  
  
// 获取字符串长度  
int length = str.length();  
  
// 获取字符串中指定位置的字符  
char firstChar = str.charAt(0);  
  
// 字符串分割  
String[] parts = str.split(",");

7.3StringBuilder类

 StringBuilder类用于构建可修改的字符串。与String不同,StringBuilder是线程不安全的,但性能更高,适用于单线程环境。

StringBuilder sb = new StringBuilder();  
  
// 追加字符串  
sb.append("Hello");  
sb.append(" ").append("World");  
sb.append("!");  
  
// 获取构建的字符串  
String result = sb.toString();  
  
// 修改字符串内容  
sb.setCharAt(7, 'J');  
sb.insert(7, "ava");  
sb.delete(7, 10);

7.4StringBuffer 类

StringBuffer类与StringBuilder类似,也是用于构建可修改的字符串。不过,StringBuffer是线程安全的,因此性能略低,适用于多线程环境。

StringBuffer sb = new StringBuffer();  
  
// 追加字符串  
sb.append("Hello");  
sb.append(" ").append("World");  
sb.append("!");  
  
// 获取构建的字符串  
String result = sb.toString();  
  
// 修改字符串内容(与StringBuilder方法类似)  
sb.setCharAt(7, 'J');  
sb.insert(7, "ava");  
sb.delete(7, 10);

7.5集合类

 集合类(Collection Classes)是Java Collections Framework的一部分,它提供了丰富的接口和类来存储和操作对象集合。这些集合类允许你存储、检索、添加和删除对象,而且它们都是对象导向的,可以容纳任何类型的对象。

Java集合框架主要包括两种类型的集合:Collection和Map。

Collection接口

Collection接口是集合层次结构的根接口,它代表了一组对象,这些对象被称为集合的元素。Collection接口提供了对集合框架的基本操作的通用视图,如添加、删除、查找等。

List接口

List接口继承自Collection接口,它是有序集合(也称为序列),可以包含重复的元素。List接口的主要实现类有ArrayListLinkedListVector

Set接口

Set接口也是继承自Collection接口,但它不允许包含重复的元素。Set接口的主要实现类有HashSetTreeSetLinkedHashSet

Map接口

Map接口存储的是键值对映射,而不是单一元素。每个键在映射中都是唯一的,映射可以包含与每个键相关联的值。Map接口的主要实现类有HashMapTreeMapLinkedHashMap等。

常用集合类和方法

  1. ArrayList:基于数组实现的动态数组,允许存储重复元素。

  2. LinkedList:基于链表实现的动态列表,允许存储重复元素,且元素插入和删除效率高。

  3. HashSet:基于HashMap实现的集合,不允许存储重复元素,元素是无序的。

  4. TreeSet:基于红黑树实现的集合,不允许存储重复元素,元素是有序的。

  5. HashMap:基于哈希表实现的键值对映射,允许存储null键和null值。

  6. TreeMap:基于红黑树实现的键值对映射,元素是有序的。

集合类常用方法

  • add(E e): 添加元素到集合中。
  • remove(E e): 从集合中删除元素。
  • contains(E e): 检查集合是否包含指定元素。
  • isEmpty(): 检查集合是否为空。
  • size(): 返回集合中元素的数量。
  • iterator(): 返回集合的迭代器,用于遍历集合元素。

Map接口常用方法

  • put(K key, V value): 向映射中添加键值对。
  • get(Object key): 根据键获取映射中的值。
  • remove(Object key): 从映射中删除指定的键值对。
  • containsKey(Object key): 检查映射是否包含指定的键。
  • containsValue(Object value): 检查映射是否包含指定的值。
  • keySet(): 返回映射中所有键的集合。
  • values(): 返回映射中所有值的集合。
  • entrySet(): 返回映射中所有键值对的集合。
import java.util.*;  
  
public class CollectionExample {  
    public static void main(String[] args) {  
        // 创建一个ArrayList  
        List<String> list = new ArrayList<>();  
        list.add("Apple");  
        list.add("Banana");  
        list.add("Cherry");  
  
        // 遍历列表  
        for (String fruit : list) {  
            System.out.println(fruit);  
        }  
  
        // 创建一个HashSet  
        Set<String> set = new HashSet<>();  
        set.add("Apple");  
        set.add("Banana");  
        set.add("Cherry");  
  
        // 遍历集合  
        for (String fruit : set) {  
            System.out.println(fruit);  
        }  
  
        // 创建一个HashMap  
        Map<String, Integer> map = new HashMap<>();  
        map.put("Apple", 1);  
        map.put("Banana", 2);  
        map.put("Cherry", 3);  
  
        // 遍历映射  
        for (Map.Entry<String, Integer> entry : map.entrySet()) {  
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());  
        }  
    }  
}

7.6枚举Enumeration

枚举(Enumeration)是一种特殊的类,它用于表示固定数量的常量。枚举类型可以让你为一组值(通常是有限的)定义一个新的类型,这样这些值就可以作为常规的程序组件使用了。枚举类型在Java 5中被引入,它们提供了一种更加清晰和类型安全的方式来定义和使用常量。

枚举类型的优点包括:

  1. 类型安全:枚举常量是类型安全的,这意味着它们不能是其他类型的值。

  2. 清晰的表示:枚举提供了对常量值的明确和有意义的名称。

  3. 可读性:使用枚举可以增加代码的可读性,因为它们通常比使用魔术数字或字符串字面量更有意义。

  4. 可扩展性:如果将来需要添加或删除常量,只需修改枚举类型即可。

在Java中定义枚举类型的语法如下:

public enum EnumName {  
    VALUE1, VALUE2, VALUE3, ...;  
      
    // 枚举常量可以有构造函数、方法和字段  
    private String description;  
  
    EnumName() {  
        // 构造函数  
    }  
  
    public String getDescription() {  
        return description;  
    }  
  
    // 还可以定义枚举常量特有的方法  
    public void doSomething() {  
        // ...  
    }  
}

 以下是一个简单的枚举示例:

public enum Day {  
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;  
  
    // 枚举方法  
    public static Day dayOfWeek(String dayName) {  
        for (Day day : Day.values()) {  
            if (day.name().equalsIgnoreCase(dayName)) {  
                return day;  
            }  
        }  
        throw new IllegalArgumentException("No such day: " + dayName);  
    }  
}

使用枚举类型时,你可以像使用其他类一样使用它们,但它们的实例是固定的,不能创建新的实例。例如:

public class EnumExample {  
    public static void main(String[] args) {  
        Day today = Day.MONDAY;  
          
        // 调用枚举常量特有的方法  
        today.doSomething();  
          
        // 调用枚举类型的方法  
        Day day = Day.dayOfWeek("WEDNESDAY");  
          
        // 遍历所有枚举常量  
        for (Day dayOfWeek : Day.values()) {  
            System.out.println(dayOfWeek);  
        }  
    }  
}

在这个例子中,Day是一个枚举类型,它包含一周中的七天。我们还定义了一个dayOfWeek方法,该方法接受一个字符串参数,并返回与该字符串匹配的枚举常量。

枚举类型在Java中非常有用,特别是在需要定义一组常量并且这些常量的数量不会改变的情况下。使用枚举可以提高代码的可读性和可维护性。

7.7接口

 接口(Interface)是一种引用类型,它是方法的集合。接口通常用来定义一个行为的集合,而这些行为可以由一个类或多个类来实现。接口定义了一个契约,类必须遵循这个契约(即实现接口中定义的所有方法)才能被认为是该接口的实现。

接口的主要特点包括:

  1. 抽象方法:接口中的所有方法都是抽象的,这意味着它们没有实现(即没有方法体)。实现接口的类必须提供这些方法的具体实现。

  2. 常量:接口可以包含常量,这些常量默认是public static final的。常量在接口中通常用于定义一些全局的、不变的值。

  3. 不能实例化:接口不能被实例化,它们只能被类实现。

  4. 继承:一个接口可以继承多个其他接口,使用extends关键字。这允许你创建一个接口,该接口组合了多个其他接口的行为。

  5. 实现:一个类可以实现一个或多个接口,使用implements关键字。实现接口的类必须提供接口中所有方法的具体实现。

  6. 默认方法和静态方法:从Java 8开始,接口可以包含默认方法(使用default关键字)和静态方法(使用static关键字)。默认方法允许在接口中提供方法的默认实现,而静态方法可以在不实例化接口的情况下被调用。

  7. 私有方法:从Java 9开始,接口还可以包含私有方法,这些方法只能被接口中的其他方法调用,不能由实现接口的类直接调用。

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

public interface Animal {  
      
    // 常量  
    String SPECIES = "Animal";  
  
    // 抽象方法  
    void eat();  
  
    // 默认方法(从Java 8开始)  
    default void breathe() {  
        System.out.println("The animal breathes.");  
    }  
  
    // 静态方法(从Java 8开始)  
    static void sleep() {  
        System.out.println("The animal sleeps.");  
    }  
  
    // 私有方法(从Java 9开始)  
    private void move() {  
        System.out.println("The animal moves.");  
    }  
}

然后,可以创建一个实现Animal接口的类:

public class Dog implements Animal {  
  
    // 实现接口中的抽象方法  
    @Override  
    public void eat() {  
        System.out.println("The dog eats dog food.");  
    }  
  
    // 调用接口中的默认方法  
    public void live() {  
        breathe();  
        move();  
    }  
  
    public static void main(String[] args) {  
        Dog dog = new Dog();  
        dog.eat();        // 调用实现的方法  
        dog.breathe();    // 调用默认方法  
        Animal.sleep();   // 调用静态方法  
        dog.live();       // 调用实现的方法并间接调用私有方法  
    }  
}

在这个例子中,Animal是一个接口,它定义了一个抽象方法eat()、一个默认方法breathe()、一个静态方法sleep()和一个私有方法move()Dog类实现了Animal接口,并提供了eat()方法的具体实现。同时,Dog类还可以调用接口中的默认方法和静态方法。

7.8抽象类

抽象类(Abstract Class)是一种特殊的类,它不能被实例化,只能被其他类继承。抽象类通常用于表示一种基础的或者通用的类型,其中一些方法的具体实现是未知的或者由子类来提供。抽象类可以包含抽象方法(没有方法体的方法)和非抽象方法(有方法体的方法)。

抽象类的主要特点包括:

  1. 抽象方法:抽象类可以包含抽象方法,这些方法没有具体的实现(即没有方法体)。子类继承抽象类时,必须提供抽象方法的具体实现,除非子类本身也是抽象类。

  2. 非抽象方法:抽象类也可以包含非抽象方法,这些方法有具体的实现。子类可以继承这些方法,也可以重写它们。

  3. 不能被实例化:由于抽象类是用来被继承的,所以它不能被直接实例化。尝试实例化一个抽象类会导致编译错误。

  4. 构造器:抽象类可以有构造器,这些构造器通常用于被子类调用。尽管抽象类不能被直接实例化,但其构造器可以被子类调用以执行一些初始化操作。

  5. 继承:一个类只能继承一个直接父类,但这个父类可以是抽象类。如果子类继承了抽象类,那么它必须实现抽象类中的所有抽象方法,除非子类也是抽象的。

  6. 访问修饰符:抽象方法可以是publicprotecteddefault(包级别访问),但不能是private。因为抽象方法是为了被子类覆盖的,而private方法不能被其他类访问。

下面是一个简单的Java抽象类示例:

public abstract class AbstractAnimal {  
      
    // 抽象方法,没有方法体  
    public abstract void eat();  
  
    // 非抽象方法,有方法体  
    public void sleep() {  
        System.out.println("The animal sleeps.");  
    }  
  
    // 构造器,用于初始化  
    public AbstractAnimal() {  
        System.out.println("An abstract animal is being created.");  
    }  
}

然后,可以创建一个继承自AbstractAnimal的具体类,并实现抽象方法: 

public class Dog extends AbstractAnimal {  
  
    // 实现抽象方法  
    @Override  
    public void eat() {  
        System.out.println("The dog eats dog food.");  
    }  
  
    public static void main(String[] args) {  
        Dog dog = new Dog(); // 创建Dog对象  
        dog.eat();           // 调用eat方法  
        dog.sleep();         // 调用sleep方法  
    }  
}

在这个例子中,AbstractAnimal是一个抽象类,它有一个抽象方法eat()和一个非抽象方法sleep()Dog类继承了AbstractAnimal并实现了eat()方法。在main方法中,我们创建了Dog类的实例,并调用了它的eat()sleep()方法。 

 7.9数组类

import java.util.*;

public class Main {
    public static void main(String[] args) {
            int[] Arr= new int[10];
            Scanner sc = new Scanner(System.in);
            for(int i=0;i< Arr.length;i++){
                Arr[i]=sc.nextInt();
                System.out.println(Arr[i]);
            }
            //多维数组
            String[][] s = new String[10][10];
            for(int i=0;i< s.length;i++){
                for(int j=0;j< s[i].length;j++){
                    s[i][j]=sc.next();
                    System.out.println(s[i][j]);
                }
            }
            //排序方法
            Arrays.sort(Arr);

            //搜索方法
            Arrays.binarySearch(Arr,10);//使用二分搜索在整数数组中搜索特定的值。
            //在指定范围搜索
            Arrays.binarySearch(Arr,1,10,10);

            //数组比较
            Arrays.equals(Arr,Arr);//equals方法要求数组长度,类型一致

            //填充数组
            Arrays.fill(Arr,10);//使用指定的整数值填充整数数组。

            //数组复制
            Arrays.copyOf(Arr,10);//复制指定数组,并返回一个新数组,新数组的长度由参数指定。
            Arrays.copyOfRange(Arr,1,10);//复制指定数组的一部分,并返回一个新数组。
    }
}

第八章Java的多线程

线程的实现

Thread类

Thread类是Java.lang包中的一个类。

1、你可以通过继承Thread类并重写run方法来创建线程。

2、new创建所定义的线程类的实例化对象。

3、调用该对象的start()方法启动线程(自动调用run()方法)。

public class javaa {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            CaseThread caseThread = new CaseThread("学生" + i);
            caseThread.start();
        }
    }
}
class CaseThread extends Thread {
    String studentName;
    public CaseThread(String studentName) {
        this.studentName = studentName;
        System.out.println("CaseThread " + studentName + "申请访问服务器");
    }
    public void run() {
        System.out.println("CaseThread " + studentName + "正在访问服务器");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        System.out.println("CaseThread " + studentName + "访问服务器完毕");
    }
}
CaseThread 学生0申请访问服务器
CaseThread 学生1申请访问服务器
CaseThread 学生2申请访问服务器
CaseThread 学生3申请访问服务器
CaseThread 学生0正在访问服务器
CaseThread 学生1正在访问服务器
CaseThread 学生2正在访问服务器
CaseThread 学生4申请访问服务器
CaseThread 学生3正在访问服务器
CaseThread 学生5申请访问服务器
CaseThread 学生4正在访问服务器
CaseThread 学生6申请访问服务器
CaseThread 学生5正在访问服务器
CaseThread 学生7申请访问服务器
CaseThread 学生6正在访问服务器
CaseThread 学生8申请访问服务器
CaseThread 学生7正在访问服务器
CaseThread 学生9申请访问服务器
CaseThread 学生8正在访问服务器
CaseThread 学生9正在访问服务器
CaseThread 学生5访问服务器完毕
CaseThread 学生7访问服务器完毕
CaseThread 学生0访问服务器完毕
CaseThread 学生1访问服务器完毕
CaseThread 学生6访问服务器完毕
CaseThread 学生4访问服务器完毕
CaseThread 学生8访问服务器完毕
CaseThread 学生9访问服务器完毕
CaseThread 学生3访问服务器完毕
CaseThread 学生2访问服务器完毕

Runnable接口

一个类已经继承了其他的类,由于单继承的特性,导致该类无法继承Thread类,因此需要实现Runnable接口。

Runnable接口只有一个方法run()。

1、创建一个类实现(implement)Runnable接口,重写run()方法。

2、在另一个类中初始化一个Thread类对象。

3、应用Thread类的构造函数实例化。

4、调用该对象的start()方法启动线程。

public class javaa implements Runnable{
    @Override
    public void run() {
        System.out.println("我是线程");
    }
}
class Test{
    public static void main(String[] args) {
        javaa j = new javaa();
        Thread t = new Thread(j);
        t.start();
    }
}

Callable和Future

通过实现Callable接口,我们可以定义具体的任务逻辑;通过使用Future对象,我们可以管理任务的执行和获取任务的结果。

【Java 基础篇】Java Callable与Future:并发编程的利器_java future和callable-CSDN博客

Callable接口

Callable接口是Java中的一个泛型接口,它定义了一个可以返回结果并可能抛出异常的任务。它只有一个方法call(),该方法在任务执行完成后返回一个结果,或者在执行过程中抛出异常。以下是Callable接口的定义:

public interface Callable<V> {
    V call() throws Exception;
}
import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    private int number;

    public MyCallable(int number) {
        this.number = number;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= number; i++) {
            sum += i;
        }
        return sum;
    }
}

Future接口

Future接口是一个泛型接口,用于表示异步计算的结果。它提供了一些方法来检查任务是否完成、获取计算结果以及取消任务的执行。以下是Future接口的定义:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
cancel(boolean mayInterruptIfRunning):尝试取消任务的执行。
isCancelled():检查任务是否已被取消。
isDone():检查任务是否已经完成。
get():获取任务的结果,如果任务尚未完成,则阻塞当前线程。
get(long timeout, TimeUnit unit):在指定的时间内获取任务的结果,如果任务尚未完成,则阻塞当前线程。
Future接口的get()方法是一个阻塞方法,它会一直等待任务执行完成并返回结果。如果任务还未完成,调用该方法的线程将被阻塞。

线程的状态与生命周期

42db426e35eb47eaa467c1467ecddd40.png

1、新建状态:当一个Thread类或其子类对象被声明并用new来实例化。

2、就绪状态:执行了start()方法后,进入就绪状态。处于阻塞状态的线程解除阻塞后也进入就绪状态。

3、运行状态:当就绪状态的线程被调度并获得处理器资源时进入运行状态。

4、阻塞状态:一个正在执行的线程在某些特殊情况下(被人挂起,需要执行费时的输入/输出操作时)进入阻塞状态,只有引起阻塞的原因被消除,线程才可以转入就绪状态。

5、死亡状态:正常运行的线程完成了它的全部工作;线程被提前强制终止。 

同步

线程都是独立的,而且异步执行,也就是说每个线程都包含了运行时所需要的数据和方法,而不需要外部的资源或方法,也不必关心其他线程的状态或行为。但是经常有一些同时运行的线程需要共享数据,例如一个线程向文件写数据,而同时另一个线程从同一文件中读取数据,因此就必须考虑其他线程的状态与行为,这时就需要实现同步来得到预期的结果。

synchronized方法

每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

synchronized块

public class Counter {
    private int counter = 0;

    public void increment() {
        synchronized (this) { // 使用当前对象作为锁
            counter++;
        }
    }

    public int getCounter() {
        return counter;
    }
}

其他方法

wait(),notify(),notifyAll():线程在调用wait()方法时,必须拥有该对象的监视器锁(monitor lock),即线程必须在synchronized块或方法中调用wait()。调用wait()方法后,线程会释放它所持有的监视器锁,并进入等待状态。当其他线程调用notify()notifyAll()方法时,等待的线程可能会重新获得监视器锁并从wait()方法返回继续执行。

异步

异步线程通常指的是不在主线程上立即执行,而是被调度到线程池或其他线程执行机制中以并行或并发方式运行的线程。异步编程可以帮助我们提高程序的响应性和吞吐量,因为它允许程序在等待某个操作完成时继续执行其他任务。

Java中处理异步线程的一种常见方式是使用java.util.concurrent包中的ExecutorServiceFutureExecutorService提供了一种管理线程池的方式,而Future则代表异步计算的结果。

以下是使用ExecutorServiceFuture进行异步线程操作的一个简单示例:

import java.util.concurrent.*;  
  
public class AsyncThreadExample {  
    public static void main(String[] args) throws ExecutionException, InterruptedException {  
        // 创建一个单线程的线程池  
        ExecutorService executorService = Executors.newSingleThreadExecutor();  
  
        // 提交一个异步任务到线程池  
        Future<String> future = executorService.submit(() -> {  
            // 模拟耗时操作  
            try {  
                Thread.sleep(2000);  
            } catch (InterruptedException e) {  
                Thread.currentThread().interrupt();  
                throw new IllegalStateException(e);  
            }  
            // 返回结果  
            return "异步任务完成";  
        });  
  
        // 主线程可以继续执行其他任务  
        System.out.println("主线程正在做其他事情...");  
  
        // 在需要的时候获取异步任务的结果  
        String result = future.get(); // 这会阻塞,直到异步任务完成  
        System.out.println("异步任务的结果: " + result);  
  
        // 关闭线程池  
        executorService.shutdown();  
    }  
}

在这个示例中,我们首先创建了一个单线程的ExecutorService。然后,我们使用submit方法提交了一个Callable任务到线程池。这个Callable任务会在另一个线程中执行,而主线程可以继续执行System.out.println("主线程正在做其他事情...");这行代码,不会等待Callable任务完成。

当主线程需要Callable任务的结果时,它调用future.get()。这个方法会阻塞,直到Callable任务完成并返回结果。一旦Callable任务完成,future.get()将返回结果,并且主线程可以继续执行。

除了ExecutorServiceFuture,Java 8及以后的版本引入了CompletableFuture类,它提供了一种更简洁和强大的方式来处理异步编程和函数式编程。CompletableFuture支持链式编程,可以很容易地组合多个异步操作。

以下是一个使用CompletableFuture的示例:

import java.util.concurrent.CompletableFuture;  
  
public class CompletableFutureExample {  
    public static void main(String[] args) throws Exception {  
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  
            // 模拟耗时操作  
            try {  
                Thread.sleep(2000);  
            } catch (InterruptedException e) {  
                Thread.currentThread().interrupt();  
                throw new IllegalStateException(e);  
            }  
            // 返回结果  
            return "异步任务完成";  
        });  
  
        // 主线程可以继续执行其他任务  
        System.out.println("主线程正在做其他事情...");  
  
        // 在需要的时候获取异步任务的结果  
        String result = future.get(); // 这会阻塞,直到异步任务完成  
        System.out.println("异步任务的结果: " + result);  
    }  
}

在这个示例中,CompletableFuture.supplyAsync方法用于提交一个异步任务,并立即返回一个CompletableFuture对象。主线程可以继续执行其他任务,而不需要等待异步任务完成。当需要结果时,可以调用future.get()来获取。

总的来说,使用ExecutorServiceFutureCompletableFuture,你可以很容易地在Java中实现异步线程编程。

线程调度和优先级

线程的优先级用数字1~10表示,线程默认优先级是5,预定义变量MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY其值为10,1,5。

线程优先级只是一种提示,操作系统并不一定会严格按照优先级顺序进行调度,具体的线程调度还受到操作系统和处理器的调度策略的影响。

getPriority() 返回线程的优先级
setPriority() 改变线程的优先级
public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread 1 is running with priority: " + Thread.currentThread().getPriority());
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread 2 is running with priority: " + Thread.currentThread().getPriority());
            }
        });

        thread1.setPriority(7);
        thread2.setPriority(3);

        thread1.start();
        thread2.start();
    }
}

 挂起线程

控制线程使其由运行状态转换为阻塞状态。

1、sleep()方法:沉睡时间结束后,继续执行后续代码。

当在沉睡时间内被打断,它会抛出一个类型为InterruptedException的异常。

该方法会给低优先级的线程一个运行机会。

try{
    Thread.sleep((int)(Math.random()*2000));
}catch(InterruptedException ex){
    System.err.println(ex.toString());
}

2、yield()方法: 暂停当前的线程,将其放入可运行队列,而选同优先级的另一线程运行,如果没有相同优先级的可运行线程,则该方法将什么都不做并继续让当前线程执行。

    public static void main(String[] args) {
        Thread producer = new Producer();
        producer.start();

        Thread consumer = new Consumer();
        consumer.start();
    }
}
class Producer extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("生产者生产项目: " + i);
            Thread.yield();
        }
    }
}
class Consumer extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("消费者消费项目: " + i);
            Thread.yield();
        }
    }
}

3、interrupt()方法:一个线程运行时,另一个线程可以调用对应Thread对象的interrupt()方法来中断它。

4、wait()方法:使线程进入阻塞状态,直至被另外一个线程唤醒。

wait()notify() 和 notifyAll() 方法只能在同步块或同步方法内部调用,因为它们需要当前线程持有对象的监视器锁。此外,wait() 方法可能会抛出 InterruptedException,表示等待过程中线程被中断。

public class WaitNotifyExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread waiter = new Waiter();
        Thread notifier = new Notifier();
        waiter.start();
        notifier.start();
    }

    static class Waiter extends Thread {
        public void run() {
            synchronized (lock) {
                try {
                    System.out.println("Waiter: 我在等待一个通知...");
                    lock.wait();
                    System.out.println("Waiter: 我已经收到了通知!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Notifier extends Thread {
        public void run() {
            synchronized (lock) {
                System.out.println("Notifier: 准备发送通知...");
                lock.notify();
                System.out.println("Notifier: 通知已发送!");
            }
        }
    }
}

5、join()方法:将几个并行的线程合并成单线程执行。

如果某线程(线程A)只有在另一线程(线程B)终止时才能继续执行,则线程A可以调用线程B的join()方法,即线程A执行该方法,而后被阻塞。

 检查线程

检查线程包括检查线程的名字,当前运行状态,线程的优先级。

1、getName():取得线程的名称;setName():设置线程的名称。

2、isAlive():当线程处于新建状态时,该方法返回false;当线程处于运行状态(非就绪状态)时,该方法返回true;当线程处于死亡状态时,该方法返回false。

3、currentThread():用于获得这一线程,以便进一步控制线程的执行。返回值为Thread的引用。

结束线程

1、stop():使线程由其他状态进入死亡状态。

2、destroy():强制结束线程,但不会释放锁。

3、参数控制法:

1、编写一个类继承Thread类
2、在类中声明一个bool类型的变量,其初始值为true
3、重写run()方法
4、声明一个可改变变量值为false的函数
5、调用函数以结束线程
public class ThreadControlExample {

    private static class WorkerThread extends Thread {
        private volatile boolean running = true;

        public void run() {
            while (running) {
                // 执行工作...
                System.out.println("工作线程正在运行...");

                try {
                    Thread.sleep(1000); // 模拟工作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("工作线程已经结束。");
        }

        public void shutdown() {
            running = false;
        }
    }

    public static void main(String[] args) {
        WorkerThread worker = new WorkerThread();
        worker.start();

        try {
            Thread.sleep(5000); // 主线程等待5秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        worker.shutdown(); // 请求工作线程结束
    }
}

线程组与守护线程

线程组是指包含了许多线程的对象集,并可以拥有一个名字和一些相关的属性,用于统一管理组中的线程。

ThreadGroup tg=new ThreadGroup("workThreadGroup");
Thread wt1=new Thread(tg,"1stwork");
Thread wt2=new Thread(tg,"2ndwork");
wt1.start();
wt2.start();

守护线程 

守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点

 面试官: 谈谈什么是守护线程以及作用 ?_守护线程什么时候退出-CSDN博客

线程池

 线程池详解(通俗易懂超级好)-CSDN博客

死锁

死锁的产生原因以及解决方案_死锁的原因及解决方法-CSDN博客

  第九章流

9.1字节流与字符流

1、字节流

InputStream和OutputStream是抽象类,它们分别为字节输入和输出操作定义了方法,它们的子类重载或重写了这些方法。 

InputStream类中的主要常用方法:

1)read():读取字节数据

2)close():关闭输入流并释放与该流关联的所有系统资源。

OutputStream类中的主要常用方法:

1)write(int b):先将int类型转为byte类型,把b低字节写入到输入流。

2)flush():将数据缓冲区中的数据强制全部输出,并清空缓冲区。

3)close():关闭输出流并释放与该流关联的所有系统资源。

2、字符流

Reader和Writer是抽象类,它们分别为字符输入和输出操作定义了方法,它们的子类重载或重写了这些方法。 

Reader类中的主要常用方法:

1)read():读取字符。

2)ready():判断输入字符流中的数据是否准备好。

3)close():释放资源。

Writer类中的主要常用方法:

1)write():写入字符。

2)flush():刷新流的缓冲。

3)close():释放资源。

9.2节点流与处理流

1、节点流

计算机中的外部设备(如键盘、显示器)、磁盘文件或一块内存区域统称为节点。

流的一端是程序,另一端是节点的流,称为节点流。

2、处理流

以其他已经存在的流作为一个端点的流,称为处理流。处理流又称过滤流。

处理流构造方法总有一个其他流对象作参数。

InputStream is = new FileInputStream("data.dat");

9.3文件流

FileInputStream和FileOutputStream

FileReader和FileWriter

import java.io.*;  
  
public class FileIOExample {  
    public static void main(String[] args) {  
        File inputFile = new File("input.txt");  
        File outputFile = new File("output.txt");  
  
        try (FileReader reader = new FileReader(inputFile);  
             FileWriter writer = new FileWriter(outputFile)) {  
  
            char[] buffer = new char[1024];  
            int length;  
  
            // 从输入文件中读取数据  
            while ((length = reader.read(buffer)) > 0) {  
                writer.write(buffer, 0, length);  
            }  
  
            System.out.println("文件复制完成。");  
  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}

9.4缓冲流

在对流进行读写操作时,使用一块称作缓冲区的内存空间,输出的数据先存入缓冲区,当缓冲区满了或调用缓冲区的flush()方法后,才完成对输出设备或文件的实际输出;

输入数据时,从输入设备或文件每次读入尽可能多的数据到缓冲区,程序需要的数据从缓冲区取得,当缓冲区变空时再读入一个数据块。

9.1Scanner类

import java.util.*;
public class Main {
    public static  void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        System.out.println(s);
    }
}
  • nextInt():读取一个整数。
  • nextLine():读取一行文本(直到用户按下 Enter 键)。
  • next():读取一个单词(遇到空格、制表符或换行符时停止)。
  • nextDouble():读取一个双精度浮点数。

 next()和nextLine()的区别

next()方法:

它读取输入直到遇到第一个空格、制表符或换行符。

例如,如果你输入 "Hello World",next() 只会返回 "Hello"。

nextLine()方法:

它读取整行内容,直到遇到换行符。

使用 nextLine() 时,如果用户在上一次输入后按下了 Enter 键,但没有输入任何内容,nextLine() 会直接返回一个空字符串。

在上述 "Hello World" 的例子中,nextLine() 会返回 "World"(前提是 next() 已经读取了 "Hello" 并遇到了空格)。

9.2matches方法(正则表达式)

在Java中,matches方法是String类的一个方法,它用于判断整个字符串是否与给定的正则表达式匹配。如果字符串符合正则表达式的模式,则matches方法返回true,否则返回false

matches方法要求整个字符串与正则表达式匹配,而不是字符串中的一部分。如果你想在字符串中查找与正则表达式匹配的子串,你应该使用PatternMatcher类,或者String类的findindexOfreplaceAllsplit等方法。

public class MatchesExample {  
    public static void main(String[] args) {  
        // 定义一个字符串  
        String text = "Hello, World!";  
          
        // 使用正则表达式匹配整个字符串  
        boolean isMatch = text.matches("Hello, World!");  
          
        // 输出匹配结果  
        System.out.println("Does the text match the regex? " + isMatch);  
          
        // 尝试匹配不同的字符串  
        isMatch = text.matches("Hello.*!"); // .* 表示匹配任意数量的任意字符  
        System.out.println("Does the text match the regex with wildcards? " + isMatch);  
          
        // 不匹配的例子  
        isMatch = text.matches("Goodbye, World!");  
        System.out.println("Does the text match the mismatched regex? " + isMatch);  
    }  
}

e22742f16b45407ea69f0a1f58e5c266.png

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        String emailMatcher="[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+";

        //利用matches()方法进行正则匹配,如果合法,则输出"邮箱格式合法",否则输出"邮箱格式不合法"
        System.out.println(str.matches(emailMatcher)?"邮箱格式合法":"邮箱格式不合法");

    }
}

9.4序列化和反序列化 

ObjectInputStream 和 ObjectOutputStream 是 Java 中用于对象序列化和反序列化的两个核心类。序列化是将对象的状态转换为可以存储或传输的形式的过程,而反序列化则是将这个形式的数据恢复为对象的过程。

以下是这两个类的简要概述和它们的用途:

ObjectOutputStream

ObjectOutputStream 类用于将 Java 对象序列化(或转换为字节流)以便可以将其写入输出流(如文件或网络连接)。要使用 ObjectOutputStream,您需要首先创建一个输出流(如 FileOutputStream),然后将其传递给 ObjectOutputStream 的构造函数。

例如:

FileOutputStream fos = new FileOutputStream("file.ser");  
ObjectOutputStream oos = new ObjectOutputStream(fos);  
oos.writeObject(myObject); // 将 myObject 序列化并写入文件  
oos.close();  
fos.close();

ObjectInputStream

ObjectInputStream 类用于从输入流(如文件或网络连接)中反序列化(或读取)Java 对象。同样,您需要首先创建一个输入流(如 FileInputStream),然后将其传递给 ObjectInputStream 的构造函数。

例如:

FileInputStream fis = new FileInputStream("file.ser");  
ObjectInputStream ois = new ObjectInputStream(fis);  
MyClass myObject = (MyClass) ois.readObject(); // 从文件中反序列化对象  
ois.close();  
fis.close();

注意事项

  1. 安全性:反序列化过程可能存在安全风险,因为恶意的序列化数据可能导致代码执行或其他形式的攻击。因此,当从不受信任的来源反序列化数据时,应格外小心。

  2. 版本兼容性:序列化的对象应该与反序列化的代码版本兼容。如果对象的类在序列化后进行了更改(例如,添加或删除字段),则反序列化可能会失败或产生不正确的结果。

  3. 不是所有对象都可以序列化:只有实现了 Serializable 接口的对象才能被序列化。如果一个类的实例需要被序列化,那么这个类必须实现 Serializable 接口,即使它不包含任何特定的序列化代码。这个接口是一个标记接口,没有任何方法需要实现。

public class MyClass implements Serializable {  
    // ...  
}

总的来说,ObjectInputStream 和 ObjectOutputStream 提供了 Java 对象序列化和反序列化的基本机制,使得对象可以轻松地保存到文件、数据库或通过网络发送。

第十章图形用户界面

Java GUI——Java图形用户界面_java图形界面-CSDN博客

JFrame(框架)

JFrame frame = new JFrame("简易计算器");
        frame.setSize(600, 300);
        frame.setVisible(true);

 JButton(按钮)

        //添加按钮
        JButton button1 = new JButton("+");
        JButton button2 = new JButton("-");
        JButton button3 = new JButton("*");
        JButton button4 = new JButton("/");
        //按钮字体
        Font font = new Font("宋体", Font.BOLD, 20);
        button1.setFont(font);
        button2.setFont(font);
        button3.setFont(font);
        button4.setFont(font);
        //按钮布局
        frame.setLayout(new BorderLayout());
        JPanel panel1 = new JPanel(new FlowLayout());
        panel1.add(button1);
        panel1.add(button2);
        panel1.add(button3);
        panel1.add(button4);
        frame.add(panel1, BorderLayout.NORTH);
        //按钮大小
        button1.setPreferredSize(new Dimension(100, 50));
        button2.setPreferredSize(new Dimension(100, 50));
        button3.setPreferredSize(new Dimension(100, 50));
        button4.setPreferredSize(new Dimension(100, 50));

 

JTextArea(文本输入框)

        // 添加输入框
        JTextField textField1 = new JTextField(10);
        JTextField textField2 = new JTextField(10);
        JTextField textField3 = new JTextField(10);
        textField1.setFont(font);
        textField2.setFont(font);
        textField3.setFont(font);
        textField3.setEditable(false);
        JPanel panel2 = new JPanel(new FlowLayout());
        panel2.add(textField1);
        panel2.add(textField2);
        panel2.add(textField3);
        frame.add(panel2, BorderLayout.CENTER);

        // 显示输入框
        textField1.setVisible(true);
        textField2.setVisible(true);
        textField3.setVisible(true);

 

 addActionListener(按钮监听)

// 添加事件
        button1.addActionListener(e -> {
                int num1 = Integer.parseInt(textField1.getText());
                int num2 = Integer.parseInt(textField2.getText());
                int result = num1 + num2;
                textField3.setText(String.valueOf(result));
        });
        button2.addActionListener(e -> {
                int num1 = Integer.parseInt(textField1.getText());
                int num2 = Integer.parseInt(textField2.getText());
                int result = num1 - num2;
                textField3.setText(String.valueOf(result));
        });
        button3.addActionListener(e -> {
                int num1 = Integer.parseInt(textField1.getText());
                int num2 = Integer.parseInt(textField2.getText());
                int result = num1 * num2;
                textField3.setText(String.valueOf(result));
        });
        button4.addActionListener(e -> {
                int num1 = Integer.parseInt(textField1.getText());
                int num2 = Integer.parseInt(textField2.getText());
                int result = num1 / num2;
                textField3.setText(String.valueOf(result));
        });

 

第十一章网络编程

11.1网络编程

11.1.1URL

协议名:主机名/目录及文件名

如:http://www.pku.edu.cn/index.html

Java提供了URL类来处理URL,通过URL类,可以解析和操作URL地址,如获取协议、主机、端口、路径等信息。

下面是一个示例代码,演示了如何使用URL类获取网页内容:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

public class URLExample {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://www.example.com");
            URLConnection connection = url.openConnection();

            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

11.1.2Socket编程

通过Socket类,可以实现客户端和服务器之间的网络连接和数据传输。Java提供了Socket和ServerSocket类,分别用于客户端和服务器端的Socket编程。

DataInputStream 和 DataOutputStream

这两个类用于在Socket连接上进行数据的读写,提供了对基本数据类型(如int、double等)的读写方法。

下面是一个示例代码,演示了使用Socket进行简单的客户端和服务器通信:

// 服务器端代码
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("服务器启动,等待客户端连接...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端连接成功,地址:" + clientSocket.getInetAddress());

                // 处理客户端请求
                // ...

                clientSocket.close();
                System.out.println("客户端连接断开");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端代码
import java.io.IOException;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8888)) {
            System.out.println("连接服务器成功");

            // 发送请求和接收响应
            // ...
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

第十二章JDBC编程

JDBC的全称是Java Database Connectivity,即Java数据库连接,即一系列Java接口,它规范以统一标准方式使用JDBC驱动程序与数据库交互。

注解

注解常用于日志管理、权限控制、数据校验、序列化、切面编程(AOP)、测试框架等场景,能帮助简化配置、提高代码的可读性和自动化处理能力。

泛型

泛型在Java中是一种强大的类型安全工具,它允许在定义类、接口或方法时使用未知的类型参数(即类型占位符),并在实际使用时传入具体的数据类型。简单来说:
类型参数化:就像方法可以接受参数一样,泛型允许你定义类型级别的参数,如 List<T>,这里的 T 是类型参数,代表某种未知的类型。
类型安全:使用泛型可以确保在编译时期就能检查类型安全,例如,一个 List<String> 不会允许插入整数或其他非字符串类型,这减少了运行时因类型错误引发的异常。
代码重用:通过泛型,你可以编写适用于多种类型的通用组件。例如,一个泛型类 ArrayList<T> 可以用来创建 ArrayList<Integer>、ArrayList<String> 或任何其他对象类型的列表。
类型擦除:Java中的泛型是类型擦除的,意味着在编译阶段,所有泛型信息会被擦除,并替换为对应的原始类型(如 List<Object>)。这样设计是为了保持与Java早先版本的兼容性,但在运行时不会保留类型参数的具体信息。
总结起来,Java泛型增强了代码的灵活性、可读性和可维护性,使得开发者能够编写出更抽象、更具有普适性的代码结构。

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值