Java从入门到精通 2
2023-12-19 11:47:21 0 举报
AI智能生成
登录查看完整内容
Java从入门到精通 2
作者其他创作
大纲/内容
Collection接口是层次结构中的跟接口,构成Collection的单位称为元素。Collection接口接口通常不能直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。
Collection接口的常用方法 方法 功能描述add(E e) 将指定的对象添加到该集合中remove(Object o) 将指定的对象从该集合中移除iterator() 返回在此Collection的元素上进行迭代器。用于遍历集合的对象isEmpty() 返回Boolean值,用于判断当前集合是否为空size() 返回int型值,获取该集合中元素的个数
Collection 接口
实现了可变的数组,允许保存所有元素,包括 null。并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或删除对象的速度较慢。
ArrayList 类
采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合中插入、删除对象时,使用 LinkedList 类实现的 List 集合的效率较高;但对于随机访问集合中的对象,使用 LinkedList 类实现 List 集合的效率低。
LinkedList 类
List 集合
实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 Set 集合的迭代顺序,特别是它不保证改顺序永久不变。此类允许使用 null 元素。
HashSet 类
采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合中插入、删除对象时,使用LinkedList类实现List集合的效率较低。
ThreeSet 类
Set 集合
基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。HashMap类通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap 类
不仅实现了Map接口,还实现了java.util.SortedMap接口,因此集合中的映射关系具有一定的顺序。但是添加、删除和定位映射关系时,TreeMap类比HashMap类性能稍等。由于TreeMap类实现的Map集合中的映射关系是根据建对象按照一定的顺序排列,因此不允许键对象是null。
TreeMap 类
Map集合没有继承Collection接口,其提供的是key到value的映射。Map集合中不能包含相同的key,每个key只能映射一个value。key还决定了存储对象在映射中的存储位置,但不是由key对象本身决定的。
Map 集合
第12章 集合类
枚举类型实例,该方法将枚举中所有的枚举值以数组的形式返回。
values() 方法
枚举类型中的静态方法 valuesOf() 可以将普通字符串转换为枚举类型,而 comparedTo() 方法用于比较两个枚举类型对象定义时的顺序。
valuesOf() 方法与 compareTo() 方法
枚举类型中的 ordinal() 方法用于获取某个枚举对象的位置索引值。
ordinal() 方法
在枚举类型中,可以添加构造方法,但是规定这个构造方法必须被 private 修饰符所修饰。
枚举类型中的构造方法
枚举类型声明提供了一种对用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结枚举类型,它具有以下特点: 类型安全。 紧凑有效的数据定义。 可以和程序其他部分完美交互。 运行效率高。
枚举类型
Object类最上层的父类,很多程序员为了使用更为通用,设计程序时通常使传入的值与返回的值都以Object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在运行时将会发生ClassCastException异常。为了提前预防这种问题,Java提供了泛型机制。语法如下: 类名.<T>
定义泛型类
泛型的常规用法
泛型的高级用法
泛型
第13章 枚举于泛型
lambda 表达式可以用非常少的代码实现抽象方法。lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数接口的对象。可以将lambda表达式语法用法如下:(方法参数) -> {方法体}这个方法 按照 这样的代码来实现语法格式如下:()->{代码块} 参数 ->{代码块} (参数1,参数2,...,参数n)->{代码块 }
lambda 表达式实现函数式接口
lambda 表达式除了可以调用定义好的参数,还可以调用表达式以外的变量。但是这些外部的变量有些可以被更改,有些则不能。例如,lambda 表达式无法更改局部变量的值,但是却可以更改外部类的成员变量(也可叫做类属性)的值。1、lambda 表达式无法更改局部变量 局部变量在lambda 表达式中默认被定义为final(静态)的,也就是说,lambda 表达式只能调用局部变量,却不能改变值。 2、 lambda 表达式可以更改类成员变量 类成员变量是在lambda 表达式中不是被final修饰的,所以lambda 表达式可以改变其值。
lambda 表达式调用外部变量
很多接口的抽象方法为保证程序的安全性,会在定义时就抛出异常。但是lambda 表达式中并没有抛出异常的语法,这是因为lambda 表达式会默认抛出抽象方法原有的异常,当此方法被调用时则需要进行异常处理。
lambda 表达式与异常处理
lambda 表达式
引用静态方法引用静态方法的语法如下:类名 : : 静态方法名
引用成员方法引用成员方法的语法如下:对象名 : : 成员方法名
引用构造方法1、引用无参数构造方法引用无参数构造方法的方法如下:类名 : : new 2、 引用有参数构造方法引用有参构造方法的语法与引用无构造方法一样。区别就是函数式接口的抽象方法是有参数的。
方法的引用
流处理有点类似数据库的SQL语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一的缺点是代码可读性不高,如果开发者基础不好,可能会看到API所表达的含义。
流处理的接口都定义在 java.uil.stream 包下。BaseStream 接口是最基础的接口,但最常见的是BaseStream 接口的一个子接口——Stream接口,基本上绝大多数的流处理都是在Stream 接口实现的。Stream 接口是泛型接口,所有流中操作的元素可以是任何的对象。因为所有集合类都是Collection接口的子类,如ArrayList类,HashSet类等,所有这些都可以进行流处理。例如:List<Integer>list=new ArrayList<Interger>(); //创建集合Stream<Integer> s=list.stream(); //获取集合流对象
Stream 接口
Collectors 类为收集器类,该类实现了 java.util.Collector 接口,提供了非常丰富的 API,有着强大的数据挖掘能力,也可以将 Stream 流处理进行各种各样的封装、归类、分组等操作。同时,Collectors 类还提供了很多实用的数据加工方法,如数据统计计算等。
Collectors 类
数据过滤就是在杂乱的数据中筛选出需要的数据,类似 SQL 语句中的 WHERE 关键字,给出一定的条件,将符合条件的数据过滤并展示出来。
filter() 方法 filter() 方法是Stream 接口提供的过滤方法。该方法可以将 lambda 表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需要 Stream 提供的 collect()方法按照指定方法重新封装。
distinct()方法 distinct()方法是 Stream 接口提供的过滤方法。该方法可以去除流中的重复元素,效果与 SQL 语句中的 DISTINCT 关键字一样。
limit()方法 limit()方法是 Stream 接口提供的方法,该方法可以获取流中前 N 个元素。
skip () 方法 skip () 方法是 Stream 接口提供的方法,该方法可以忽略流中的前 N 个元素。
数据过滤
数据的映射和过滤概念不同:过滤是在流中找到符合条件的元素,映射是在流中获得具体的数据 。Stream 接口提供了 map() 方法用来实现数据映射,map () 方法会按照参数中的函数逻辑获取新的流对象,新的流对象中元素类型可能与旧流对象元素类型不相同。
数据映射
allMatch()方法 allMatch()方法是 Stream 接口提供的方法,该方法会判断流中的元素是否全部符合某一条件,返回结果是 boolean 值。如果所有元素都符合条件则返回 true,否则返回 false。
anyMatch() 方法 anyMatch() 方法是 Stream 接口提供的方法,该方法会判断流中的元素是否有符合某条件,只要有一个元素符合条件就返回 true,如果没有元素符合条件才会返回 false。
noneMatch() 方法 noneMatch() 方法是 Stream 接口提供的方法,给方法会判断流中的所有元素是否都不符合某一条件。这个方法的逻辑和 allMatch() 方法正好相反。
findFirst()方法 findFirst()方法是 Stream 接口提供的方法,这个方法会返回符合条件的第一个元素。
数据查找
1、数据统计 数据统计不仅不可以筛选出特殊元素,还可以对元素的属性进行统计计算。这种复杂的统计操作不是由 Stream 实现的,而是由 Collectors 收集器类实现的,收集器提供了非常的API,有着其强大的数据挖掘能力。2、数据分组 数据分组就是将流中元素按照指定的条件分开保存,类似 SQL 语言中的 “GROUP BY” 关键字。分组之后的数据会按照不同标签分别保存成一个集合,然后按照 “键—值” 关系封装在 Map 对象中。
数据收集
流处理
第14章 lambda表达式
InputStream 类是字节输入的抽象类,它是所有字节输入流的父类,该类中所有方法遇到错误时都会引发 IOException 异常。read()方法:从输入流中读取数据的下一个字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值为-1。read(byte[] b)方法:从输入流中读入一定的长度个字节,并以整数的形式返回字节数。mark(int readlimit)方法:在输入流的当前位置放置一个标记,readlimit 参数告知此输入流在标记位置失败之前允许读取的字节数。reset()方法:将输入指针返回到当前所做的标记处。skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。markSupported()方法:如果当前流支持 mark()/reset()操作就返回true。close()方法:关闭此输入流并释放与该流关联的所有系统资源。 Java中的字符是 Unicode 编码,是双字节的。 InputStream 类是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供一套单独的类,即 Reader 类,但 Reader 并不是 InputStream 类的替换者,只是在处理字符串时简化了编程。Reader 类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。Reader 类的方法与 InputStream中的方法类似。
输入流
输出流
输入/输出流
File 类
程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存文件中。
FileInputStream 类与 FileOutputStream 类 FileInputStream 类与 FileOutputStream 类 都用来操磁盘文件。如果用户的文件读取要求比较简单,则可以使用 FileInputStream 类,该类继承自 InputStream 类。FileOutputStream 类是 OutputStream 类的子类。 FileInputStream 类常用的构造方法:FileInputStream(String name)FileInputStream(File file)
FileReader 和FileWriter 类 使用 FileOutputStream 类向文件中写入数据与使用 FileInputStream 类丛文件中将内容读出来,都存在一点不足,即这两个类都只提供了对字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流 FileReader 类或 FileWriter 类即可避免这种现象。 FileReader 类和 FileWriter 类对应了 FileInputStream 类和 FileOutputStream 类。FileReader 类顺序地读取文件,只要不关闭流,每次调用 read() 方法就顺序地读取源中其余的内容,直接源的末尾或流被关闭。
文件输出/输入流
缓存时 I/O 的一种性能优化。缓存流为 I/O 流增加了内存缓存区,使得再流上执行 skip()、mark()、和 reset()方法成为可能。
带缓存的输入/输出流
数据输入/输出流 (DataInputStream 类与 DataOutputStream 类)允许应用程序以与机器无关的方式从底层输入流中读取基本 Java 数据类型。也就是说,当读取一个数据时,不必关心这个数值应当是哪个字节。 DataInputStream 类提供了将字符串、double 数据、int 数据、Boolean 数据写入文件的方法;DataOutputStream 类只提供了一个readUTF()方法返回字符串。 DataInputStream 类与 DataOutputStream 类的构造方法:DataInputStream(DataInputStream in):使用指定的基础 InputStream 对象创建一个 DataInputStream 对象。DataOutputStream(DataOutputStream out):创建一个新的数据输出流,将数据写入一个指定基础输出流。
数据输入/输出流
第15章 I/O(输入/输出)
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。Java反射机制的功能十分强大,在java.lang.reflect包中提供了对该功能的支持。
在通过下列一组方法访问构造方法时,将返回 Constructor 类型的对象或数组。每个Constructor 对象代表一个构造方法。
访问构造方法
在通过下列一组方法去访问成员变量时,将返回 Field 类型的对象或数组。
访问成员变量
在通过下列一组方法访问成员方法时,将返回 Method 类型的对象或数组。
访问成员方法
反射
在定义 Annotation 类型时,也需要用到用来定义接口的 interface 关键字,但需要在 interface字前加一个 “@” 符合,即定义 Annotation 类型的关键字为 @interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。
定义 Annotation 类型
如果在定义 Annotation 类型时将@RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的 Annotation 信息,如获取构造方法、字段和方法的 Annotation 信息。
访问 Annotation 信息
Java提供了 Annotation 注解功能 ,该功能可用于类、构造方法、成员变量、成员方法、参数等的声明中。该功能不影响程序的运行,但是会对编译器警告等辅助工具产生影响。
Annotation 注解
第16章 反射与注解
//第一步注册驱动 DriverManager.registerDriver(new Driver());
第一步:注册驱动
//第二步:获取连接 connection=DriverManager.getConnection( \"jdbc:mysql://localhost:3306/school_java\
第二步:获取连接
//第三步:获取statement对象 PreparedStatement preparedStatement= connection.prepareStatement(\"select * from couse;\");
第三步:获取 statement 对象
//第四步: 执行SQL语句返回结果集 ResultSet resultSet=preparedStatement.executeQuery();
第四步:执行 SQL 语句返回结果
//第五步:遍历结果集 while(resultSet.next()) { System.out.print(resultSet.getInt(\"id\")+\" \"); System.out.println(resultSet.getString(\"name\")); }
第五步:遍历结果集
//第六步:关闭连接释放资源 resultSet.close(); preparedStatement.close(); }
第六步:关闭连接释放资源
1、select 语句select 语句用于从数据中检索数据。语法如下:SELECT 搜选字段列表 FROM 数据表名WHERE 条件表达式 GROUP BY 字段名 HAVING 条件表达式(指定分组的条件)ORDER BY 字段名[ASC|DESC]2、insert 语句insert 语句用于向表中插入新数据。语法如下:insert into 表名[(字段1,字段2...)]values(属性值1,属性值2); 3、update 语句update 语句用于更新数据表中的某些记录。语法如下:UPDATE 数据表名 SET 字段名=新的字段值 WHERE 条件表达式; 4、delete 语句delete 语句用于删除数据。语法如下:delete from 数据表名 where 条件表达式;
SQL 语句
1、 DriverManager 类 DriverManager 类师JDBC的管理层,用于管理数据库中的驱动程序。在操作指定数据库之前,需要使用Java中Class 类的静态方法forName(String className)加载指定数据库的驱动程序。2、Connection 接口 Connection 接口代表与特定的数据库的连接,在连接上下文中执行SOL语句并返回结果。3、Statement 接口 Statement 接口用于在已经建立连接的基础上向数据库发送SQL语句。4、PreparedStatement 接口 PreparedStatement 接口用来动态地执行SQL语句。通过PreparedStatement 实例执行的动态的SQL语句,将被预编译并能保存到PreparedStatement 实例中,从而可以反复地执行该SQL语句。5、ResultSet 接口 ResultSet 接口类似与一个临时表,用来展示存放数据库查询操作所获得的结果。ResultSet 实例具有指定当前数据行的指针,指针开始的位置在第一个记录的前面,通常next()方法可将指针向下移。
JBDC常用的类和接口
第17章 数据库操作
JFrame 类的常用构造方法包括以下两种形式:public JFrame(): 创建一个初始不可见、没有标题的窗体。public JFrame(String title): 创建一个不可见、具体标题的窗体。 在创建窗体后,先调用 getContentPane() 方法将窗体转换为容器,再调用 add() 方法或者 remove() 方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:JButton okButn=new JButton(\"确定 \
JFrame 窗体
JDialog 对话框继承了 java.awt.Dialog 类,其功能是从一个窗体中弹出另一个窗体,如使用 IE 浏览器时弹出的确定对话框。JDialog 对话框与JFrame 窗体类似,被使用时也需 getContentPane() 方法把 JDialog 对话框转换为容器,再对 JDialog 对话框进行设置。
JDialog 对话框
1、自定义对话框 2、确认框 3、输入框
JOptionPane 小型对话框
Swing 常用窗体
null 绝对布局
流布局(FlowLayout)管理器是 Swing 中最基本的布局管理器。使用流布局管理器摆放组件时,组件被从左到右摆放。当组件占据了当前的所有空间时,溢出的组件会被移动到当前的下一行。默认情况下,行组件的排列方式会被指定为居中对齐,但是通过设置可以更改每一行组件的排序方式。
FlowLayout 流布局管理器
使用 Swing 创建窗体后,容器默认的布局管理器是边界布局(BorderLayout )管理器 ,边界布局把容量划分为东、南、西、北、中5个区域,但组件被添加到设置为边界布局管理器的容器时,需要使用 BorderLayout 类中成员变量指定被添加的组件在边界布局管理器中的区域。
BorderLayout 边界布局管理器
网格布局(GridLayout)管理器能够把容器划分为网格,组件可以按行、列进行排序。在网格布局管理器中,网格的个数由行数和列数决定,且每个网格的小大都相同。改变窗体大小时,组件的大小也会随之改变。
GridLayout 网格布局管理器
常用布局管理器
JPanel 面板 继承 java.awt.Container 类。JPanel 面板必须放在窗体容器中使用,无法摆脱窗体显示。
JPanel 面板
JScrollPane 面板是带滚动条的面板,被用于在较小的窗体显示较大篇幅的内容。JScrollPane 滚动面板不能使用布局管理器,且只能容纳一个组件。如果需要向 JScrollPane 面板中添加多个组件,那么需要先将多个组件添加到 JPanel 面板,再将 JPanel 面板添加到JScrollPane 滚动面板。
JScrollPane 滚动面板
常用面板
标签(JLabel)的父类是 JComponent 类。虽然标签不能被添加监听器,但是标签显示的文本、图表等内容可以把被指定对齐方式。通过 JLabel 类的构造方法,可以创建多种标签,如显示只有文本标签、只有图标的标签以及同时包含文本和图标的标签等。
JLabel 标签
在 Swing 程序设计中,图标经常被添加到标签、按钮等组件,使用 javax.swing.ImageIcon 类可以依据现有的图片创建图标。ImageIcon 类实现了 Icon 接口,它有多个构造方法。
图标的使用
文字标签组件与图标
JButton 按钮
Swing单选按钮由JRadioButton对象表示,在swing程序设计中,需要把多个单选按钮添加到按钮组,当用户选中某个单选按钮时,按钮组中的其他单选按钮将不能被同时选中。
JRadioButton 单选按钮
复选框组件由 JCheckBox 对象表示,以单选按钮不同的是,窗体中的复选框可以被选中多个,这是因为每一个复选框都提供了“被选中”和“不被选中”两种状态。
JCheckBox 复选框
按钮组件
初次使用下拉列表框时,会感觉swing中的下拉列表框以WINDOWS操作系统中的下拉列表框有一些相似,实质上两者并不完全相同,因为swing中的下拉列表框不仅可以供用户从中选择列表项,也提供编辑列表项的功能。 下拉列表框是一个条状的显示区,它具有下拉功能,在下拉列表框的右侧存在一个倒三角的按钮,当用户单机该按钮时,下拉列表框中的项目将会一列表形式显示出来。 下拉列表框组件由 JComboBox 对象表示,JComboBox 类是 javax.swing.JComponent 类的子类。
JComboBox 下拉列表框
列表框组件被添加到窗体中后,就会被指定长和宽。如果列表框的大小不足以容纳列表项的个数,那么需要设置列表框具有滚动效果,即把列表框添加到滚动面板。列表框组件由 JList 对象表示,JList 类的常用构造方法如下:public void JList():创建一个空的 JList 对象。public void JList(Object [ ] listData):创建一个显示指定数组中的元素的 JList 对象。public void JList(Vector listData):创建一个显示指定 Vector 中的元素的 JList 对象。public void JList(ListModel dataModel):创建显示指定的非 null 模型的元素的 JLIst 对象。
JList 列表框
列表组件
JTextField 文本框
JPasswordField 密码框
JTextArea 文本域
文本组件
JTable 类除了提供了默认的构造方法外,还提供了被用于显示二维数组中的元素的构造方法。这个构造方法的语法如下:JTanle(Object[][]rowDate,Object[]columnNames)rowDate存储表格数据的二维数组columnNames,存储表格列明的一维数组在使用表格时,要先把表格添加到滚动面板,再把滚动面板添加到窗体的相应位置 .
创建表格
DefaultTableModel 表格数据模型
表格中的数据内容需要用于维护,使用 getValueAt()方法获得表格中某一个单元格的值,使用 addRow()方法向表格中添加新的行,使用 setValueAt() 方法修改表格中某一个单元格的值,使用 removeRow 方法从表格中删除指定行等。 当删除表格模型中的指定行时,每删除一行,其后所有行的索引值将相应地减 1,所以当连续删除多行时,需要注意对删除行索引的处理。
维护表格模型
表格组件
动作事件(ActionEvent)监听器是 Swing 中比较常用的事件监听器,很多组件的动作都会使用它监听,如按钮被单机击等。
ActionEvent 动作事件
当向文本框中输入内容时,将发生键盘事件 。KeyEvent 类负责捕获键盘事件,可以通过为组件添加实现了KeyListener 接口的监听器类来处理相应的键盘事件。
KeyEvent 键盘事件
所有组件都能发生鼠标事件,MouseEvent 类负责捕获鼠标事件,可以通过为组件添加实现了MouseListener 接口的监听器类来处理相应的鼠标事件。
MouseEvent 鼠标事件
事件监听器
第18章 Swing 程序设计
Graphics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。 Graphics 类封装了 Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。 Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、矩形、多边形、椭圆、弧形等形状和文本、图形的绘制操作。另外,在执行操作之前,还可以使用相应的方法设置绘图的颜色和字体等状态属性。
Graphics 类
使用 Graphics 类可以完成简单的图像绘制任务,但是它所有实现的功能非常有限,如无法改变线条的粗线、不能对图片使用旋转和模糊等过滤效果。 Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由于Graphics2D 类是Graphics 类的扩展,也是推荐使用的 Java 绘图类。
Graphics 2D类
Java 绘图类
Java可以分为使用 Graphics 类和 Graphics2D 类绘制图形,Graphics 类使用不同的方法实现不同图形的绘制。
绘制图形
使用 Color 类可以创建任意颜色的对象,不用担心平台是否支持改颜色,因为 Java 以跨平台和与硬件无关的方式支持颜色管理。
设置颜色
默认情况下,Graphics 类使用的画笔属性是粗细为1个像素的正方形,而 Graphics2D 类可以调用 setStroke() 方法设置属性,如果改变线条的粗细、虚实,定义线端点的形状、风格等。 setStroke() 方法必须接受一个Stroke 接口的实现类对象作参数,java.awt 包中提供了BasicStroke 类,它实行了了 Stroke 接口,并且通过不同的构造方法创建画笔不同对象。
设置画笔
绘图颜色与画笔属性
设置字体
显示文字
绘制文本
显示图片
放大与缩小
图像翻转
图像旋转需要调用 Graphics2D 类的 rotate()方法,该方法将根据指定的弧度旋转图像。语法如下:rotate(douuble theta)theta:旋转的弧度
图像旋转
图像倾斜
图片处理
第19章 Java绘图
Thread 类时 java.lang 包中的一个类,从类中实例化的对象代表线程,程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,start() 方法启动线程,该工作的功能被写在run() 方法中。
继承 Thread 类
线程都是通过扩展 Thread 类来创建的,如果程序员需要继承其他类(非Thread 类),而且还要是当前类实现多线程,那么可以通过 Runnable 接口来实现。 实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。使用 Runnable 接口启动新的线程的步骤:建立 Runnable 对象使用参数为 Runnable 对象的构造方法创建 Thread 实例调用 start() 方法启动线程
实现 Runnable 接口
创建线程
一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待,休眠,赌塞或死亡状态。要使线程处于就绪,有以下几种方法:调用 sleep() 方法。调用 wait() 方法。等待输入/输出完成。当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:线程调用 notify() 方法。线程调用 notifyAll() 方法。线程调用 interrupt() 方法。线程的休眠时间结束。输入/输出结束。
线程的生命周期
一种能控制线程行为的方法是调用 sleep() 方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。 由于 sleep()方法的执行有可能抛出 InterruptedException 异常,所以将 sleep()方法调用放在 try-catch 块中。虽然使用了 sleep()方法的线程在一段时间内会醒来,但是并不能保证它醒来后进入运行状态,只能保证它进入就绪状态。
线程的休眠
如果当前程序为多线程程序,加入存在一个线程 A,现需要插入 B,并要求线程 B先执行完毕,然后再继续执行线程 A,此时可以使用 Thread 类中的 join()方法来完成。这就好不比此时读者正在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。 当某个线程使用 join() 方法的加入一个线程时,另外一个线程会等待该线程执行完毕后再继续执行。
线程的加入
以往有时候会使用 stop() 方法停止线程,但当前版本的 JDK 早已废除了 stop() 方法,不建议使用 stop() 方法来停止一个线程的运行。现在提倡在 run() 方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。 如果线程是因为使用了 sleep()或 wait()方法进入了就入就绪状态,可以使用 Thread()方法,同时程序破除了 InterruptedException 异常,在异常处理时结束了 while 循环。在项目中,经常在这里执行关闭数据连接和关闭 Socket 连接等操作。
线程的中断
Thread 类提供了一种礼让方法,使用 yied()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。 yied()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用 yied()方法,因为操作系统会为线程自动分配 CPU 时间来执行。
线程的礼让
操作线程的方法
每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就按照较低。 线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在 1~10,将产生IllegalArgumentException 异常。
线程的优先级
在编写多线程时时,因该考虑到线程安全问题。实质上线程问题来源两个线程同时存取单一对象的数据。例:实现 Runnable 接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能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()+\"---票数\
线程安全
在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同事说话、两个人同时过同一个独木桥。所以,在多线程编程中需要防止这些资源访问的冲突。Java 提供了线程同步的机制来防止资源访问的冲突。
所以解决多线程资源问题的方法基本上都是采用给定时间只允许一个线程访问共享资源的方法。这时就需要给共享源上一道锁。这就好比一个人上洗手间时,他进入洗手间后会将门上锁,出来是再将锁打开,然后其他人才可以进入。
Java中提供了同步机制,可以有效地防止资源冲突。同步机制使用 synchronized 关键字,使用该关键字包含的代码块称为同步块,也称临界区,语法如下:synchronized(Object){}
同步块
同步方法就是在方法前面用 synchronized 关键字修饰的方法,语法如下:synchronized void f(){ } 当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为 synchronized,否则就会报错。
同步方法
线程同步机制
线程同步
第20章 多线程
为了实现两台计算机的通信,必须用一个网络线路连接两台算计。 服务器是指提供信息的计算机程序,客户机是指请求信息的计算机或程序。网络用于连接服务器与客户机,实现两者的相互通信。但是,有时在某个网络中很难将服务器与客户机区分开。局域网 (LAN) 是一群通过一定形式连接起来的计算机,它可以由两台计算机组成,也可以由同一区域内地上千台计算机组成。将 LAN 延伸到更大的范围,这样的网络成为广域网(WAN)。互联网是由无数的 LAN 和 WAN 组成的。
局域网与互联网
网络协议规定了计算机之间连接的物理、机械(网络与网卡的连接规定)、电气(有效的电平范围)等特征,计算机之间的相互寻址规则,数据发送冲突的解决方式,长数据如何分段传送与接收等内容。 IP 是 Internet Protocol 的简称,是一种网络协议。Internet 网络采用的协议是 TCP/IP协议。TCP/IP 模式是一种层次结构,共分为 4 层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定服务和访问接口,并具有相对的独立性。
网络协议
一般而言,一台计算机只有单一的连接到网络的物理连接,所以的数据读通过此连接对内、对外送达特定的计算机,这就是端口。网络程序设计的端口(port)并非真实的物理存在,而是一个假想的连接装置。 网络程序中的套接字(Socket)用于将应用程序 与端口连接起来。套接字是一个假想的连接装置,就像插座一样可以连接电器与电线。
端口域套接字
网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封装成不同的类,用户只要创建这些类的对象,使用相应的方法,即使不具备有关的网络支持,也可以编写出高质量的网络通信程序。
网络程序设计基础
TCP 网络程序设计是利用 Socket 类编写通信程序。利用 TCP 协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序,两者的功能和编写方法大不一样。
java.net 包中的 InterAddress 类是与 IP 地址相关的类,利用该类可以获取 IP 地址、主机地址等信息。例:获取计算机的本机名与 IP地址import java.net.InetAddress;import java.rmi.UnknownHostException;public class Address { public static void main(String[] args) throws java.net.UnknownHostException { InetAddress ip;//创建InteAddress对象 ip=InetAddress.getLocalHost();//实例化对象 String localname=ip.getHostName();//获取本机名 String localip=ip.getHostAddress();//获取本机IP地址 System.out.println(\"本机名:\"+localname); System.out.println(\"本机IP地址:\"+localip); }}运行结果:
InterAddress 类
ServerSocket 类
例:创建 TCP/IP 协议服务器,本实例是一个 TCP服务器端程序。import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;public class MyServer { private ServerSocket server;//服务器套接字 private Socket socket;//客户机套接字 void start() throws IOException { 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)) { System.out.println(\"客户机退出\"); break; } System.out.println(\"客户机:\"+message); } reader.close();//关闭流 socket.close();//关闭套接字 } } public static void main(String[] args) throws IOException { MyServer tcp=new MyServer(); tcp.start();//启动服务器 }}运行结果:
运行服务器端程序,将输出提示信息,等待客户呼叫。下面再来看一下客户端程序。 import java.awt.BorderLayout;import java.awt.Container;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.IOException;import java.io.PrintWriter;import java.net.Socket;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField; public class MyClient extends JFrame{ private PrintWriter writer;//根据套接字字节流创建的字符输出流 Socket socket;//客户端套接字 private JTextArea area = new JTextArea();//展示信息的文本域 private JTextField text = new JTextField();//发送信息的文本框 public MyClient() { setTitle(\"向服务器送数据\
TCP 程序设计
TCP 程序
DatagramPacket 类
DatagramSocket 类
例:创建 UDP 协议广播电台程序,广播主机程序不断地向外播出信息。 import java.io.IOException;import java.net.DatagramPacket;import java.net.InetAddress;import java.net.MulticastSocket; public class Notification extends Thread{ String weather = \"节日预报:八点有大型晚会,请收听\";//发送的消息 int port = 9898;//端口 InetAddress iaddress = null; MulticastSocket socket = null;//多点广播套接字 Notification(){ try { iaddress = InetAddress.getByName(\"224.225.10.0\
接收广播程序。代码如下: font color=\"#e74f4c\
UDP 程序设计
UDP 程序
第21章 网络通信
Java从入门到精通 2
收藏
收藏
0 条评论
回复 删除
下一页