JAVA从入门到精通2
2023-12-20 14:03:13 5 举报
AI智能生成
2023学年学习章节总结
作者其他创作
大纲/内容
将指定对象添加到该集合中
add(E e)
将指定对象从该集合中移除
remove(Object o)
返回booleam值,用于判断当前集合是否为空
isEmpty
返回再次Collection的元素上进行迭代的迭代器。用于遍历集合中的对象
iterator
返回int型,获取该集合中元素的个数
size
collection接口
arraylist类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。
缺点是向指定的索引位置插入对象或删除对象速度较慢
arraylist
linkedlist类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。
缺点是随机访问集合中的对象时速度较慢
linkedlist
list集合
hashset类实现set接口,使用哈希表排序,它不能保证set集合的迭代顺序,特别是不能保证顺序恒久不变
hashset
treeset类不仅实现set接口,还实现了java.util.SortedSet接口,因此treeset类实现的数组在遍历集合时按照自然排序递增排序,也可以按照指定比较器排序
treeset
set集合
hashmap类是基于哈希表的map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性,同理,他不能保证顺序的唯一性,特别是不能保证顺序恒久不变
hashmap
treemap类不仅实现了map接口,还是实现了java.util.SortedMap接口,因此集合中的映射关系具有一定的顺序,但在添加,删除和定位映射关系时,treemap类比hashmap类性能稍差,且不允许键值为null
treemap
map集合
集合类
public interface Constants{ public static final int Constants_A = 1; public static final int Constants_B = 12;}
使用枚举设置常量
图片
枚举常用的方法
枚举类型
语法:类名<T>其中,T是泛型的名称,代表某一种类型,如果不指定某种类型,则默认使用Object类型
定义泛型类
font color=\"#e74f4c\
定义泛型类时声明多个类型
定义泛型类时声明数组类型
集合类声明容器的元素
泛型的常规用法
语法:class 类名称<T extends anyClass>其中,anyClass指某个接口或类
限制泛型可用类型
语法:A<? extends List>a = null;a = new A<ArryList>();a = new A<LinkedList>();
语法:泛型类名称<? extends List> a=null;其中<? extends List>表示类型未知,当需要使用该泛型时,可以单独实例化
使用类型通配符
继承泛型类型与实现泛型接口
泛型的高级用法
泛型
泛型总结:1.泛型的类型参数只能是类类型,不可以是简单类型,如“A<int>”这种泛型定义就是错误的2.泛型的类型个数可以是多个3.可以使用extends关键字限制泛型的类型4.可以使用他通配符限制泛型的类型
枚举类型与泛型
例如:interface Mylnterface{ void method();}
函数式接口:指仅包含一个抽象方法的接口,接口中的方法简单明了地说明了接口的用途
lambd表达式实现无参抽象方法:很多函数式接口的抽象方法式无参数的,如线程接口Runnable接口只要一个run()方法,这样的无参抽象方法在lambda表达式中使用“()”表示
lambda表达式使用代码块:当函数式接口的抽象方法需要实现复杂逻辑而不是返回一个简单的表达式的话,就需要在lambda表达式中使用代码块,它会自动判断返回值类型是否符合抽象方法的定义
lambda表达式实现函数式接口
lambda表达式无法更改局部变量:lambda表达式只能调用局部变量,却不能改变其值
lambda表达式可以更改类成员变量:类成员变量是在lambda表达式中不是被final修饰的,所以lambda表达式可以改变其值
lambda表达式调用外部变量
lambda表达式与异常处理
lambda表达式()->{代码块}
语法: 类名::静态方法名
引用静态方法
引用成员方法的语法: 对象名::成员方法名
引用成员方法
引用带泛型的方法
语法: 类名::new
引用无参构造方法
引用有参构造方法的语法与引用无参构造方法一样。区别就是函数式接口的抽象方法是有参数的
引用有参构造方法
语法; 类名[]::new
引用数组构造方法
引用构造方法
方法的引用
Steam接口
Optional接口
Collectors类
filterO方法是Stream 接口提供的过滤方法。该方法可以将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需使用Stream 提供的collectO方法按照指定方法重新封装。
filter()方法
该方法可以去除流中的重复元素,效果与SQL语句中的DISTINCT关键字一样
distinct()方法
Iimit()方法是Stream接口提供的方法,该方法可以获取流中前N个元素
Iimit()方法
skip()方法是Stream接口提供的方法,该方法可以忽略流中的前N个元素
skip方法
数据过滤
数据映射
该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值
allMatch()方法
该方法会判断流中的元素是否有符合某一条件
anyMatch方法()方法
该方法会判断流中的所有元素是否都不符合某一条件
noneMatch()方法
这个方法会返回符合条件的第一个元素
findFirst()方法
数据查找
不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算
统计
分组
数据收集
流处理
lambda表达式与流处理
InputStream类是字节输入流的抽象类,他是所有字节输入流的父类。
read()方法:从输入流中读取数据的下一字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值为-1.mark(int readlimit)方法: 在输入流的当前位置放置一个标记,readlimit参数告知此输入流再标记位置失效之前允许读取的字节数。reset()方法:将输入指针返回到当前所做的标记处。skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。markSupported()方法:如果当前流支持mark()/reset()操作就返回turn。close方法:关闭此输入流并释放与该流关联的所有系统资源。
inputStream字节/Reader字符输入流
并不是所有的 InputStream类的子类都支持 InputStream 类中定义的所有方法、如skip0、mark0、Tset0等方法只对某些子类有用。
OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类
OutputStream字节/writer字符输出流
输入输出流
1. File(String pathname)该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新File实例。new File(String pathname)
可以使用File类创建一个文件对象。通常使用以下3种构造方法来创建文件对象。
文件的创建与删除
获取文件信息
File类
FileinputStream 类常用的构造方法如下: FileinputStream(String name)。 FilelnputStream(File file)。
FilelnputStream文件字节输入流
FileOutputStream文件字节输出流
FileReader文件字符输入流
FileWriter文件字符输出流
文件输入输出流
FilelnputStream 类与FileOutputStream类都用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream 类,该类继承自 InputStream 类。FileOutputStream 类与FilelmputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutputStream类的子类。
概要
BufferedInputStream 类有两个构造方法:font color=\"#e74f4c\
BufferedInputStream 类可以对所有 InputStream 类进行带缓存区的包装以达到性能的优化。
第一种形式的构造万法创建了一个有32个字节的缓存区;第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。
BufferedinputStream缓存字节输入流
BufferedOutputStream类也有两个构造方法:font color=\"#e74f4c\
使用BufferedOutputStrcam 类输出信息和仅用0utputStream 类输出信息完全一样,只不过BufferedOutputStream 有一个fushO方法用来将缓存区的数据强制输出完。
第一种构造方法创建一个有32个字节的缓存区,第二种构造方法以指定的大小来创建缓存区。
BufferedOutputStream缓存字节输出流
根据BufferedReader类的特点,可以总结出如图所示的带缓存的字符数据读取文件的过程。
BufferedReader 类常用的方法如下:区readO方法:读取单个字符。区readLine0方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null.
BufferedReader缓存字符输入流
BufferedWriter缓存字符输出流
带缓存的输入输出流
1. DatalnputStream(InputStream in):使用指定的基础 InputStream 对象创建一个DataInputStream对象。
DataOutputStream 类提供了将字符串、double 数据、int 数据、boolean数据写入文件的方法。其中,将字符串写入文件的方法有 3种,分别是writeBytes(String s)、writeChars(String s)、writeUTF(String s)。由于Java 中的字符是Unicode 编码,是双字节的,writeBytesO方法只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeCharsO方法将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTFO方法将字符串按照UTF 编码后的字节长度写入目标设备,然后才是每一个字节的UTF 编码。
DatalnputStream数据输入流
2. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。
DatalnputStream 类只提供了一个readUTFO方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream 类中只有writeUTFO方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。
DataOutputStream数据输出流
数据输入输出流
I/O(输入/输出)
访问构造方法
方法的所有修饰符的典型代码如下: int modifiers = constructor.getModifiers(); boolean isEmbellishByPrivate = Modifier.isPrivate(modifiers); String embelishment = Modifier.toString(modifiers);
在通过下列一组方法访问成员变量时,将返回Field 类型的对象或数组。每个Field对象代表一个成员变量,利用Ficld 对象可以操纵相应的成员变量:getFields()getField(String name)getDeclaredFields()getDeclaredField(String name)如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:object. getDeclaredField(\"birthday\");
访问成员变量
访问成员方法
反射
@Override :限定重写父类方法作用范围成员方法@SuppressWarnings :抑制编译器警告作用范围类、成员属性、成员方法@Deprecated :标示已过时作用范围类、成员属性、成员方法在定义Annotation 类型时,也需要用到用来定义接口的interface 关键字,但需要在interface关键字前加一个“@”符号,即定义Annotation 类型的关键字为@interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。
定义注解
结果为:
import java.lang.annotation.*;import java.lang.reflect.*; public class AnnotationTest { public static void main(String[] args) { Class recordC = null; try { recordC = Class.forName(\"Record\"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(\"------ 构造方法的描述如下 ------\"); Constructor[] declaredConstructors = recordC.getDeclaredConstructors(); // 获得所有构造方法 for (int i = 0; i < declaredConstructors.length; i++) { Constructor constructor = declaredConstructors[i]; // 遍历构造方法 // 查看是否具有指定类型的注释 if (constructor.isAnnotationPresent(Constructor_Annotation.class)) { // 获得指定类型的注释 Constructor_Annotation ca = (Constructor_Annotation) constructor .getAnnotation(Constructor_Annotation.class); System.out.println(ca.value()); // 获得注释信息 } Annotation[][] parameterAnnotations = constructor.getParameterAnnotations(); // 获得参数的注释 for (int j = 0; j < parameterAnnotations.length; j++) { // 获得指定参数注释的长度 int length = parameterAnnotations[j].length; if (length == 0) // 如果长度为0则表示没有为该参数添加注释 System.out.println(\" 未添加Annotation的参数\"); else for (int k = 0; k < length; k++) { // 获得参数的注释 Field_Method_Parameter_Annotation pa = (Field_Method_Parameter_Annotation) parameterAnnotations[j][k]; System.out.print(\" \" + pa.describe()); // 获得参数描述 System.out.println(\" \" + pa.type()); // 获得参数类型 } } System.out.println(); } System.out.println(); System.out.println(\"-------- 字段的描述如下 --------\"); Field[] declaredFields = recordC.getDeclaredFields(); // 获得所有字段 for (int i = 0; i < declaredFields.length; i++) { Field field = declaredFields[i]; // 遍历字段 // 查看是否具有指定类型的注释 if (field.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) { // 获得指定类型的注释 Field_Method_Parameter_Annotation fa = field.getAnnotation(Field_Method_Parameter_Annotation.class); System.out.print(\" \" + fa.describe()); // 获得字段的描述 System.out.println(\" \" + fa.type()); // 获得字段的类型 } } System.out.println(); System.out.println(\"-------- 方法的描述如下 --------\"); Method[] methods = recordC.getDeclaredMethods(); // 获得所有方法 for (int i = 0; i < methods.length; i++) { Method method = methods[i]; // 遍历方法 // 查看是否具有指定类型的注释 if (method.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) { // 获得指定类型的注释 Field_Method_Parameter_Annotation ma = method.getAnnotation(Field_Method_Parameter_Annotation.class); System.out.println(ma.describe()); // 获得方法的描述 System.out.println(ma.type()); // 获得方法的返回值类型 } Annotation[][] parameterAnnotations = method.getParameterAnnotations(); // 获得参数的注释 for (int j = 0; j < parameterAnnotations.length; j++) { int length = parameterAnnotations[j].length; // 获得指定参数注释的长度 if (length == 0) // 如果长度为0表示没有为该参数添加注释 System.out.println(\" 未添加Annotation的参数\"); else for (int k = 0; k < length; k++) { // 获得指定类型的注释 Field_Method_Parameter_Annotation pa = (Field_Method_Parameter_Annotation) parameterAnnotations[j][k]; System.out.print(\" \" + pa.describe()); // 获得参数的描述 System.out.println(\" \" + pa.type()); // 获得参数的类型 } } System.out.println(); } }}//例题16.5
访问注解信息
Annotation注解
反射与注解
打开“命令提示符”,用管理员身份运行
第一步
登录MySQL
第二步
创建库和表
第三步
使用Java命令查询数据库操作
第四步
右击——点击“Build Path”——选择第四个——找到包的位置——导入成功
第五步
创建java项目连接数据库1.注册驱动2.获取链接3.获取statment对象 4.执行sql语句返回结果集 5.遍历结果集 6.关闭连接释放资源:java存在自动回收资源,不关闭会占空间
第六步
数据库操作
Grapics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。 Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、钜形、多边形、椭面、圆弧等形状和文本、图片的绘制操作。另外,在执行这些操作之前,还可以使用相应的方法设置给图的颜色和字体等状态属性。
Graphics类
使用Graphics 类可以完成简单的图形绘制任务,但是它所实现的功能非常有限,如无法改变线条的粗细、不能对图片使用旋转和模糊等过滤效果。 Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由子Graphies2D类是Graphics 类的扩展,也是推荐使用的Java 绘图类。
Graphics2D类
Graphics2D 是推荐使用的绘图类,但是程序设计中提供的绘图对象大多是Gmphics 类的实例对象,这时应该使用强制类型转换将其转换为Giraphics2D 类型。
java绘图类
Java 可以分别使用Graphics 类和 Graphics2D 类绘制图形,Graphics类使用不同的方法实现不同图形的给制。例如,drawLine0方法可以绘制直线,drawRectO方法用于绘制矩形,drawOval0方法用于绘制椭圓形等。
Graphics2D类是在继承Graphics 类的基础上编写的,它包含了Graphics类的绘图方法并添加了更强的功能,在创建绘图类时推荐使用该类。Graphics2D类可以分别使用不同的类来表示不同的形状,Line2D类、Rectangle2D类等。 要绘制指定形状的图形,需要先创建并初始化该图形类的对象,且这些图形类必须是Shape接口药实现类;然后使用Graphics2D类的draw0方法绘制该图形对象,或者使用610方法填充该图形对象。
java.awt.geom 包中提供了如下常用的图形类,这些图形类都实现了Shape 接口:Arc2D类CubicCurve2D类Ellipse2D类Line2D类Point2D类QuadCurve2D类Rectangle2D类RoundRectangle2D类
绘制图形
使用Color 类可以创建任意颜色的对象,不用担心平台是否支持该颜色,因为Java以跨平台和与硬件无关的方式支持颜色管理。创建Color 对象的构造方法有如下两种:font color=\"#e74f4c\
设置颜色
rgb:颜色值,该值是红、绿、蓝三原色的总和。r:该参数是三原色中红色的取值。g:该参数是三原色中绿色的取值。b:该参数是三原色中蓝色的取值。
默认情况下,Graphics 类使用的画笔属性是粗细为1个像素的正方形,而Graphics2D类可以调用setStrokeO方法设置画笔的属性,如改变线条的粗细、虚实,定义线段端点的形状、风格等。
其中,参数stroke是Stroke 接口的实现类对象。
语法格式如下:setStroke(Stroke stroke)
etStroke0方法必须接受一个 Stroke 接口的实现类对象作参数,java.awrt包中提供了BasisSrke类它实现了Stroke接口,并且通过不同的构造方法创建画笔属性不同的对象。这些构造方法如下:font color=\"#e74f4c\
设置画笔
颜色与画笔
Java 使用Font 类封装了字体的大小、样式等属性,该类在java.awt包中定义,其构造方法可以指定字体的名称、大小和样式3个属性。
语法如下:font color=\"#e74f4c\
设置绘图类的字体可以使用绘图类的setFontO方法。设置字体以后在图形上下文中绘制的所有文字都使用该字体,除非再次设置其他字体。语法如下:setFont(Font font)
设置字体
name:字体的名称style:字体的样式size:字体的大小
其中,参数font 是Font 类的字体对象。
Graphics2D类提供了drawString0方法,使用该方法可以实现图形上下文的文本绘制,从而实现在图片上显示文字的功能。
语法格式有如下两种:font color=\"#e74f4c\
显示文字
str:要绘制的文本字符串。x:绘制字符串的水平起始位置。y:绘制字符串的垂直起始位置。这两个方法唯一不同的就是x和y的参数类型不同。
绘制文本
绘图类不仅可以绘制图形和文本,还可以使用drawImageO方法将图片资源显示到绘图上下文中,而且可以实现各种特效处理,如图片的缩放、翻转等。有关图像处理的知识将在19.6节讲解,本节主要讲解如何显示图片。
语法如下:font color=\"#e74f4c\
显示图片
在显示图片时,使用了drawImageO方法将图片以原始大小显示在窗体中,要想实现图片的放大与缩小,则需要使用它的重载方法。
缩放
图像的翻转需要使用drawImage()方法的另一个重载方法。
此方法总是用非缩放的图像来呈现缩放的矩形,并动态地执行所需的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。方法中涉及的参数说明如表所示
翻转
图像旋转需要调用Graphics2D类的rotateO方法,该方法将根据指定的弧度旋转图像。
语法如下:rotate(double theta)
旋转
其中,theta 是指旋转的弧度
可以使用Graphics2D类提供的shearO方法设置绘图的倾斜方向,从而使图像实现倾斜的效果。
倾斜
shx:水平方向的倾斜量shy : 垂直方向的倾斜量
显示及处理图片
java绘图
继承Thread类创建一个新的线程的语法如下:public class ThreadTest extends Threadf {}
Thread类中常用的两个构造方法如下:public Thread():创建一个新的线程对象。public Thread(String threadName):创建一个名称为threadName的线程对象。
Thread 类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。
run0方法必须使用以下语法格式:public void run() {}
完成线程真正功能的代码放在类的run0方法中,当一个类继承Thread类后,就可以在该类中覆盖run0方法,将实现该线程功能的代码写入runO方法中,然后调用 Thread类中的start0方法执行线程也就是调用run0方法。
代码如下:public static void main(String[] args){ new ThreadTest().start();}
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由Java 虚拟机负责,程序员负责启动自己的线程。
继承Thread类
实现Runnable接口的语法如下:public class Thread extends Object implements Runnable
Thread类中有以下两个构造方法:font color=\"#e74f4c\
实现Runnable 接口的程序会创建一个Thread对象,并将 Runnable 对象与Thread对象相关联。
使用Runnable 接口启动新的线程的步骤如下:建立Runnable对象使用参数为Runnable对象的构造方法创建Thread实例调用startO方法启动线程
通过Runnable 接口创建线程时,程序员首先需要编写一个实现Runnable接口的类,然后实例化该类的对象,这样就建立了Runnable对象;接下来使用相应的构造方法创建Thread 实例;最后使用该实例调用Thread类中的startO方法启动线程。
实现Runnad接口
创建线程
sleep()方法语法如下:try{ Thread.sleep(2000);}catch(InterruptedException e){ e.printStackTrace(();}
一种能控制线程行为的方法是调用sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。
休眠
结果如下
当某一个线程使用join()方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行
加入
下面的实例演示了某个线程使用interrupted()方法,同时程序抛出了InterruptedException异常,在异常处理时结束了while 循环。在项目中,经常在这里执行关闭数据库连接和关闭Socket连接等操作。
以往有的时候会使用stop()方法停止线程,但当前版本的JDK早己废除了stop()方法,不建议使用stop()方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。如果线程是因为使用了slcep()或wait()方法进入了就绪状态,可以使用Thread 类中 interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while循环。
中断
Thread 类中提供了一种礼让方法,使用yield()方法表示,它只是给当前正处于运行状态的线程个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。yield()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状体。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配CPU时间片来执行。
礼让
操作线程
每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就较低。 Thread类中包含的成员变量代表了线程的某些优先级,如Thread.MIN_PRIORITY(常数1)、Thread.MAXPRIORITY(常数10)、Thread.NORM PRIORITY(常数5)。其中,每个线程的优先级都在 Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,在默认情况下其优先级都是Thread.NORM PRIORITY。每个新产生的线程都继承了父线程的优先级。 在多任务操作系统中,每个线程都会得到一小段CPU时间片运行,在时间结束时,将轮换另一个线程进入运行状态,这时系统会选择与当前线程优先级相同的线程予以运行。系统始终选择就绪状态下优先级较高的线程进入运行状态。处于各个优先级状态下的线程的运行顺序如图所示。
public class ThreadSafeTest implements Runnable{ int num = 10; //设置当前总票数 public void run() { while(true) { //设置无限循环 if(num>0) { //判断当前票数是否大于0 try { Thread.sleep(100); //使当前线程休眠100秒 } catch(InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+\"---票数\
例如,在项目中创建ThreadSafeTest类,该类实现了Rummable接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能的代码如下:
线程安全
语法如下:synchronized(Object) {}
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用synchronized关键字,使用该关键字包含的代码块称为同步块,也称为临界区
其语法如下:synchronized void f(){}
同步方法就是在方法前面用synchronized关键字修饰的方法
同步机制
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。
通常将共享资源的操作放置在 synchronized 定义的区域内,这样当其他线程获取到这个锁时,就必须等待锁被释放后才可以进入该区域。Object 为任意一个对象,每个对象都存在一个标志位,并具有两个值,分别为0和1。一个线程运行到同步块时首先检查该对象的标志位,如果为0状态,表明此同步块内存在其他线程,这时当期线程处于就绪状态,直到处于同步块中的线程执行完同步块中的代码后,这时该对象的标识位设置为1,当期线程才能开始执行同步块中的代码,并将Object对象的标识位设置为0,以防止其他线程执行同步块中的代码。
线程同步
多线程
为了实现两台计算机的通信,必须用一个网络线路连接两台计算机。
局域网与互联网
IP是Internet Protocol的简称,是一种网络协议。Internet 网络采用的协议是TCP/IP协议,其全称是Transmission Control Protocol/Internet Protocol。Internet 依靠TCP/IP协议,在全球范围内实现了不同硬件结构、不同操作系统、不同网络系统间的互联。在Internet 网络上存在着数以亿计的主机,每台主机都用网络为其分配的 Internet 地址代表自己,这个地址就是I地址。到目前为止,I地址用4个字节,也就是32位的二进制数来表示,称为IPv4。为了便于使用,通常取用每个字节的十进制数,并且每个字节之间用圆点隔开来表示I地址,如192.168.1.1。现在人们正在试验使用16个字节来表示I地址,这就是IPv6,但IPv6还没有投入使用。TCP/IP 模式是一种层次结构,共分为4层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性
IP协议
TCP 协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送。TCP可以保证数据从一端送至连接的另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相同。因此,TCP协议适合可靠性要求比较高的场合。就像拨打电话,必须先拨号给对方,等两端确定连接后,相互才能听到对方说话,也知道对方回应的是什么。
UDP 协议适合于一些对数据准确性要求不高,但对传输速度和时效性要求非常高的网站,如网络聊天室、在线影片等。这是由于TCP协议在认证上存在额外耗费,可能使传输速度减慢,而UDP协议即使有一小部分数据包遗失或传送顺序有所不同,也不会严重危害该项通信。
UDP是无连接通信协议,不保证数据的可靠传输,但能够向若干个目标发送数据,或接收来自若干个源的数据。UDP以独立发送数据包的方式进行。这种方式就像邮递员送信给收信人,可以寄出很多信给同一个人,且每一封信都是相对独立的,各封信送达的顺序并不重要,收信人接收信件的顺序也不能保证与寄出信件的顺序相同。
TCP与UDP协议
网络协议
端口与套接字
网络基础概念
java.net包中的InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
InetAddress地址类
ServerSocket服务器套接字类
import java.io.*;import java.net.*; public class MyServer { private ServerSocket server; // 服务器套接字 private Socket socket; // 客户端套接字 void start() {// 启动服务器 try { server = new ServerSocket(8998); // 服务器启用8998端口 System.out.println(\"服务器套接字已经创建成功\"); while (true) { System.out.println(\"等待客户端的连接\"); socket = server.accept(); // 服务器监听客户端连接 // 根据套接字字节流创建字符输入流 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true) {// 循环接受信息 String message = reader.readLine();// 读取一行文本 if (\"exit\".equals(message)) {// 如果客户端发来的内容为“exit” System.out.println(\"客户端退出\"); break;// 停止接受信息 } System.out.println(\"客户端:\" + message); } reader.close(); // 关闭流 socket.close(); // 关闭套接字 } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { MyServer tcp = new MyServer(); tcp.start(); // 启动服务器 }}//21.2
TCP网络程序设计
TCP
java.net 包的DatagramPacket 类用来表示数据包。
DatagramPacke数据包类
DatagramSocket套接字类
广播主机程序不断地向外播放信息,代码如下:import java.io.IOException;import java.net.*; public class Notification extends Thread { String weather = \"节目预报:八点有大型晚会,请收听\";// 发送的消息 int port = 9898; // 端口 InetAddress iaddress = null; MulticastSocket socket = null; // 多点广播套接字 Notification() { try { iaddress = InetAddress.getByName(\"224.255.10.0\
UDP网络程序设计
将数据打包(称为数据包),然后将数据包发往目的地。接收别人发来的数据包,然后查看数据包。发送数据包的步骤如下:
接收数据包的步骤如下:
UDP
网络通信
java从入门到精通2
收藏
收藏
0 条评论
下一页