JAVA从入门到精通2
2023-12-20 14:03:13 5 举报AI智能生成
2023学年学习章节总结
大学
模版推荐
作者其他创作
大纲/内容
集合类
collection接口
add(E e)
将指定对象添加到该集合中
remove(Object o)
将指定对象从该集合中移除
isEmpty
返回booleam值,用于判断当前集合是否为空
iterator
返回再次Collection的元素上进行迭代的迭代器。用于遍历集合中的对象
size
返回int型,获取该集合中元素的个数
list集合
arraylist
arraylist类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。
<font color="#e74f4c">缺点是向指定的索引位置插入对象或删除对象速度较慢</font>
linkedlist
linkedlist类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。
<font color="#e74f4c">缺点是随机访问集合中的对象时速度较慢</font>
set集合
hashset
hashset类实现set接口,使用哈希表排序,它不能保证set集合的迭代顺序,特别是不能保证顺序恒久不变
treeset
treeset类不仅实现set接口,还实现了java.util.SortedSet接口,因此treeset类实现的数组在遍历集合时按照自然排序递增排序,也可以按照指定比较器排序
map集合
hashmap
hashmap类是基于哈希表的map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性,同理,他不能保证顺序的唯一性,特别是不能保证顺序恒久不变
treemap
treemap类不仅实现了map接口,还是实现了java.util.SortedMap接口,因此集合中的映射关系具有一定的顺序,但在添加,删除和定位映射关系时,treemap类比hashmap类性能稍差,且不允许键值为null
枚举类型与泛型
枚举类型
使用枚举设置常量
<b><font color="#e74f4c">public interface Constants{<br> public static final int Constants_A = 1;<br> public static final int Constants_B = 12;<br>}</font></b>
枚举常用的方法
图片
泛型
定义泛型类
<font color="#e74f4c">语法:类名<T><br>其中,T是泛型的名称,代表某一种类型,如果不指定某种类型,则默认使用Object类型</font>
泛型的常规用法
定义泛型类时声明多个类型
<font color="#e74f4c">语法:class MyClass<T1,T2>{ }<br>其中,T1,T2为可能被定义的类型</font>
定义泛型类时声明数组类型
集合类声明容器的元素
图片
泛型的高级用法
限制泛型可用类型
<font color="#e74f4c">语法:class 类名称<T extends anyClass><br>其中,anyClass指某个接口或类</font><br>
使用类型通配符
语法:泛型类名称<? extends List> a=null;<br>其中<? extends List>表示类型未知,当需要使用该泛型时,可以单独实例化
<font color="#e74f4c">语法:<br>A<? extends List>a = null;<br>a = new A<ArryList>();<br>a = new A<LinkedList>();</font>
继承泛型类型与实现泛型接口
语法:<br>class ExtendsClass<T1>{}<br>class SubClass<T1,T2,T3> extends ExtendsClass<T1>{}
lambda表达式与流处理
lambda表达式()->{代码块}
lambda表达式实现函数式接口
函数式接口:<br>指仅包含一个抽象方法的接口,接口中的方法简单明了地说明了接口的用途
<font color="#e74f4c">例如:<br>interface Mylnterface{<br> void method();<br>}</font>
lambd表达式实现无参抽象方法:<br>很多函数式接口的抽象方法式无参数的,如线程接口Runnable接口只要<br>一个run()方法,这样的无参抽象方法在lambda表达式中使用“()”表示
lambda表达式实现有参抽象方法:<br>抽象方法中有一个或多个参数的函数式接口也是很常见的,lambda表达式中可以用<br>“(a1,a2,a2)”的方法表示有参抽象方法,圆括号里标识符也对应抽象方法的参数,<br>如果抽象方法中只有一个参数,也可以省略括号
lambda表达式使用代码块:<br>当函数式接口的抽象方法需要实现复杂逻辑而不是返回一个简单的表达式的话,<br>就需要在lambda表达式中使用代码块,它会自动判断返回值类型是否符合抽象方法<br>的定义
lambda表达式调用外部变量
lambda表达式无法更改局部变量:<br>lambda表达式只能调用局部变量,却不能改变其值
lambda表达式可以更改类成员变量:<br>类成员变量是在lambda表达式中不是被final修饰的,所以lambda表达式可以改变其值<br>
lambda表达式与异常处理
方法的引用
引用静态方法
<font color="#e74f4c">语法:<br> <br>类名::静态方法名</font>
引用成员方法
<font color="#e74f4c">引用成员方法的语法:<br> <br>对象名::成员方法名</font>
引用带泛型的方法
引用构造方法
引用无参构造方法
<font color="#e74f4c"><br>语法:<br> <br>类名::new</font>
引用有参构造方法
引用有参构造方法的语法与引用无参构造方法一样。区别就是函数式接口的抽象方法是有参数的
引用数组构造方法<br>
<font color="#e74f4c"><br>语法;<br> <br>类名[]::new</font>
流处理
Steam接口
Optional接口
Collectors类
数据过滤
filter()方法
filterO方法是Stream 接口提供的过滤方法。该方法可以将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需使用Stream 提供的collectO方法按照指定方法重新封装。
distinct()方法
该方法可以去除流中的重复元素,效果与SQL语句中的DISTINCT关键字一样
Iimit()方法
Iimit()方法是Stream接口提供的方法,该方法可以获取流中前N个元素
skip方法
skip()方法是Stream接口提供的方法,该方法可以忽略流中的前N个元素
数据映射
数据查找
allMatch()方法
该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值
anyMatch方法()方法
该方法会判断流中的元素是否有符合某一条件
noneMatch()方法
该方法会判断流中的所有元素是否都不符合某一条件
findFirst()方法
这个方法会返回符合条件的第一个元素
数据收集
统计
不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算
分组
不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算
I/O(输入/输出)
输入输出流
inputStream字节/Reader字符输入流
InputStream类是字节输入流的抽象类,他是所有字节输入流的父类。
read()方法:从输入流中读取数据的下一字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值为-1.<br>mark(int readlimit)方法: 在输入流的当前位置放置一个标记,readlimit参数告知此输入流再标记位置失效之前允许读取的字节数。<br>reset()方法:将输入指针返回到当前所做的标记处。<br>skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。<br>markSupported()方法:如果当前流支持mark()/reset()操作就返回turn。<br>close方法:关闭此输入流并释放与该流关联的所有系统资源。
OutputStream字节/writer字符输出流
OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类
OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常,<br>1.write(intb)方法:将指定的字节写入此输出流。<br><br>2. writebyte[]b)方法:将b个字节从指定的byte 数组写入此输出流。<br><br>3.write(byte[ b,int off,int len)方法:将指定 byte 数组中从偏移量of开始的len个字节写入此输<br><br>出流。<br><br>4.fush0方法:彻底完成输出并清空缓存区。<br><br>5.close0方法:关闭输出流。<br>
File类
文件的创建与删除
可以使用File类创建一个文件对象。通常使用以下3种构造方法来创建文件对象。<br>
1. File(String pathname)<br>该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新File实例。<br><font color="#e74f4c">new File(String pathname)</font><br>
2. File(String parent,String child)<br>该构造方法根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象。语法如下:<br><font color="#e74f4c">new File(String parent, String child)</font>
3. File(File f, String child)<br>该构造方法根据f抽象路径名和child路径名字符串创建一个新File实例。语法如下<br><font color="#e74f4c">new File(File f,String child)</font>
获取文件信息
文件输入输出流
FilelnputStream文件字节输入流
<br>FileinputStream 类常用的构造方法如下:<br> <br><font color="#e74f4c"> FileinputStream(String name)。<br> <br> FilelnputStream(File file)。</font>
FileOutputStream文件字节输出流
FileReader文件字符输入流
FileWriter文件字符输出流
带缓存的输入输出流
BufferedinputStream缓存字节输入流
BufferedInputStream 类可以对所有 InputStream 类进行带缓存区的包装以达到性能的优化。
BufferedInputStream 类有两个构造方法:<br><font color="#e74f4c">1. BufferedInputStream(InputStream in)。<br>2.BufferedInputStream(InputStream in,int size).</font>
BufferedOutputStream缓存字节输出流
使用BufferedOutputStrcam 类输出信息和仅用0utputStream 类输出信息完全一样,只不过BufferedOutputStream 有一个fushO方法用来将缓存区的数据强制输出完。
BufferedOutputStream类也有两个构造方法:<br><font color="#e74f4c">1. BufferedOutputStream(OutputStream in)。<br>2. BufferedOutputStream(OutputStream in,int size)。</font>
BufferedReader缓存字符输入流
BufferedReader 类常用的方法如下:<br>区readO方法:读取单个字符。<br>区readLine0方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null.<br>
根据BufferedReader类的特点,可以总结出如图所示的带缓存的字符数据读取文件的过程。<br><br>
BufferedWriter缓存字符输出流
BufferedWriter 类中的方法都返回void。常用的方法如下:<br>write(String s,int off, int len)方法:写入字符串的某一部分。<br>flushO方法:刷新该流的缓存。<br>newLineO方法:写入一个行分隔符。
数据输入输出流
DatalnputStream数据输入流
DataOutputStream 类提供了将字符串、double 数据、int 数据、boolean数据写入文件的方法。其中,将字符串写入文件的方法有 3种,分别是writeBytes(String s)、writeChars(String s)、writeUTF(String s)。由于Java 中的字符是Unicode 编码,是双字节的,writeBytesO方法只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeCharsO方法将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTFO方法将字符串按照UTF 编码后的字节长度写入目标设备,然后才是每一个字节的UTF 编码。
1. DatalnputStream(InputStream in):使用指定的基础 InputStream 对象创建一个DataInputStream<br><br>对象。
DataOutputStream数据输出流
DatalnputStream 类只提供了一个readUTFO方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream 类中只有writeUTFO方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。
2. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。
反射与注解
反射
访问构造方法
在通过下列一组方法访问构造方法时,将返回Constructor 类型的对象或数组。每个Constuctor 对象代表一个构造方法,利用Constructor 对象可以操纵相应的构造方法:<br><br>getConstructors()<br>getConstructor(Class<?>...parameterTypes)<br>getDeclaredConstructors()<br>getDeclaredConstructor(Class<?>..parameterTypes)<br>如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String型和 int型的构造方法,通过下面两种方式均可实现:<br><br>objeciClass.getDeclaredConstructor(String.class, int.class);<br> <br>objectClass.getDeclaredConstructor(new Classil { String.class, int.class });
访问成员变量
在通过下列一组方法访问成员变量时,将返回Field 类型的对象或数组。每个Field对象代表一个成员变量,利用Ficld 对象可以操纵相应的成员变量:<br><br>getFields()<br>getField(String name)<br>getDeclaredFields()<br>getDeclaredField(String name)<br>如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:<br><font color="#e74f4c">object. getDeclaredField("birthday");</font>
访问成员方法
在通过下列一组方法访问成员方法时,将返回Method类型的对象或数组。每个Method对象代表-个方法,利用Method 对象可以操纵相应的方法:<br><br>getMethods()<br>getMethod(String name, Class<?>...parameterTypes)<br>getDeclaredMethods()<br>getDeclaredMethod(String name, Class<?>...parameterTypes)<br>如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数类型依次为String型和int型的方法,通过下面两种方式均可实现:<br><br>objectClass.getDeclaredMethod("print",String.class, int.class);<br> <br>objectClass.getDeclaredMethod("print", new Class[] {String.class, int.class });
Annotation注解
定义注解
@Override :限定重写父类方法作用范围成员方法<br>@SuppressWarnings :抑制编译器警告作用范围类、成员属性、成员方法<br>@Deprecated :标示已过时作用范围类、成员属性、成员方法<br>在定义Annotation 类型时,也需要用到用来定义接口的interface 关键字,但需要在interface关键字前加一个“@”符号,即定义Annotation 类型的关键字为@interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。
访问注解信息
<b><br>import java.lang.annotation.*;<br>import java.lang.reflect.*;<br> <br>public class AnnotationTest {<br> <br> public static void main(String[] args) {<br> Class recordC = null;<br> try {<br> recordC = Class.forName("Record");<br> } catch (ClassNotFoundException e) {<br> e.printStackTrace();<br> }<br> <br> System.out.println("------ 构造方法的描述如下 ------");<br> Constructor[] declaredConstructors = recordC.getDeclaredConstructors(); // 获得所有构造方法<br> for (int i = 0; i < declaredConstructors.length; i++) {<br> Constructor constructor = declaredConstructors[i]; // 遍历构造方法<br> // 查看是否具有指定类型的注释<br> if (constructor.isAnnotationPresent(Constructor_Annotation.class)) {<br> // 获得指定类型的注释<br> Constructor_Annotation ca = (Constructor_Annotation) constructor<br> .getAnnotation(Constructor_Annotation.class);<br> System.out.println(ca.value()); // 获得注释信息<br> }<br> Annotation[][] parameterAnnotations = constructor.getParameterAnnotations(); // 获得参数的注释<br> for (int j = 0; j < parameterAnnotations.length; j++) {<br> // 获得指定参数注释的长度<br> int length = parameterAnnotations[j].length;<br> if (length == 0) // 如果长度为0则表示没有为该参数添加注释<br> System.out.println(" 未添加Annotation的参数");<br> else<br> for (int k = 0; k < length; k++) {<br> // 获得参数的注释<br> Field_Method_Parameter_Annotation pa = (Field_Method_Parameter_Annotation) parameterAnnotations[j][k];<br> System.out.print(" " + pa.describe()); // 获得参数描述<br> System.out.println(" " + pa.type()); // 获得参数类型<br> }<br> }<br> System.out.println();<br> }<br> System.out.println();<br> <br> System.out.println("-------- 字段的描述如下 --------");<br> <br> Field[] declaredFields = recordC.getDeclaredFields(); // 获得所有字段<br> for (int i = 0; i < declaredFields.length; i++) {<br> Field field = declaredFields[i]; // 遍历字段<br> // 查看是否具有指定类型的注释<br> if (field.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) {<br> // 获得指定类型的注释<br> Field_Method_Parameter_Annotation fa = field.getAnnotation(Field_Method_Parameter_Annotation.class);<br> System.out.print(" " + fa.describe()); // 获得字段的描述<br> System.out.println(" " + fa.type()); // 获得字段的类型<br> }<br> }<br> <br> System.out.println();<br> <br> System.out.println("-------- 方法的描述如下 --------");<br> <br> Method[] methods = recordC.getDeclaredMethods(); // 获得所有方法<br> for (int i = 0; i < methods.length; i++) {<br> Method method = methods[i]; // 遍历方法<br> // 查看是否具有指定类型的注释<br> if (method.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) {<br> // 获得指定类型的注释<br> Field_Method_Parameter_Annotation ma = method.getAnnotation(Field_Method_Parameter_Annotation.class);<br> System.out.println(ma.describe()); // 获得方法的描述<br> System.out.println(ma.type()); // 获得方法的返回值类型<br> }<br> Annotation[][] parameterAnnotations = method.getParameterAnnotations(); // 获得参数的注释<br> for (int j = 0; j < parameterAnnotations.length; j++) {<br> int length = parameterAnnotations[j].length; // 获得指定参数注释的长度<br> if (length == 0) // 如果长度为0表示没有为该参数添加注释<br> System.out.println(" 未添加Annotation的参数");<br> else<br> for (int k = 0; k < length; k++) {<br> // 获得指定类型的注释<br> Field_Method_Parameter_Annotation pa = (Field_Method_Parameter_Annotation) parameterAnnotations[j][k];<br> System.out.print(" " + pa.describe()); // 获得参数的描述<br> System.out.println(" " + pa.type()); // 获得参数的类型<br> }<br> }<br> System.out.println();<br> }<br> }<br>}<br>//例题16.5</b>
结果为:
数据库操作
第一步
打开“命令提示符”,用管理员身份运行
第二步
登录MySQL<br>
第三步
创建库和表<br>
第四步
使用Java命令查询数据库操作<br>
第五步
右击——点击“Build Path”——选择第四个——找到包的位置——导入成功
第六步
创建java项目连接数据库<br>1.注册驱动<br><br><br>2.获取链接<br><br><br>3.获取statment对象 <br><br>4.执行sql语句返回结果集 <br><br><br>5.遍历结果集 <br><br><br>6.关闭连接释放资源:java存在自动回收资源,不关闭会占空间 <br>
java绘图
java绘图类
Graphics类
Grapics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。<br><br> Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、钜形、多边形、椭面、圆弧等形状和文本、图片的绘制操作。另外,在执行这些操作之前,还可以使用相应的方法设置给图的颜色和字体等状态属性。
Graphics2D类
使用Graphics 类可以完成简单的图形绘制任务,但是它所实现的功能非常有限,如无法改变线条的粗细、不能对图片使用旋转和模糊等过滤效果。<br><br> Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由子Graphies2D类是Graphics 类的扩展,也是推荐使用的Java 绘图类。<br>
绘制图形
Java 可以分别使用Graphics 类和 Graphics2D 类绘制图形,Graphics类使用不同的方法实现不同图形的给制。例如,drawLine0方法可以绘制直线,drawRectO方法用于绘制矩形,drawOval0方法用于绘制椭圓形等。
Graphics2D类是在继承Graphics 类的基础上编写的,它包含了Graphics类的绘图方法并添加了更强的功能,在创建绘图类时推荐使用该类。Graphics2D类可以分别使用不同的类来表示不同的形状,Line2D类、Rectangle2D类等。<br><br> 要绘制指定形状的图形,需要先创建并初始化该图形类的对象,且这些图形类必须是Shape接口药实现类;然后使用Graphics2D类的draw0方法绘制该图形对象,或者使用610方法填充该图形对象。
java.awt.geom 包中提供了如下常用的图形类,这些图形类都实现了Shape 接口:<br><br>Arc2D类<br>CubicCurve2D类<br>Ellipse2D类<br>Line2D类<br>Point2D类<br>QuadCurve2D类<br>Rectangle2D类<br>RoundRectangle2D类
颜色与画笔
设置颜色
使用Color 类可以创建任意颜色的对象,不用担心平台是否支持该颜色,因为Java以跨平台和与硬件无关的方式支持颜色管理。创建Color 对象的构造方法有如下两种:<br><br><font color="#e74f4c">Color col = new Color(int r, int g, int b)<br><br>Color col = new Color(int rgb</font>
设置画笔
默认情况下,Graphics 类使用的画笔属性是粗细为1个像素的正方形,而Graphics2D类可以调用setStrokeO方法设置画笔的属性,如改变线条的粗细、虚实,定义线段端点的形状、风格等。
语法格式如下:<br><br><font color="#e74f4c">setStroke(Stroke stroke)</font>
其中,参数stroke是Stroke 接口的实现类对象。
etStroke0方法必须接受一个 Stroke 接口的实现类对象作参数,java.awrt包中提供了BasisSrke类它实现了Stroke接口,并且通过不同的构造方法创建画笔属性不同的对象。这些构造方法如下:<br><br><font color="#e74f4c"> BasicStroke()<br>BasicStroke(float width)<br>BasicStroke(float width, int cap, int join)<br>BasicStroke(float width, int cap, int join, float miterlimit)<br>BasicStroke(float width, int cap, int join, float miterlimit, float[] dash, float dash_phase)</font>
绘制文本
设置字体
Java 使用Font 类封装了字体的大小、样式等属性,该类在java.awt包中定义,其构造方法可以指定字体的名称、大小和样式3个属性。
语法如下:<br><br><font color="#e74f4c">Font(String name, int style, int size)</font>
设置绘图类的字体可以使用绘图类的setFontO方法。设置字体以后在图形上下文中绘制的所有文字都使用该字体,除非再次设置其他字体。<br>语法如下:<br><br><font color="#e74f4c">setFont(Font font)</font>
显示文字
Graphics2D类提供了drawString0方法,使用该方法可以实现图形上下文的文本绘制,从而实现在图片上显示文字的功能。
语法格式有如下两种:<br><br><font color="#e74f4c">drawString(String str, int x, int y)<br>drawString(String str, float x, float y)</font>
显示及处理图片
显示图片
绘图类不仅可以绘制图形和文本,还可以使用drawImageO方法将图片资源显示到绘图上下文中,而且可以实现各种特效处理,如图片的缩放、翻转等。有关图像处理的知识将在19.6节讲解,本节主要讲解如何显示图片。
语法如下:<br><br><font color="#e74f4c">drawimage(lmage img, int x, int y, ImageObserver observer)</font>
缩放
在显示图片时,使用了drawImageO方法将图片以原始大小显示在窗体中,要想实现图片的放大与缩小,则需要使用它的重载方法。
语法如下:<br><br><font color="#e74f4c">drawlmage(lmage img, int x, int y, int width, int height, ImageObserver observer)</font>
翻转
图像的翻转需要使用drawImage()方法的另一个重载方法。
语法如下:<br><br><font color="#e74f4c">drawimage(lmage img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)</font>
此方法总是用非缩放的图像来呈现缩放的矩形,并动态地执行所需的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。方法中涉及的参数说明如表所示
旋转
图像旋转需要调用Graphics2D类的rotateO方法,该方法将根据指定的弧度旋转图像。
语法如下:<br><br><font color="#e74f4c">rotate(double theta)</font>
倾斜
可以使用Graphics2D类提供的shearO方法设置绘图的倾斜方向,从而使图像实现倾斜的效果。
语法如下:<br><br><font color="#e74f4c">shear(double shx, double shy)</font>
多线程
创建线程
继承Thread类
Thread 类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。
Thread类中常用的两个构造方法如下:<br><br><font color="#e74f4c">public Thread():创建一个新的线程对象。<br>public Thread(String threadName):创建一个名称为threadName的线程对象。</font>
继承Thread类创建一个新的线程的语法如下:<br><br><font color="#e74f4c">public class ThreadTest extends Threadf {}</font>
完成线程真正功能的代码放在类的run0方法中,当一个类继承Thread类后,就可以在该类中覆盖run0方法,将实现该线程功能的代码写入runO方法中,然后调用 Thread类中的start0方法执行线程也就是调用run0方法。
run0方法必须使用以下语法格式:<br><br><font color="#e74f4c">public void run() {<br><br>}</font>
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由Java 虚拟机负责,程序员负责启动自己的线程。
代码如下:<br><br><font color="#e74f4c">public static void main(String[] args){<br><br> new ThreadTest().start();<br><br>}</font>
实现Runnad接口
实现Runnable接口的语法如下:<br><br><font color="#e74f4c">public class Thread extends Object implements Runnable</font>
实现Runnable 接口的程序会创建一个Thread对象,并将 Runnable 对象与Thread对象相关联。
Thread类中有以下两个构造方法:<br><font color="#e74f4c"><br>public Thread(Runnable target)<br>public Thread(Runnable target,String name)<br></font>这两个构造方法的参数中都存在Runnable 实例,使用以上构造方法就可以将Runnable实例与Thread实例相关联。
使用Runnable 接口启动新的线程的步骤如下:<br><br><font color="#e74f4c">建立Runnable对象<br>使用参数为Runnable对象的构造方法创建Thread实例<br>调用startO方法启动线程</font>
操作线程
休眠
一种能控制线程行为的方法是调用sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。
sleep()方法语法如下:<br><br><font color="#e74f4c">try{<br><br> Thread.sleep(2000);<br><br>}catch(InterruptedException e){<br><br> e.printStackTrace(();<br><br>}</font>
加入
当某一个线程使用join()方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行
<b>例题<br>import java.awt.BorderLayout;<br> <br>import javax.swing.*;<br> <br>public class JionTest extends JFrame{<br> private Thread threadA; //定义两个线程<br> private Thread threadB;<br> private JProgressBar progressBar = new JProgressBar(); //定义两个进度条组件<br> private JProgressBar progressBar2 = new JProgressBar();<br> public static void main(String[] args) {<br> JionTest test = new JionTest();<br> test.setVisible(true);<br> <br> }<br> private JionTest() {<br> setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br> setBounds(200,200,200,100);<br> getContentPane().add(progressBar,BorderLayout.NORTH); //将进度条设置在窗体最北面<br> getContentPane().add(progressBar2,BorderLayout.SOUTH); //将进度条设置在窗体最南面<br> progressBar.setStringPainted(true); //设置进度条显示数字字符<br> progressBar2.setStringPainted(true);<br> threadA = new Thread(new Runnable() { //使匿名内部类形式初始化Thread实例<br> int count = 0;<br> public void run() { //重写run()方法<br> while (true) {<br> progressBar.setValue(++count); //设置进度条的当前值<br> try {<br> Thread.sleep(100); //使线程A休眠100毫秒<br> threadB.join(); //使线程B调用join()方法<br> }catch(InterruptedException e) {<br> e.printStackTrace();<br> }<br> }<br> }<br> });<br> threadA.start(); //启动线程A<br> threadB = new Thread(new Runnable() {<br> int count = 0;<br> public void run() {<br> while (true) {<br> progressBar2.setValue(++count); //设置进度条的当前值<br> try {<br> Thread.sleep(100); //使线程B休眠100毫秒<br> threadB.join();<br> }catch(InterruptedException e) {<br> e.printStackTrace();<br> }<br> if(count==100) //当count变量增长为100时<br> break; //跳出循环<br> }<br> }<br> });<br> threadB.start(); //启动线程B<br> }<br>}//例题20.4</b><br>
结果如下
中断
以往有的时候会使用stop()方法停止线程,但当前版本的JDK早己废除了stop()方法,不建议使用stop()方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。<br><br>如果线程是因为使用了slcep()或wait()方法进入了就绪状态,可以使用Thread 类中 interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while循环。
下面的实例演示了某个线程使用interrupted()方法,同时程序抛出了InterruptedException异常,在异常处理时结束了while 循环。在项目中,经常在这里执行关闭数据库连接和关闭Socket连接等操作。
<b>import java.awt.BorderLayout;<br>import java.awt.event.*;<br> <br>import javax.swing.*;<br> <br>public class InterruptedSwing extends JFrame{<br> private InterruptedSwing() {<br> JProgressBar progressBar = new JProgressBar(); //创建进度条<br> getContentPane().add(progressBar,BorderLayout.NORTH); //讲进度条放置在窗体合适位置<br> JButton button= new JButton("停止");<br> getContentPane().add(button,BorderLayout.SOUTH);<br> progressBar.setStringPainted(true); //设置进度条上显示数字<br> Thread t = new Thread(new Runnable() { <br> int count = 0;<br> <br> public void run() { <br> while (true) {<br> progressBar.setValue(++count); //设置进度条的当前值<br> try {<br> Thread.sleep(100); //使线程A休眠100毫秒 <br> }catch(InterruptedException e) { //捕捉InterruptedException异常<br> System.out.println("当前线程序被中断");<br> break;<br> }<br> }<br> }<br> });<br> <br> button.addActionListener(new ActionListener() {<br> <br> @Override<br> public void actionPerformed(ActionEvent e) {<br> t.interrupt(); //中断线程<br> }<br> });<br> t.start(); //启动线程<br> }<br> <br> public static void init(JFrame frame, int width, int height) {<br> frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br> frame.setSize(width, height);<br> frame.setVisible(true);<br> }<br> public static void main(String[] args){<br> init(new InterruptedSwing(), 100, 100);<br> }<br>}//例题20.5</b>
结果如下
礼让
Thread 类中提供了一种礼让方法,使用yield()方法表示,它只是给当前正处于运行状态的线程个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。<br><br>yield()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状体。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配CPU时间片来执行。
线程同步
线程安全
例如,在项目中创建ThreadSafeTest类,该类实现了Rummable接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能的代码如下:
<b><br>public class ThreadSafeTest implements Runnable{<br> int num = 10; //设置当前总票数<br> <br> public void run() {<br> while(true) { //设置无限循环<br> if(num>0) { //判断当前票数是否大于0<br> try {<br> Thread.sleep(100); //使当前线程休眠100秒<br> } catch(InterruptedException e) {<br> e.printStackTrace();<br> }<br> System.out.println(Thread.currentThread().getName()+"---票数"+num--); //票数减一<br> }<br> }<br>}<br> public static void main(String[]args) {<br> ThreadSafeTest t = new ThreadSafeTest(); //实例化类对象<br> Thread tA = new Thread(t,"线程一"); //以该类对象分别实例化4个线程<br> Thread tB= new Thread(t,"线程二");<br> Thread tC= new Thread(t,"线程三");<br> Thread tD= new Thread(t,"线程四");<br> tA.start(); //分别启动线程<br> tB.start();<br> tC.start();<br> tD.start();<br> }<br> }</b>
结果如下
同步机制
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用synchronized关键字,使用该关键字包含的代码块称为同步块,也称为临界区
语法如下:<br><br><font color="#e74f4c">synchronized(Object) {<br><br>}</font>
同步方法就是在方法前面用synchronized关键字修饰的方法
其语法如下:<br><br><font color="#e74f4c">synchronized void f(){}</font>
网络通信
网络基础概念
局域网与互联网
为了实现两台计算机的通信,必须用一个网络线路连接两台计算机。
网络协议
IP协议
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还没有投入使用。<br><br>TCP/IP 模式是一种层次结构,共分为4层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性<br>
TCP与UDP协议
TCP 协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送。TCP可以保证数据从一端送至连接的另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相同。因此,TCP协议适合可靠性要求比较高的场合。就像拨打电话,必须先拨号给对方,等两端确定连接后,相互才能听到对方说话,也知道对方回应的是什么。
UDP是无连接通信协议,不保证数据的可靠传输,但能够向若干个目标发送数据,或接收来自若干个源的数据。UDP以独立发送数据包的方式进行。这种方式就像邮递员送信给收信人,可以寄出很多信给同一个人,且每一封信都是相对独立的,各封信送达的顺序并不重要,收信人接收信件的顺序也不能保证与寄出信件的顺序相同。<br>
UDP 协议适合于一些对数据准确性要求不高,但对传输速度和时效性要求非常高的网站,如网络聊天室、在线影片等。这是由于TCP协议在认证上存在额外耗费,可能使传输速度减慢,而UDP协议即使有一小部分数据包遗失或传送顺序有所不同,也不会严重危害该项通信。
端口与套接字
一般而言,一台计算机只有单一的连到网络的物理连接(Physical Connection),所有的数据都通过此连接对内、对外送达特定的计算机,这就是端口。网络程序设计中的端口(port)并非真实的物理存在,而是一个假想的连接装置。端口被规定为一个在0~65535的整数。HTTP服务一般使用80端口,FTP 服务使用21端口。假如一台计算机提供了HTTP、FTP等多种服务,那么客户机会通过不同的端口来确定连接到服务器的哪项服务上,Java 将套接字抽象化为类,程序设计者只需创建Socket类对象,即可使用套接字。
TCP
InetAddress地址类
java.net包中的InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
ServerSocket服务器套接字类
ServerSocker 类的构造方法通常会抛出1OException异常,具体有以下几种形式:<br>ServerSocket():创建非绑定服务器套接字。<br>ServerSocket(int port):创建绑定到特定端口的服务器套接字。<br>ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字,并将其绑定到指定的本地端口号上。<br>ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于计算机上有多块网卡和多个I地址的情况,用户可以明确规定ServerSocket在哪块网卡或哪个IP地址上等待客户的连接请求。
TCP网络程序设计
<b><br> <br>import java.io.*;<br>import java.net.*;<br> <br>public class MyServer {<br> private ServerSocket server; // 服务器套接字<br> private Socket socket; // 客户端套接字<br> <br> void start() {// 启动服务器<br> try {<br> server = new ServerSocket(8998); // 服务器启用8998端口<br> System.out.println("服务器套接字已经创建成功");<br> while (true) {<br> System.out.println("等待客户端的连接");<br> socket = server.accept(); // 服务器监听客户端连接<br> // 根据套接字字节流创建字符输入流<br> BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));<br> while (true) {// 循环接受信息<br> String message = reader.readLine();// 读取一行文本<br> if ("exit".equals(message)) {// 如果客户端发来的内容为“exit”<br> System.out.println("客户端退出");<br> break;// 停止接受信息<br> }<br> System.out.println("客户端:" + message);<br> }<br> reader.close(); // 关闭流<br> socket.close(); // 关闭套接字<br> }<br> } catch (IOException e) {<br> e.printStackTrace();<br> }<br> }<br> <br> public static void main(String[] args) {<br> MyServer tcp = new MyServer();<br> tcp.start(); // 启动服务器<br> }<br>}<br>//21.2</b>
UDP
将数据打包(称为数据包),然后将数据包发往目的地。<br>接收别人发来的数据包,然后查看数据包。<br>发送数据包的步骤如下:
(1)使用DatagramSocketO创建一个数据包套接字。<br><br>(2)使用DatagramPacket(byte[] buf,int offset, int length,InetAddress address,int port)创建要发送的数据包。<br><br>(3)使用DatagramSocket 类的sendO方法发送数据包。
DatagramPacke数据包类
java.net 包的DatagramPacket 类用来表示数据包。
DatagramPacket 类的构造方法如下:<br><br>DatagramPacket(byte[] buf, int length)<br>DatagramPacket(bytel] buf, int length, InetAddress address, int port)<br>第一种构造方法在创建DatagramPacket 对象时,指定了数据包的内存空间和大小。<br><br>第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口
DatagramSocket套接字类
java.net 包中的()<br>DatagramSocket(int port)<br>DatagramSocket(int port, InetAddress addr)<br>第一种构造方法创建DatagramSocket对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。<br><br>第二种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到本地主机的指定端口上。<br><br>第三种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个I地址的情况。<br>
UDP网络程序设计
<b>广播主机程序不断地向外播放信息,代码如下:<br><br>import java.io.IOException;<br>import java.net.*;<br> <br>public class Notification extends Thread {<br> String weather = "节目预报:八点有大型晚会,请收听";// 发送的消息<br> int port = 9898; // 端口<br> InetAddress iaddress = null;<br> MulticastSocket socket = null; // 多点广播套接字<br> <br> Notification() {<br> try {<br> iaddress = InetAddress.getByName("224.255.10.0"); // 实例化InetAddress,指定地址<br> socket = new MulticastSocket(port); // 实例化多点广播套接字<br> socket.setTimeToLive(1); // 指定发送范围是本地网络<br> socket.joinGroup(iaddress); // 加入广播组<br> } catch (IOException e) {<br> e.printStackTrace(); // 输出异常信息<br> }<br> }<br> <br> public void run() {<br> while (true) {<br> DatagramPacket packet = null; // 数据包<br> byte data[] = weather.getBytes(); // 字符串消息的字节数组<br> packet = new DatagramPacket(data, data.length, iaddress, port); // 将数据打包<br> System.out.println(weather); // 控制台打印消息<br> try {<br> socket.send(packet); // 发送数据<br> sleep(3000); // 线程休眠<br> } catch (IOException e) {<br> e.printStackTrace(); <br> } catch (InterruptedException e) {<br> e.printStackTrace();<br> }<br> }<br> }<br> <br> public static void main(String[] args) { <br> Notification w = new Notification();<br> w.start(); // 启动线程<br> }<br>}<br>//21.3</b><br>
<b>接收广播程序。单机“开始接收”按钮,系统开始接收主机播出的信息;单机“停止接收”按钮,系统停止接收广播主机播出的信息。代码如下:<br><br>import java.awt.*;<br>import java.awt.event.*;<br>import java.io.IOException;<br>import java.net.*;<br>import javax.swing.*;<br> <br>public class Receive extends JFrame implements Runnable, ActionListener {<br> int port; // 端口<br> InetAddress group = null; // 广播组地址<br> MulticastSocket socket = null; // 多点广播套接字对象<br> JButton inceBtn = new JButton("开始接收");<br> JButton stopBtn = new JButton("停止接收");<br> JTextArea inceAr = new JTextArea(10, 10); // 显示接收广播的文本域<br> JTextArea inced = new JTextArea(10, 10);<br> Thread thread;<br> boolean stop = false; // 停止接受信息状态<br> <br> public Receive() {<br> setTitle("广播数据报");<br> setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);<br> thread = new Thread(this);<br> inceBtn.addActionListener(this); // 绑定按钮ince的单击事件<br> stopBtn.addActionListener(this); // 绑定按钮stop的单击事件<br> inceAr.setForeground(Color.blue); // 指定文本域中文字的颜色<br> JPanel north = new JPanel(); // 创建Jpanel对象<br> north.add(inceBtn); // 将按钮添加到面板north上<br> north.add(stopBtn);<br> add(north, BorderLayout.NORTH); // 将north放置在窗体的上部<br> JPanel center = new JPanel(); // 创建面板对象center<br> center.setLayout(new GridLayout(1, 2)); // 设置面板布局<br> center.add(inceAr); // 将文本域添加到面板上<br> center.add(inced);<br> add(center, BorderLayout.CENTER); // 设置面板布局<br> validate(); // 刷新<br> port = 9898; // 设置端口号<br> try {<br> group = InetAddress.getByName("224.255.10.0"); // 指定接收地址<br> socket = new MulticastSocket(port); // 绑定多点广播套接字<br> socket.joinGroup(group); // 加入广播组<br> } catch (IOException e) {<br> e.printStackTrace(); // 输出异常信息<br> }<br> setBounds(100, 50, 360, 380); // 设置布局<br> setVisible(true); // 将窗体设置为显示状态<br> }<br> <br> public void run() { // run()方法<br> while (!stop) {<br> byte data[] = new byte[1024]; // 创建缓存字节数组<br> DatagramPacket packet = null;<br> packet = new DatagramPacket(data, data.length, group, port); // 待接收的数据包<br> try {<br> socket.receive(packet); // 接收数据包<br> String message = new String(packet.getData(), 0, packet.getLength()); // 获取数据包中的内容<br> inceAr.setText("正在接收的内容:\n" + message); // 将接收内容显示在文本域中<br> inced.append(message + "\n"); // 每条信息为一行<br> } catch (IOException e) {<br> e.printStackTrace(); // 输出异常信息<br> }<br> }<br> }<br> <br> public void actionPerformed(ActionEvent e) { // 单击事件<br> if (e.getSource() == inceBtn) { // 单击按钮ince触发的事件<br> inceBtn.setBackground(Color.red); // 设置按钮颜色<br> stopBtn.setBackground(Color.yellow);<br> if (!(thread.isAlive())) { // 如线程不处于“新建状态”<br> thread = new Thread(this); // 实例化Thread对象<br> }<br> thread.start(); // 启动线程<br> stop = false; // 开始接受信息<br> }<br> if (e.getSource() == stopBtn) { // 单击按钮stop触发的事件<br> inceBtn.setBackground(Color.yellow); // 设置按钮颜色<br> stopBtn.setBackground(Color.red);<br> stop = true; // 停止接受信息<br> }<br> }<br> <br> public static void main(String[] args) {<br> Receive rec = new Receive();<br> rec.setSize(460, 200);<br> }<br>}</b><br>
接收数据包的步骤如下:
(1)使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口。<br><br> (2)使用 DatagramPacket(byte buf, int length)创建字节数组来接收数据包。<br><br>(3)使用DatagramPacket 类的receive0方法接收UDP包。
收藏
立即使用
收藏
立即使用
Collect
Get Started
Collect
Get Started
Collect
Get Started
Collect
Get Started
评论
0 条评论
下一页