Java从入门到精通 2
2023-12-19 11:47:21 0 举报
AI智能生成
Java从入门到精通 2
作者其他创作
大纲/内容
第12章 集合类
Collection 接口
Collection接口是层次结构中的跟接口,构成Collection的单位称为元素。Collection接口接口通常不能直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。
Collection接口的常用方法
方法 功能描述
add(E e) 将指定的对象添加到该集合中
remove(Object o) 将指定的对象从该集合中移除
iterator() 返回在此Collection的元素上进行迭代器。用于遍历集合的对象
isEmpty() 返回Boolean值,用于判断当前集合是否为空
size() 返回int型值,获取该集合中元素的个数
方法 功能描述
add(E e) 将指定的对象添加到该集合中
remove(Object o) 将指定的对象从该集合中移除
iterator() 返回在此Collection的元素上进行迭代器。用于遍历集合的对象
isEmpty() 返回Boolean值,用于判断当前集合是否为空
size() 返回int型值,获取该集合中元素的个数
List 集合
ArrayList 类
实现了可变的数组,允许保存所有元素,包括 null。并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或删除对象的速度较慢。
LinkedList 类
采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合中插入、删除对象时,使用 LinkedList 类实现的 List 集合的效率较高;但对于随机访问集合中的对象,使用 LinkedList 类实现 List 集合的效率低。
Set 集合
HashSet 类
实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 Set 集合的迭代顺序,特别是它不保证改顺序永久不变。此类允许使用 null 元素。
ThreeSet 类
采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合中插入、删除对象时,使用LinkedList类实现List集合的效率较低。
Map 集合
HashMap 类
基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。HashMap类通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
TreeMap 类
不仅实现了Map接口,还实现了java.util.SortedMap接口,因此集合中的映射关系具有一定的顺序。但是添加、删除和定位映射关系时,TreeMap类比HashMap类性能稍等。由于TreeMap类实现的Map集合中的映射关系是根据建对象按照一定的顺序排列,因此不允许键对象是null。
Map集合没有继承Collection接口,其提供的是key到value的映射。Map集合中不能包含相同的key,每个key只能映射一个value。key还决定了存储对象在映射中的存储位置,但不是由key对象本身决定的。
Map接口除集合常用方法外的特殊方法
方法 功能描述
put(K key,V value) 向集合中添加指定的key与value的映射关系
containsKey(Object key) 如果此映射包含指定key的映射关系,则返回true
contains Value(Object value) 如果此映射将一个或多个key映射到指定值,则返回true
get(Object key) 如果存在指定key对象,则返回该对象对应的值,否则返回null
keySet() 返回该集合中所有key对象形成Set集合
values() 返回该集合中所有值对象形成的Collection集合
方法 功能描述
put(K key,V value) 向集合中添加指定的key与value的映射关系
containsKey(Object key) 如果此映射包含指定key的映射关系,则返回true
contains Value(Object value) 如果此映射将一个或多个key映射到指定值,则返回true
get(Object key) 如果存在指定key对象,则返回该对象对应的值,否则返回null
keySet() 返回该集合中所有key对象形成Set集合
values() 返回该集合中所有值对象形成的Collection集合
第13章 枚举于泛型
枚举类型
values() 方法
枚举类型实例,该方法将枚举中所有的枚举值以数组的形式返回。
valuesOf() 方法与 compareTo() 方法
枚举类型中的静态方法 valuesOf() 可以将普通字符串转换为枚举类型,而 comparedTo() 方法用于比较两个枚举类型对象定义时的顺序。
ordinal() 方法
枚举类型中的 ordinal() 方法用于获取某个枚举对象的位置索引值。
枚举类型中的构造方法
在枚举类型中,可以添加构造方法,但是规定这个构造方法必须被 private 修饰符所修饰。
枚举类型声明提供了一种对用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结枚举类型,它具有以下特点:
类型安全。
紧凑有效的数据定义。
可以和程序其他部分完美交互。
运行效率高。
类型安全。
紧凑有效的数据定义。
可以和程序其他部分完美交互。
运行效率高。
泛型
定义泛型类
Object类最上层的父类,很多程序员为了使用更为通用,设计程序时通常使传入的值与返回的值都以Object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在运行时将会发生ClassCastException异常。
为了提前预防这种问题,Java提供了泛型机制。语法如下:
类名.<T>
为了提前预防这种问题,Java提供了泛型机制。语法如下:
类名.<T>
泛型的常规用法
定义泛型类时声明多个类型,语法如下:
class MyClass<T1,T2>{ }
class MyClass<T1,T2>{ }
泛型的高级用法
1、限制泛型可用类型
默认可以使用任何类型来实例化一个泛型类对象,但Java中也对泛型类实例的类型作了限制。
语法如下:
class 类名名称<T extends anyClass>
anyClas指某个接口或类,使用泛型限制后,泛型类的类型必须实现或继承anyClass 这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。
2、使用类型通配符
在泛型机制中,提供了类型通配符,主要作用是在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或子类。要声明这样一个对象可以使用“?”通配符来表示,同时使用extends关键字来对泛型加以限制。
使用泛型类型通配符的语法如下:
泛型类名称<?extends List>a=null;
3、继承泛型类与现实泛型接口
定义泛型的类和接口可以被继承与实现。让SubClass类继承ExtendClass的泛型,代码如下:
class ExtendClass<T1>{}
class SubClass<T1,T2,T3>implements SomeInterface<T1>{}
默认可以使用任何类型来实例化一个泛型类对象,但Java中也对泛型类实例的类型作了限制。
语法如下:
class 类名名称<T extends anyClass>
anyClas指某个接口或类,使用泛型限制后,泛型类的类型必须实现或继承anyClass 这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。
2、使用类型通配符
在泛型机制中,提供了类型通配符,主要作用是在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或子类。要声明这样一个对象可以使用“?”通配符来表示,同时使用extends关键字来对泛型加以限制。
使用泛型类型通配符的语法如下:
泛型类名称<?extends List>a=null;
3、继承泛型类与现实泛型接口
定义泛型的类和接口可以被继承与实现。让SubClass类继承ExtendClass的泛型,代码如下:
class ExtendClass<T1>{}
class SubClass<T1,T2,T3>implements SomeInterface<T1>{}
第14章 lambda表达式
lambda 表达式
lambda 表达式可以用非常少的代码实现抽象方法。lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数接口的对象。
可以将lambda表达式语法用法如下:
(方法参数) -> {方法体}
这个方法 按照 这样的代码来实现
语法格式如下:
()->{代码块}
参数 ->{代码块}
(参数1,参数2,...,参数n)->{代码块 }
可以将lambda表达式语法用法如下:
(方法参数) -> {方法体}
这个方法 按照 这样的代码来实现
语法格式如下:
()->{代码块}
参数 ->{代码块}
(参数1,参数2,...,参数n)->{代码块 }
lambda 表达式实现函数式接口
1、函数式接口
函数式接口指的是仅包含一个抽象方法的接口,接口中的方法简单明了地说明了接口的用途。开发者可以创建自定义的函数式接口 2、lambda 表达式实现无参抽象方法
很多函数式接口的抽象放方法式无参数的这样的无参抽象方法在lambda表达式中使用“()”表示。 3、lambda 表达式实现有参抽象方法
抽象方法中有一个或多个参数的函数式接口也是很常见的,lambda 表达式中可以用“(a1,a2,a3)”的方法表示有参数抽象方法,圆括号里标识符对应抽象方法的参数。如果抽象方法中只有一个参数,则可以省略圆括号。 4、lambda 表达式使用代码块
当函数式接口的抽象方法需要方法实现复杂逻辑而不是返回一个简单的表达式的话,就需要在lambda 表达式中使用代码块。lambda 表达式会自动判断返回值类型是否符合抽象方法的定义。
函数式接口指的是仅包含一个抽象方法的接口,接口中的方法简单明了地说明了接口的用途。开发者可以创建自定义的函数式接口 2、lambda 表达式实现无参抽象方法
很多函数式接口的抽象放方法式无参数的这样的无参抽象方法在lambda表达式中使用“()”表示。 3、lambda 表达式实现有参抽象方法
抽象方法中有一个或多个参数的函数式接口也是很常见的,lambda 表达式中可以用“(a1,a2,a3)”的方法表示有参数抽象方法,圆括号里标识符对应抽象方法的参数。如果抽象方法中只有一个参数,则可以省略圆括号。 4、lambda 表达式使用代码块
当函数式接口的抽象方法需要方法实现复杂逻辑而不是返回一个简单的表达式的话,就需要在lambda 表达式中使用代码块。lambda 表达式会自动判断返回值类型是否符合抽象方法的定义。
lambda 表达式调用外部变量
lambda 表达式除了可以调用定义好的参数,还可以调用表达式以外的变量。但是这些外部的变量有些可以被更改,有些则不能。例如,lambda 表达式无法更改局部变量的值,但是却可以更改外部类的成员变量(也可叫做类属性)的值。
1、lambda 表达式无法更改局部变量
局部变量在lambda 表达式中默认被定义为final(静态)的,也就是说,lambda 表达式只能调用局部变量,却不能改变值。 2、 lambda 表达式可以更改类成员变量
类成员变量是在lambda 表达式中不是被final修饰的,所以lambda 表达式可以改变其值。
1、lambda 表达式无法更改局部变量
局部变量在lambda 表达式中默认被定义为final(静态)的,也就是说,lambda 表达式只能调用局部变量,却不能改变值。 2、 lambda 表达式可以更改类成员变量
类成员变量是在lambda 表达式中不是被final修饰的,所以lambda 表达式可以改变其值。
lambda 表达式与异常处理
很多接口的抽象方法为保证程序的安全性,会在定义时就抛出异常。但是lambda 表达式中并没有抛出异常的语法,这是因为lambda 表达式会默认抛出抽象方法原有的异常,当此方法被调用时则需要进行异常处理。
方法的引用
引用静态方法
引用静态方法的语法如下:
类名 : : 静态方法名
引用静态方法的语法如下:
类名 : : 静态方法名
引用成员方法
引用成员方法的语法如下:
对象名 : : 成员方法名
引用成员方法的语法如下:
对象名 : : 成员方法名
引用构造方法
1、引用无参数构造方法
引用无参数构造方法的方法如下:
类名 : : new 2、 引用有参数构造方法
引用有参构造方法的语法与引用无构造方法一样。区别就是函数式接口的抽象方法是有参数的。
1、引用无参数构造方法
引用无参数构造方法的方法如下:
类名 : : new 2、 引用有参数构造方法
引用有参构造方法的语法与引用无构造方法一样。区别就是函数式接口的抽象方法是有参数的。
流处理
流处理有点类似数据库的SQL语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一的缺点是代码可读性不高,如果开发者基础不好,可能会看到API所表达的含义。
Stream 接口
流处理的接口都定义在 java.uil.stream 包下。BaseStream 接口是最基础的接口,但最常见的是BaseStream 接口的一个子接口——Stream接口,基本上绝大多数的流处理都是在Stream 接口实现的。Stream 接口是泛型接口,所有流中操作的元素可以是任何的对象。
因为所有集合类都是Collection接口的子类,如ArrayList类,HashSet类等,所有这些都可以进行流处理。例如:
List<Integer>list=new ArrayList<Interger>(); //创建集合
Stream<Integer> s=list.stream(); //获取集合流对象
因为所有集合类都是Collection接口的子类,如ArrayList类,HashSet类等,所有这些都可以进行流处理。例如:
List<Integer>list=new ArrayList<Interger>(); //创建集合
Stream<Integer> s=list.stream(); //获取集合流对象
Collectors 类
Collectors 类为收集器类,该类实现了 java.util.Collector 接口,提供了非常丰富的 API,有着强大的数据挖掘能力,也可以将 Stream 流处理进行各种各样的封装、归类、分组等操作。同时,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 对象中。
数据统计不仅不可以筛选出特殊元素,还可以对元素的属性进行统计计算。这种复杂的统计操作不是由 Stream 实现的,而是由 Collectors 收集器类实现的,收集器提供了非常的API,有着其强大的数据挖掘能力。
2、数据分组
数据分组就是将流中元素按照指定的条件分开保存,类似 SQL 语言中的 “GROUP BY” 关键字。分组之后的数据会按照不同标签分别保存成一个集合,然后按照 “键—值” 关系封装在 Map 对象中。
第15章 I/O(输入/输出)
输入/输出流
输入流
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中的方法类似。
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中的方法类似。
输出流
OutputStream 类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类。 OutputStream 类中的所有方法均返回 void,在遇到错误时会引发 IOException 异常 。
write(int b)方法:将指定的字节写入此输入流
write(byte[] b)方法:将b个字节从指定的byte数组写入此输入流
write(byte[] b,int off,int len)方法:将指定byte数组中从偏移量 off 开始的 len 个字节写入此输出流
flush()方法:彻底完成输出并清空缓存区。
close() 方法:关闭输出流
Writer 类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。
write(int b)方法:将指定的字节写入此输入流
write(byte[] b)方法:将b个字节从指定的byte数组写入此输入流
write(byte[] b,int off,int len)方法:将指定byte数组中从偏移量 off 开始的 len 个字节写入此输出流
flush()方法:彻底完成输出并清空缓存区。
close() 方法:关闭输出流
Writer 类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。
File 类
1、File(String pathname)
该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新 File 实例。语法如下:
new File(String pathname)
2、 File(String parent,String child)
该构造方法定义的父路径和子路径字符串(包含文件名)创建一个新的 File 对象。语法如下:
new File(String parent,String child)
3、 File( Filef,String child)
该构造方法根据f抽象路径名和child路径名字符串创建一个新年 File 实例。语法如下:
new File( Filef,String child)
该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新 File 实例。语法如下:
new File(String pathname)
2、 File(String parent,String child)
该构造方法定义的父路径和子路径字符串(包含文件名)创建一个新的 File 对象。语法如下:
new File(String parent,String child)
3、 File( Filef,String child)
该构造方法根据f抽象路径名和child路径名字符串创建一个新年 File 实例。语法如下:
new File( Filef,String child)
文件输出/输入流
程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存文件中。
FileInputStream 类与 FileOutputStream 类
FileInputStream 类与 FileOutputStream 类 都用来操磁盘文件。如果用户的文件读取要求比较简单,则可以使用 FileInputStream 类,该类继承自 InputStream 类。FileOutputStream 类是 OutputStream 类的子类。
FileInputStream 类常用的构造方法:
FileInputStream(String name)
FileInputStream(File file)
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() 方法就顺序地读取源中其余的内容,直接源的末尾或流被关闭。
使用 FileOutputStream 类向文件中写入数据与使用 FileInputStream 类丛文件中将内容读出来,都存在一点不足,即这两个类都只提供了对字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流 FileReader 类或 FileWriter 类即可避免这种现象。
FileReader 类和 FileWriter 类对应了 FileInputStream 类和 FileOutputStream 类。FileReader 类顺序地读取文件,只要不关闭流,每次调用 read() 方法就顺序地读取源中其余的内容,直接源的末尾或流被关闭。
带缓存的输入/输出流
缓存时 I/O 的一种性能优化。缓存流为 I/O 流增加了内存缓存区,使得再流上执行 skip()、mark()、和 reset()方法成为可能。
BufferedReader 与 BufferedWriter 类
BufferedReader 类与 BufferedWriter 类分别继承 Reader 与 Writer 类。这两个类同时具有内部缓存机制,并能够以行单位进行输入/输出。
BufferedReader 类常用的方法如下:
read()方法:读取单个字符
readLine()方法:读取一个文本行,并将其返回为字符串。若无数据可读,返回null。
BufferedWriter 类中的方法都返回void。常用的方法如下:
write(String s,int off,int len)方法:写入字符串的某一部分
flush()方法:刷新该流的缓存
newLine()方法:写入一个行分隔符
BufferedReader 类与 BufferedWriter 类分别继承 Reader 与 Writer 类。这两个类同时具有内部缓存机制,并能够以行单位进行输入/输出。
BufferedReader 类常用的方法如下:
read()方法:读取单个字符
readLine()方法:读取一个文本行,并将其返回为字符串。若无数据可读,返回null。
BufferedWriter 类中的方法都返回void。常用的方法如下:
write(String s,int off,int len)方法:写入字符串的某一部分
flush()方法:刷新该流的缓存
newLine()方法:写入一个行分隔符
数据输入/输出流
数据输入/输出流 (DataInputStream 类与 DataOutputStream 类)允许应用程序以与机器无关的方式从底层输入流中读取基本 Java 数据类型。也就是说,当读取一个数据时,不必关心这个数值应当是哪个字节。
DataInputStream 类提供了将字符串、double 数据、int 数据、Boolean 数据写入文件的方法;DataOutputStream 类只提供了一个readUTF()方法返回字符串。
DataInputStream 类与 DataOutputStream 类的构造方法:
DataInputStream(DataInputStream in):使用指定的基础 InputStream 对象创建一个 DataInputStream 对象。
DataOutputStream(DataOutputStream out):创建一个新的数据输出流,将数据写入一个指定基础输出流。
DataInputStream 类提供了将字符串、double 数据、int 数据、Boolean 数据写入文件的方法;DataOutputStream 类只提供了一个readUTF()方法返回字符串。
DataInputStream 类与 DataOutputStream 类的构造方法:
DataInputStream(DataInputStream in):使用指定的基础 InputStream 对象创建一个 DataInputStream 对象。
DataOutputStream(DataOutputStream out):创建一个新的数据输出流,将数据写入一个指定基础输出流。
第16章 反射与注解
反射
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。Java反射机制的功能十分强大,在java.lang.reflect包中提供了对该功能的支持。
访问构造方法
在通过下列一组方法访问构造方法时,将返回 Constructor 类型的对象或数组。每个Constructor 对象代表一个构造方法。
访问成员变量
在通过下列一组方法去访问成员变量时,将返回 Field 类型的对象或数组。
访问成员方法
在通过下列一组方法访问成员方法时,将返回 Method 类型的对象或数组。
Annotation 注解
定义 Annotation 类型
在定义 Annotation 类型时,也需要用到用来定义接口的 interface 关键字,但需要在 interface字前加一个 “@” 符合,即定义 Annotation 类型的关键字为 @interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。
访问 Annotation 信息
如果在定义 Annotation 类型时将@RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的 Annotation 信息,如获取构造方法、字段和方法的 Annotation 信息。
Java提供了 Annotation 注解功能 ,该功能可用于类、构造方法、成员变量、成员方法、参数等的声明中。该功能不影响程序的运行,但是会对编译器警告等辅助工具产生影响。
第17章 数据库操作
第一步:注册驱动
//第一步注册驱动
DriverManager.registerDriver(new Driver());
DriverManager.registerDriver(new Driver());
第二步:获取连接
//第二步:获取连接
connection=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/school_java","root","1234");
}
connection=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/school_java","root","1234");
}
第三步:获取 statement 对象
//第三步:获取statement对象
PreparedStatement preparedStatement=
connection.prepareStatement("select * from couse;");
PreparedStatement preparedStatement=
connection.prepareStatement("select * from couse;");
第四步:执行 SQL 语句返回结果
//第四步: 执行SQL语句返回结果集
ResultSet resultSet=preparedStatement.executeQuery();
ResultSet resultSet=preparedStatement.executeQuery();
第五步:遍历结果集
//第五步:遍历结果集
while(resultSet.next()) {
System.out.print(resultSet.getInt("id")+" ");
System.out.println(resultSet.getString("name"));
}
while(resultSet.next()) {
System.out.print(resultSet.getInt("id")+" ");
System.out.println(resultSet.getString("name"));
}
第六步:关闭连接释放资源
//第六步:关闭连接释放资源
resultSet.close();
preparedStatement.close();
}
resultSet.close();
preparedStatement.close();
}
SQL 语句
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 条件表达式;
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 条件表达式;
JBDC常用的类和接口
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()方法可将指针向下移。
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()方法可将指针向下移。
第18章 Swing 程序设计
Swing 常用窗体
JFrame 窗体
JFrame 类的常用构造方法包括以下两种形式:
public JFrame(): 创建一个初始不可见、没有标题的窗体。
public JFrame(String title): 创建一个不可见、具体标题的窗体。
在创建窗体后,先调用 getContentPane() 方法将窗体转换为容器,再调用 add() 方法或者 remove() 方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:
JButton okButn=new JButton("确定 ")
container.add(okButn);
删除容器中的按钮, 关键代码如下:
container.remove(okButn);
在创建窗体后,要对窗体进行设置,如设置窗体的位置、大小、是否可见等。具体如下:
setBounds(int x , int y , int width , int length): 设置窗体左上角在屏幕中坐标为(x , y),窗体的宽度为 width,窗体的高度为height。
setLocation(int x , int y): 设置窗体左上角在屏幕中的坐标为(x , y)。
setSize(int width , int height): 设置窗体的宽度为 width,高度为 height。
setVisible(boolean b): 设置窗体是否可见。b 为 true 时,表示可加;b 为 false 时,表示不可见。
setDefaultCloseOperation(int operation): 设置窗体的关闭方式,默认值为 DISPOSE_NO_CLOSE。
public JFrame(): 创建一个初始不可见、没有标题的窗体。
public JFrame(String title): 创建一个不可见、具体标题的窗体。
在创建窗体后,先调用 getContentPane() 方法将窗体转换为容器,再调用 add() 方法或者 remove() 方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:
JButton okButn=new JButton("确定 ")
container.add(okButn);
删除容器中的按钮, 关键代码如下:
container.remove(okButn);
在创建窗体后,要对窗体进行设置,如设置窗体的位置、大小、是否可见等。具体如下:
setBounds(int x , int y , int width , int length): 设置窗体左上角在屏幕中坐标为(x , y),窗体的宽度为 width,窗体的高度为height。
setLocation(int x , int y): 设置窗体左上角在屏幕中的坐标为(x , y)。
setSize(int width , int height): 设置窗体的宽度为 width,高度为 height。
setVisible(boolean b): 设置窗体是否可见。b 为 true 时,表示可加;b 为 false 时,表示不可见。
setDefaultCloseOperation(int operation): 设置窗体的关闭方式,默认值为 DISPOSE_NO_CLOSE。
JDialog 对话框
JDialog 对话框继承了 java.awt.Dialog 类,其功能是从一个窗体中弹出另一个窗体,如使用 IE 浏览器时弹出的确定对话框。JDialog 对话框与JFrame 窗体类似,被使用时也需 getContentPane() 方法把 JDialog 对话框转换为容器,再对 JDialog 对话框进行设置。
JOptionPane 小型对话框
Java API 中的,Javax.swing,JOptionPane 类时一个非常简便的小型对话框类,该类用于创建对话框的方法都是静态方法,无须创建对象即可弹出。在日常开发中经常使用该类弹出提示、确认用户需要、调试程序等。
1、自定义对话框 2、确认框 3、输入框
常用布局管理器
null 绝对布局
绝对布局也叫 null 布局,其特点是硬性指定组件在容器中的位置大小,组件的位置通过绝对坐标的方式来指定。使用绝对布局首先使用 Container.seLayout(null)方法取消容器的布局管理器,然后再使用 Component.setBounds(int x,int y,int width,int height)方法设置每个组件在容器中的位置和大小。
FlowLayout 流布局管理器
流布局(FlowLayout)管理器是 Swing 中最基本的布局管理器。使用流布局管理器摆放组件时,组件被从左到右摆放。当组件占据了当前的所有空间时,溢出的组件会被移动到当前的下一行。默认情况下,行组件的排列方式会被指定为居中对齐,但是通过设置可以更改每一行组件的排序方式。
BorderLayout 边界布局管理器
使用 Swing 创建窗体后,容器默认的布局管理器是边界布局(BorderLayout )管理器 ,边界布局把容量划分为东、南、西、北、中5个区域,但组件被添加到设置为边界布局管理器的容器时,需要使用 BorderLayout 类中成员变量指定被添加的组件在边界布局管理器中的区域。
GridLayout 网格布局管理器
网格布局(GridLayout)管理器能够把容器划分为网格,组件可以按行、列进行排序。在网格布局管理器中,网格的个数由行数和列数决定,且每个网格的小大都相同。改变窗体大小时,组件的大小也会随之改变。
常用面板
JPanel 面板
JPanel 面板 继承 java.awt.Container 类。JPanel 面板必须放在窗体容器中使用,无法摆脱窗体显示。
JScrollPane 滚动面板
JScrollPane 面板是带滚动条的面板,被用于在较小的窗体显示较大篇幅的内容。JScrollPane 滚动面板不能使用布局管理器,且只能容纳一个组件。如果需要向 JScrollPane 面板中添加多个组件,那么需要先将多个组件添加到 JPanel 面板,再将 JPanel 面板添加到JScrollPane 滚动面板。
文字标签组件与图标
JLabel 标签
标签(JLabel)的父类是 JComponent 类。虽然标签不能被添加监听器,但是标签显示的文本、图表等内容可以把被指定对齐方式。通过 JLabel 类的构造方法,可以创建多种标签,如显示只有文本标签、只有图标的标签以及同时包含文本和图标的标签等。
图标的使用
在 Swing 程序设计中,图标经常被添加到标签、按钮等组件,使用 javax.swing.ImageIcon 类可以依据现有的图片创建图标。ImageIcon 类实现了 Icon 接口,它有多个构造方法。
按钮组件
JButton 按钮
Swing 按钮由 JButton 对象表示,JButton 常用的构造方法如下:
public JButton():创建一个不带文本或图标的按钮。
public JButton(String text):创建一个带文本的按钮。
public JButton(Icon icon):创建一个带图标的按钮。
public JButton(String text,Icon icon):创建一个带文本和图标的按钮。
public JButton():创建一个不带文本或图标的按钮。
public JButton(String text):创建一个带文本的按钮。
public JButton(Icon icon):创建一个带图标的按钮。
public JButton(String text,Icon icon):创建一个带文本和图标的按钮。
JRadioButton 单选按钮
Swing单选按钮由JRadioButton对象表示,在swing程序设计中,需要把多个单选按钮添加到按钮组,当用户选中某个单选按钮时,按钮组中的其他单选按钮将不能被同时选中。
JCheckBox 复选框
复选框组件由 JCheckBox 对象表示,以单选按钮不同的是,窗体中的复选框可以被选中多个,这是因为每一个复选框都提供了“被选中”和“不被选中”两种状态。
列表组件
JComboBox 下拉列表框
初次使用下拉列表框时,会感觉swing中的下拉列表框以WINDOWS操作系统中的下拉列表框有一些相似,实质上两者并不完全相同,因为swing中的下拉列表框不仅可以供用户从中选择列表项,也提供编辑列表项的功能。
下拉列表框是一个条状的显示区,它具有下拉功能,在下拉列表框的右侧存在一个倒三角的按钮,当用户单机该按钮时,下拉列表框中的项目将会一列表形式显示出来。
下拉列表框组件由 JComboBox 对象表示,JComboBox 类是 javax.swing.JComponent 类的子类。
下拉列表框是一个条状的显示区,它具有下拉功能,在下拉列表框的右侧存在一个倒三角的按钮,当用户单机该按钮时,下拉列表框中的项目将会一列表形式显示出来。
下拉列表框组件由 JComboBox 对象表示,JComboBox 类是 javax.swing.JComponent 类的子类。
JList 列表框
列表框组件被添加到窗体中后,就会被指定长和宽。如果列表框的大小不足以容纳列表项的个数,那么需要设置列表框具有滚动效果,即把列表框添加到滚动面板。
列表框组件由 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 对象表示,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 对象。
文本组件
JTextField 文本框
文本框组件由 JTextField 对象表示。JTextField 类的常用构造方法如下:
public JTextField():创建一个文本为指定的文本框。
public JTextField(String text):创建一个指定文本的文本框。
public JTextField(int fieldwidth):创建一个指定列宽的文本框。
public JTextField(String text,int fieldwidth):创建一个指定文本和列宽的文本框。
public JTextField(Document docModel,String text,int fieldWidth):创建一个指定文本模型、文本内容和列宽的文本框。
public JTextField():创建一个文本为指定的文本框。
public JTextField(String text):创建一个指定文本的文本框。
public JTextField(int fieldwidth):创建一个指定列宽的文本框。
public JTextField(String text,int fieldwidth):创建一个指定文本和列宽的文本框。
public JTextField(Document docModel,String text,int fieldWidth):创建一个指定文本模型、文本内容和列宽的文本框。
JPasswordField 密码框
密码框组件由 JPasswordField 对象表示,其作用是把用户输入的字符串,以某种符号进行加密。JPasswordField 类的常用构造方法如下:
public JPasswordField():创建一个文本未被指定的密码框。
public JPasswordField(String text):创建一个指定文本的密码框。
public JPasswordField(int fieldwidth):创建一个指定列宽的密码框。
public JPasswordField(String text,int fieldwidth):创建一个指定文本和列宽的密码框。
public JPasswordField(Document docModel,String text,int fieldWidth):创建一个指定文本模型、文本内容和列宽的密码框。
public JPasswordField():创建一个文本未被指定的密码框。
public JPasswordField(String text):创建一个指定文本的密码框。
public JPasswordField(int fieldwidth):创建一个指定列宽的密码框。
public JPasswordField(String text,int fieldwidth):创建一个指定文本和列宽的密码框。
public JPasswordField(Document docModel,String text,int fieldWidth):创建一个指定文本模型、文本内容和列宽的密码框。
JTextArea 文本域
文本域组件由JTextArea对象表示,其作用是接受用户的多行文本输入,常用构造方法如下:
public JTextArea(): 创建一个文本未被指定的文本域。
public JTextArea(String text): 创建一个指定文本的文本域。
public JTextArea(int rows,int columns): 创建一个指定行高和列宽,但文本未被指定的文本域。
public JTextArea(Document doc): 创建一个指定文档模型的文本域。
public JTextArea(Document doc ,String Text,int rows,int columns): 创建一个指定文档模型、文本内容以及行高和列宽的文本域。
JTetArea类提供了一个setLineWrap(boolean wrap)方法,这个方法被用于设置文本域中的文本内容,是否可以自动换行。如果参数为true,那么会自动换行,否则不会自动换行
此外,还提供了一个append(String str)方法,这个方法被用于向文本域中添加文本内容。
public JTextArea(): 创建一个文本未被指定的文本域。
public JTextArea(String text): 创建一个指定文本的文本域。
public JTextArea(int rows,int columns): 创建一个指定行高和列宽,但文本未被指定的文本域。
public JTextArea(Document doc): 创建一个指定文档模型的文本域。
public JTextArea(Document doc ,String Text,int rows,int columns): 创建一个指定文档模型、文本内容以及行高和列宽的文本域。
JTetArea类提供了一个setLineWrap(boolean wrap)方法,这个方法被用于设置文本域中的文本内容,是否可以自动换行。如果参数为true,那么会自动换行,否则不会自动换行
此外,还提供了一个append(String str)方法,这个方法被用于向文本域中添加文本内容。
表格组件
创建表格
JTable 类除了提供了默认的构造方法外,还提供了被用于显示二维数组中的元素的构造方法。这个构造方法的语法如下:
JTanle(Object[][]rowDate,Object[]columnNames)
rowDate存储表格数据的二维数组
columnNames,存储表格列明的一维数组
在使用表格时,要先把表格添加到滚动面板,再把滚动面板添加到窗体的相应位置 .
JTanle(Object[][]rowDate,Object[]columnNames)
rowDate存储表格数据的二维数组
columnNames,存储表格列明的一维数组
在使用表格时,要先把表格添加到滚动面板,再把滚动面板添加到窗体的相应位置 .
DefaultTableModel 表格数据模型
Swing使用TableModel接口定义了一个表格模型,AbstractDefaultTableModel抽象类实现了TableModel接口的大部分方法,只有以下 3 个抽象方法没有实现:
public int getRowCount():
public int getColumnCount():
public Object getValueAt(int rowIndex,int colunIndex):
public int getRowCount():
public int getColumnCount():
public Object getValueAt(int rowIndex,int colunIndex):
维护表格模型
表格中的数据内容需要用于维护,使用 getValueAt()方法获得表格中某一个单元格的值,使用 addRow()方法向表格中添加新的行,使用 setValueAt() 方法修改表格中某一个单元格的值,使用 removeRow 方法从表格中删除指定行等。
当删除表格模型中的指定行时,每删除一行,其后所有行的索引值将相应地减 1,所以当连续删除多行时,需要注意对删除行索引的处理。
当删除表格模型中的指定行时,每删除一行,其后所有行的索引值将相应地减 1,所以当连续删除多行时,需要注意对删除行索引的处理。
事件监听器
ActionEvent 动作事件
动作事件(ActionEvent)监听器是 Swing 中比较常用的事件监听器,很多组件的动作都会使用它监听,如按钮被单机击等。
KeyEvent 键盘事件
当向文本框中输入内容时,将发生键盘事件 。KeyEvent 类负责捕获键盘事件,可以通过为组件添加实现了KeyListener 接口的监听器类来处理相应的键盘事件。
MouseEvent 鼠标事件
所有组件都能发生鼠标事件,MouseEvent 类负责捕获鼠标事件,可以通过为组件添加实现了
MouseListener 接口的监听器类来处理相应的鼠标事件。
MouseListener 接口的监听器类来处理相应的鼠标事件。
第19章 Java绘图
Java 绘图类
Graphics 类
Graphics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。 Graphics 类封装了 Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。
Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、矩形、多边形、椭圆、弧形等形状和文本、图形的绘制操作。另外,在执行操作之前,还可以使用相应的方法设置绘图的颜色和字体等状态属性。
Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、矩形、多边形、椭圆、弧形等形状和文本、图形的绘制操作。另外,在执行操作之前,还可以使用相应的方法设置绘图的颜色和字体等状态属性。
Graphics 2D类
使用 Graphics 类可以完成简单的图像绘制任务,但是它所有实现的功能非常有限,如无法改变线条的粗线、不能对图片使用旋转和模糊等过滤效果。
Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由于Graphics2D 类是Graphics 类的扩展,也是推荐使用的 Java 绘图类。
Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由于Graphics2D 类是Graphics 类的扩展,也是推荐使用的 Java 绘图类。
绘制图形
Java可以分为使用 Graphics 类和 Graphics2D 类绘制图形,Graphics 类使用不同的方法实现不同图形的绘制。
绘图颜色与画笔属性
设置颜色
使用 Color 类可以创建任意颜色的对象,不用担心平台是否支持改颜色,因为 Java 以跨平台和与硬件无关的方式支持颜色管理。
设置画笔
默认情况下,Graphics 类使用的画笔属性是粗细为1个像素的正方形,而 Graphics2D 类可以调用 setStroke() 方法设置属性,如果改变线条的粗细、虚实,定义线端点的形状、风格等。
setStroke() 方法必须接受一个Stroke 接口的实现类对象作参数,java.awt 包中提供了BasicStroke 类,它实行了了 Stroke 接口,并且通过不同的构造方法创建画笔不同对象。
setStroke() 方法必须接受一个Stroke 接口的实现类对象作参数,java.awt 包中提供了BasicStroke 类,它实行了了 Stroke 接口,并且通过不同的构造方法创建画笔不同对象。
绘制文本
设置字体
Java使用 Font 类封装了字体的大小、样式等属性,该类在 java.awt 包中定义,其构造方法可以指定字体的名称、大小和样式3个属性。语法如下:
Font(Striig name,int style,int size)
name:字体的名称
style:字体的样式
size:字体的大小
Font(Striig name,int style,int size)
name:字体的名称
style:字体的样式
size:字体的大小
显示文字
Graphics2D 类提供了 drawString()方法,使用该方法可以实现图形上下文的文本绘制,从而实现在图片上显示文字的功能。语法格式有如下两种:
drawString(String str,int x,int y)
drawString(String str,float x,float y)
str:要绘制的文本字符串
x:绘制字符串的水平起始位置
y:绘制字符串的垂直起始位置
drawString(String str,int x,int y)
drawString(String str,float x,float y)
str:要绘制的文本字符串
x:绘制字符串的水平起始位置
y:绘制字符串的垂直起始位置
显示图片
绘图不仅可以绘制图形和文本,还可以使用 drawImage() 方法将图片资源显示到绘图上下文中,而且可以实现各种特效处理。语法如下:
drawImage (Image img,int x,int y,ImageObserver observer)
drawImage (Image img,int x,int y,ImageObserver observer)
图片处理
放大与缩小
使用了 drawImage() 方法将图片以原始大小显示在窗体中,要想实现图片的放大与缩小,则需要使用他的重载方法。语法如下:
drawImage(Image img,int x,int y,int width,int height,ImageObserver observer)
drawImage(Image img,int x,int y,int width,int height,ImageObserver observer)
图像翻转
图像的翻转需要使用 drawImage() 方法的另一个重载方法。语法如下:
drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageOberver oberver)
此方法总是用来非缩放的图像来呈现缩放的矩形,并动态地执行所需要的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。
drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageOberver oberver)
此方法总是用来非缩放的图像来呈现缩放的矩形,并动态地执行所需要的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。
图像旋转
图像旋转需要调用 Graphics2D 类的 rotate()方法,该方法将根据指定的弧度旋转图像。语法如下:
rotate(douuble theta)
theta:旋转的弧度
rotate(douuble theta)
theta:旋转的弧度
图像倾斜
可以使用 Graphics2D 类提供的 shear()方法设置绘图的倾斜方向,从而使图像实现倾斜的效果。语法如下:
shear(double shx,double shy)
shx:水平方向的倾斜量
shy:垂直方向的倾斜量
shear(double shx,double shy)
shx:水平方向的倾斜量
shy:垂直方向的倾斜量
第20章 多线程
创建线程
继承 Thread 类
Thread 类时 java.lang 包中的一个类,从类中实例化的对象代表线程,程序员启动一个新线程需要建立 Thread 实例。
Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,start() 方法启动线程,该工作的功能被写在run() 方法中。
Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,start() 方法启动线程,该工作的功能被写在run() 方法中。
实现 Runnable 接口
线程都是通过扩展 Thread 类来创建的,如果程序员需要继承其他类(非Thread 类),而且还要是当前类实现多线程,那么可以通过 Runnable 接口来实现。
实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。
使用 Runnable 接口启动新的线程的步骤:
建立 Runnable 对象
使用参数为 Runnable 对象的构造方法创建 Thread 实例
调用 start() 方法启动线程
实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。
使用 Runnable 接口启动新的线程的步骤:
建立 Runnable 对象
使用参数为 Runnable 对象的构造方法创建 Thread 实例
调用 start() 方法启动线程
线程的生命周期
一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待,休眠,赌塞或死亡状态。
要使线程处于就绪,有以下几种方法:
调用 sleep() 方法。
调用 wait() 方法。
等待输入/输出完成。
当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:
线程调用 notify() 方法。
线程调用 notifyAll() 方法。
线程调用 interrupt() 方法。
线程的休眠时间结束。
输入/输出结束。
要使线程处于就绪,有以下几种方法:
调用 sleep() 方法。
调用 wait() 方法。
等待输入/输出完成。
当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:
线程调用 notify() 方法。
线程调用 notifyAll() 方法。
线程调用 interrupt() 方法。
线程的休眠时间结束。
输入/输出结束。
操作线程的方法
线程的休眠
一种能控制线程行为的方法是调用 sleep() 方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。
由于 sleep()方法的执行有可能抛出 InterruptedException 异常,所以将 sleep()方法调用放在 try-catch 块中。虽然使用了 sleep()方法的线程在一段时间内会醒来,但是并不能保证它醒来后进入运行状态,只能保证它进入就绪状态。
由于 sleep()方法的执行有可能抛出 InterruptedException 异常,所以将 sleep()方法调用放在 try-catch 块中。虽然使用了 sleep()方法的线程在一段时间内会醒来,但是并不能保证它醒来后进入运行状态,只能保证它进入就绪状态。
线程的加入
如果当前程序为多线程程序,加入存在一个线程 A,现需要插入 B,并要求线程 B先执行完毕,然后再继续执行线程 A,此时可以使用 Thread 类中的 join()方法来完成。这就好不比此时读者正在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。
当某个线程使用 join() 方法的加入一个线程时,另外一个线程会等待该线程执行完毕后再继续执行。
当某个线程使用 join() 方法的加入一个线程时,另外一个线程会等待该线程执行完毕后再继续执行。
线程的中断
以往有时候会使用 stop() 方法停止线程,但当前版本的 JDK 早已废除了 stop() 方法,不建议使用 stop() 方法来停止一个线程的运行。现在提倡在 run() 方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。
如果线程是因为使用了 sleep()或 wait()方法进入了就入就绪状态,可以使用 Thread()方法,同时程序破除了 InterruptedException 异常,在异常处理时结束了 while 循环。在项目中,经常在这里执行关闭数据连接和关闭 Socket 连接等操作。
如果线程是因为使用了 sleep()或 wait()方法进入了就入就绪状态,可以使用 Thread()方法,同时程序破除了 InterruptedException 异常,在异常处理时结束了 while 循环。在项目中,经常在这里执行关闭数据连接和关闭 Socket 连接等操作。
线程的礼让
Thread 类提供了一种礼让方法,使用 yied()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。
yied()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用 yied()方法,因为操作系统会为线程自动分配 CPU 时间来执行。
yied()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用 yied()方法,因为操作系统会为线程自动分配 CPU 时间来执行。
线程的优先级
每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就按照较低。
线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在 1~10,将产生IllegalArgumentException 异常。
线程的优先级可以使用 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()+"---票数"+num--);//票数减一
}
}
}
public static void main(String[] args) {
ThreadSafeTest t=new ThreadSafeTest();//实例化类对象
Thread tA=new Thread(t,"线程一");//以该类对象分别实例化4个线程
Thread tB=new Thread(t,"线程二");
Thread tC=new Thread(t,"线程三");
Thread tD=new Thread(t,"线程四");
tA.start();//分别启动线程
tB.start();
tC.start();
tD.start();
}
}
运行结果:
在编写多线程时时,因该考虑到线程安全问题。实质上线程问题来源两个线程同时存取单一对象的数据。
例:实现 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()+"---票数"+num--);//票数减一
}
}
}
public static void main(String[] args) {
ThreadSafeTest t=new ThreadSafeTest();//实例化类对象
Thread tA=new Thread(t,"线程一");//以该类对象分别实例化4个线程
Thread tB=new Thread(t,"线程二");
Thread tC=new Thread(t,"线程三");
Thread tD=new Thread(t,"线程四");
tA.start();//分别启动线程
tB.start();
tC.start();
tD.start();
}
}
运行结果:
在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同事说话、两个人同时过同一个独木桥。所以,在多线程编程中需要防止这些资源访问的冲突。Java 提供了线程同步的机制来防止资源访问的冲突。
线程同步机制
所以解决多线程资源问题的方法基本上都是采用给定时间只允许一个线程访问共享资源的方法。这时就需要给共享源上一道锁。这就好比一个人上洗手间时,他进入洗手间后会将门上锁,出来是再将锁打开,然后其他人才可以进入。
同步块
Java中提供了同步机制,可以有效地防止资源冲突。同步机制使用 synchronized 关键字,使用该关键字包含的代码块称为同步块,也称临界区,语法如下:
synchronized(Object){
}
synchronized(Object){
}
同步方法
同步方法就是在方法前面用 synchronized 关键字修饰的方法,语法如下:
synchronized void f(){ }
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为 synchronized,否则就会报错。
synchronized void f(){ }
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为 synchronized,否则就会报错。
第21章 网络通信
网络程序设计基础
局域网与互联网
为了实现两台计算机的通信,必须用一个网络线路连接两台算计。
服务器是指提供信息的计算机程序,客户机是指请求信息的计算机或程序。网络用于连接服务器与客户机,实现两者的相互通信。但是,有时在某个网络中很难将服务器与客户机区分开。局域网 (LAN) 是一群通过一定形式连接起来的计算机,它可以由两台计算机组成,也可以由同一区域内地上千台计算机组成。将 LAN 延伸到更大的范围,这样的网络成为广域网(WAN)。互联网是由无数的 LAN 和 WAN 组成的。
为了实现两台计算机的通信,必须用一个网络线路连接两台算计。
服务器是指提供信息的计算机程序,客户机是指请求信息的计算机或程序。网络用于连接服务器与客户机,实现两者的相互通信。但是,有时在某个网络中很难将服务器与客户机区分开。局域网 (LAN) 是一群通过一定形式连接起来的计算机,它可以由两台计算机组成,也可以由同一区域内地上千台计算机组成。将 LAN 延伸到更大的范围,这样的网络成为广域网(WAN)。互联网是由无数的 LAN 和 WAN 组成的。
网络协议
网络协议规定了计算机之间连接的物理、机械(网络与网卡的连接规定)、电气(有效的电平范围)等特征,计算机之间的相互寻址规则,数据发送冲突的解决方式,长数据如何分段传送与接收等内容。
IP 是 Internet Protocol 的简称,是一种网络协议。Internet 网络采用的协议是 TCP/IP协议。TCP/IP 模式是一种层次结构,共分为 4 层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定服务和访问接口,并具有相对的独立性。
IP 是 Internet Protocol 的简称,是一种网络协议。Internet 网络采用的协议是 TCP/IP协议。TCP/IP 模式是一种层次结构,共分为 4 层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定服务和访问接口,并具有相对的独立性。
端口域套接字
一般而言,一台计算机只有单一的连接到网络的物理连接,所以的数据读通过此连接对内、对外送达特定的计算机,这就是端口。网络程序设计的端口(port)并非真实的物理存在,而是一个假想的连接装置。
网络程序中的套接字(Socket)用于将应用程序 与端口连接起来。套接字是一个假想的连接装置,就像插座一样可以连接电器与电线。
网络程序中的套接字(Socket)用于将应用程序 与端口连接起来。套接字是一个假想的连接装置,就像插座一样可以连接电器与电线。
网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封装成不同的类,用户只要创建这些类的对象,使用相应的方法,即使不具备有关的网络支持,也可以编写出高质量的网络通信程序。
TCP 程序
TCP 网络程序设计是利用 Socket 类编写通信程序。利用 TCP 协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序,两者的功能和编写方法大不一样。
InterAddress 类
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);
}
}
运行结果:
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);
}
}
运行结果:
ServerSocket 类
java.net 包中的 ServerSocket 类用于表示服务器套接字,其主要功能是等待来自网络上的“请求”,它可以通过指定的端口来等待连接的套接字。服务器套接字一次可以与一个套接字。如果多台客户机同时提供出连接请求,服务器套接字会将请求连接的客户机存入列队中,然后从中取出一个套接字,与服务器新建的套接字连接起来。若请求连接大于最大容纳数,则多出的连接请求被拒绝。队列的默认大小是 50。
ServerSocket 类的构造方法通常会抛出 IOException 异常,具体有以下几种形式:
ServerSocket(): 创建非绑定服务器套接字。
ServerSocket(int port): 创建绑定到特定端口的服务器套接字。
ServerSocket(int port,int backlog): 利用指定的 backlog 创建服务器套接字,并将其绑定到指定的本地端口号上。
ServerSocket(int port,int backlog,InetAddress bindAddress): 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP 地址的情况,用户可以明确规定 ServerSocket 在哪块网卡或哪个 IP 地址上等待客户的连接请求。
ServerSocket 类的构造方法通常会抛出 IOException 异常,具体有以下几种形式:
ServerSocket(): 创建非绑定服务器套接字。
ServerSocket(int port): 创建绑定到特定端口的服务器套接字。
ServerSocket(int port,int backlog): 利用指定的 backlog 创建服务器套接字,并将其绑定到指定的本地端口号上。
ServerSocket(int port,int backlog,InetAddress bindAddress): 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP 地址的情况,用户可以明确规定 ServerSocket 在哪块网卡或哪个 IP 地址上等待客户的连接请求。
TCP 程序设计
例:创建 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("向服务器送数据");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane(); //主容器
JScrollPane scrollPane = new JScrollPane(area);//滚动面板
getContentPane().add(scrollPane,BorderLayout.CENTER);
c.add(text,"South");//将文本框放在窗体的下部
text.addActionListener(new ActionListener() {//文本框触发回车事件
public void actionPerformed(ActionEvent e) {
writer.println(text.getText().trim());//将文本框中的信息显示在文本域中
area.append(text.getText()+'\n');//将文本框中的信息显示在文本域中
text.setText("");//将文本框清空
}
});
}
private void connect() {//连接服务器方法
area.append("尝试连接\n");//文本域中提示信息
try {
socket = new Socket("127.0.0.1",8998);//连接本地计算机的8998端口
writer = new PrintWriter(socket.getOutputStream(),true);
area.append("完成连接\n");
}catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MyClient clien = new MyClient();
clien.setSize(200, 200);//窗体大小
clien.setVisible(true);//显示窗体
clien.connect();//连接服务器
}
}
运行结果:
例:创建 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("向服务器送数据");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane(); //主容器
JScrollPane scrollPane = new JScrollPane(area);//滚动面板
getContentPane().add(scrollPane,BorderLayout.CENTER);
c.add(text,"South");//将文本框放在窗体的下部
text.addActionListener(new ActionListener() {//文本框触发回车事件
public void actionPerformed(ActionEvent e) {
writer.println(text.getText().trim());//将文本框中的信息显示在文本域中
area.append(text.getText()+'\n');//将文本框中的信息显示在文本域中
text.setText("");//将文本框清空
}
});
}
private void connect() {//连接服务器方法
area.append("尝试连接\n");//文本域中提示信息
try {
socket = new Socket("127.0.0.1",8998);//连接本地计算机的8998端口
writer = new PrintWriter(socket.getOutputStream(),true);
area.append("完成连接\n");
}catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MyClient clien = new MyClient();
clien.setSize(200, 200);//窗体大小
clien.setVisible(true);//显示窗体
clien.connect();//连接服务器
}
}
运行结果:
UDP 程序
用户数据报协议 (UDP) 是网络信息传输的另一种形式。基于 UDP 的通信和基于 TCP 的通信基于 UDP的信息传递更快,但不提供可靠性保证。使用 UDP 传递数据时,用户无法知道数据能否正确地到达主机,也不能确定到达目的地的顺序是否和发送相同。虽然 UDP 是一种不可靠的员议,但如果需要较快地传输信息,并能容忍小的错误,可以考虑使用 UDP。
基于 UDP 通信的基本模式如下:
将数据打包 (称为数据包),然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。
发送数据包的步骤如下:
使用 DatagramSocket() 创建一个数据包套接字。
使用 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)创建要发送的
数据包。
使用 DatagramSocket 类的 send() 方法发送数据包。
接收数据包的步骤如下:
使用 DatagramSocket(int port) 创建数据包套接字,绑定到指定的端口。
使用 DatagramPacket(byte[]buf,int length) 创建字节数组来接收数据包。
使用 DatagramPacket 类的 receive() 方法接收UDP包。
基于 UDP 通信的基本模式如下:
将数据打包 (称为数据包),然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。
发送数据包的步骤如下:
使用 DatagramSocket() 创建一个数据包套接字。
使用 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)创建要发送的
数据包。
使用 DatagramSocket 类的 send() 方法发送数据包。
接收数据包的步骤如下:
使用 DatagramSocket(int port) 创建数据包套接字,绑定到指定的端口。
使用 DatagramPacket(byte[]buf,int length) 创建字节数组来接收数据包。
使用 DatagramPacket 类的 receive() 方法接收UDP包。
DatagramPacket 类
java.net 包的 DatagramPacket 类用来表示数据包。DatagramPacket 类的构造方法如下:
DatagramPacket(byte[] buf, int length)
DatagramPacket(byte[] buf, int length, InetAddress address, int port).
第一种构造方法在创建 DatagramPacket 对象时,指定了数据包的内存空间和大小。第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和口、在发送数据时,必须指定接收方的 Socket 地址和端口号,因此使用第二种构造方法可创建发送数据的 DamgramPacket 对象。
DatagramPacket(byte[] buf, int length)
DatagramPacket(byte[] buf, int length, InetAddress address, int port).
第一种构造方法在创建 DatagramPacket 对象时,指定了数据包的内存空间和大小。第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和口、在发送数据时,必须指定接收方的 Socket 地址和端口号,因此使用第二种构造方法可创建发送数据的 DamgramPacket 对象。
DatagramSocket 类
javanet 包中的 DatagramSocket 类用于表示发送和接收数据包的套接字。该类的构造方法如下:
DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
第一种构造方法创建 DatagramSocket 对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。第二种构造方法创建 DatagramSocket 对象,创建数据报套字,并将其绑定到本地主机的指定端口上。第三种构造方法创建 DatagramSocket 对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个 IP 地址的情况。
DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
第一种构造方法创建 DatagramSocket 对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。第二种构造方法创建 DatagramSocket 对象,创建数据报套字,并将其绑定到本地主机的指定端口上。第三种构造方法创建 DatagramSocket 对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个 IP 地址的情况。
UDP 程序设计
例:创建 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");//广播组地址
socket = new MulticastSocket(port);//实例化多点广播套接字
socket.setTimeToLive(1);//指定发送范围是本地网络
socket.joinGroup(iaddress);//加入广播组
}catch(IOException e) {
e.printStackTrace();//输出异常信息
}
}
public void run() {
while(true) {
DatagramPacket packet = null;//数据包
byte data[] = weather.getBytes();///字符串消息的字节数组
packet = new DatagramPacket(data,data.length,iaddress,port); //将数据打包
System.out.println(weather);//控制台打印消息
try {
socket.send(packet);//发送数据
sleep(3000);//线程休眠
}catch(IOException e) {
e.printStackTrace();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Notification w = new Notification();
w.start();//启动线程
}
}
运行结果:
接收广播程序。代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class Receive extends JFrame implements Runnable,ActionListener{
int port; //端口
InetAddress group = null; //广播组地址
MulticastSocket socket = null; //多点广播套接字对象
JButton inceBtn = new JButton("开始接收");
JButton stopBtn = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10,10); //显示接收广播的文本域
JTextArea inced = new JTextArea(10,10);
Thread thread;
boolean stop = false; //停止接收信息状态
public Receive() {
setTitle("广播数据报");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
thread = new Thread(this);
inceBtn.addActionListener(this); //绑定按钮ince的单击事件
stopBtn.addActionListener(this); //绑定按钮stop的单击事件
inceAr.setForeground(Color.blue); //指定文本域中文字的颜色
JPanel north = new JPanel();
north.add(inceBtn); //将按钮添加到面板north上
north.add(stopBtn);
add(north,BorderLayout.NORTH); //将north放置在窗体的上部
JPanel center = new JPanel(); //创建面板对象center
center.setLayout(new GridLayout(1,2));//设置面板布局
center.add(inceAr); //将文本域添加到面板上
center.add(inced);
add(center,BorderLayout.CENTER); //设置面板布局
validate(); //刷新
port = 9898; //设置端口号
try {
group = InetAddress.getByName("224.225.10.0");//指定接收地址
socket = new MulticastSocket(port); //绑定多点广播套接字
socket.joinGroup(group); //加入广播组
}catch(IOException e) {
e.printStackTrace(); //输出异常信息
}
setBounds(100,50,360,380);//设置布局
setVisible(true);//将窗体设置为显示状态
}
public void run() { //run()方法
while(!stop) {
byte data[] = new byte[1024];//创建缓存字节数组
DatagramPacket packet = null;
packet = new DatagramPacket(data,data.length,group,port);//待接收的数据包
try {
socket.receive(packet);//接收数据包
//获取数据包中的内容
String message = new String(packet.getData(),0,packet.getLength());
inceAr.setText("正在接收的内容:\n"+message);//将接收内容显示在文本域中
inced.append(message+"\n");//每一条信息为一行
}catch(IOException e) {
e.printStackTrace();//输出异常信息
}
}
}
@Override
public void actionPerformed(ActionEvent e) { //单击按钮ince触发的事件
if(e.getSource() == inceBtn) {
inceBtn.setBackground(Color.red); //设置按钮颜色
stopBtn.setBackground(Color.yellow);
if(!(thread.isAlive())) { //如线程不处于”新建状态“
thread = new Thread(this); //实例化Thread对象
}
thread.start(); //启动线程
stop = false; //开始接收信息
}
if(e.getSource() == stopBtn) { //单击按钮stop触发的事件
inceBtn.setBackground(Color.yellow); //设置按钮颜色
stopBtn.setBackground(Color.red);
stop = true; //停止接收信息
}
}
public static void main(String[] args) {
Receive rec = new Receive();
rec.setSize(460,200);
}
}
运行结果:
例:创建 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");//广播组地址
socket = new MulticastSocket(port);//实例化多点广播套接字
socket.setTimeToLive(1);//指定发送范围是本地网络
socket.joinGroup(iaddress);//加入广播组
}catch(IOException e) {
e.printStackTrace();//输出异常信息
}
}
public void run() {
while(true) {
DatagramPacket packet = null;//数据包
byte data[] = weather.getBytes();///字符串消息的字节数组
packet = new DatagramPacket(data,data.length,iaddress,port); //将数据打包
System.out.println(weather);//控制台打印消息
try {
socket.send(packet);//发送数据
sleep(3000);//线程休眠
}catch(IOException e) {
e.printStackTrace();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Notification w = new Notification();
w.start();//启动线程
}
}
运行结果:
接收广播程序。代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class Receive extends JFrame implements Runnable,ActionListener{
int port; //端口
InetAddress group = null; //广播组地址
MulticastSocket socket = null; //多点广播套接字对象
JButton inceBtn = new JButton("开始接收");
JButton stopBtn = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10,10); //显示接收广播的文本域
JTextArea inced = new JTextArea(10,10);
Thread thread;
boolean stop = false; //停止接收信息状态
public Receive() {
setTitle("广播数据报");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
thread = new Thread(this);
inceBtn.addActionListener(this); //绑定按钮ince的单击事件
stopBtn.addActionListener(this); //绑定按钮stop的单击事件
inceAr.setForeground(Color.blue); //指定文本域中文字的颜色
JPanel north = new JPanel();
north.add(inceBtn); //将按钮添加到面板north上
north.add(stopBtn);
add(north,BorderLayout.NORTH); //将north放置在窗体的上部
JPanel center = new JPanel(); //创建面板对象center
center.setLayout(new GridLayout(1,2));//设置面板布局
center.add(inceAr); //将文本域添加到面板上
center.add(inced);
add(center,BorderLayout.CENTER); //设置面板布局
validate(); //刷新
port = 9898; //设置端口号
try {
group = InetAddress.getByName("224.225.10.0");//指定接收地址
socket = new MulticastSocket(port); //绑定多点广播套接字
socket.joinGroup(group); //加入广播组
}catch(IOException e) {
e.printStackTrace(); //输出异常信息
}
setBounds(100,50,360,380);//设置布局
setVisible(true);//将窗体设置为显示状态
}
public void run() { //run()方法
while(!stop) {
byte data[] = new byte[1024];//创建缓存字节数组
DatagramPacket packet = null;
packet = new DatagramPacket(data,data.length,group,port);//待接收的数据包
try {
socket.receive(packet);//接收数据包
//获取数据包中的内容
String message = new String(packet.getData(),0,packet.getLength());
inceAr.setText("正在接收的内容:\n"+message);//将接收内容显示在文本域中
inced.append(message+"\n");//每一条信息为一行
}catch(IOException e) {
e.printStackTrace();//输出异常信息
}
}
}
@Override
public void actionPerformed(ActionEvent e) { //单击按钮ince触发的事件
if(e.getSource() == inceBtn) {
inceBtn.setBackground(Color.red); //设置按钮颜色
stopBtn.setBackground(Color.yellow);
if(!(thread.isAlive())) { //如线程不处于”新建状态“
thread = new Thread(this); //实例化Thread对象
}
thread.start(); //启动线程
stop = false; //开始接收信息
}
if(e.getSource() == stopBtn) { //单击按钮stop触发的事件
inceBtn.setBackground(Color.yellow); //设置按钮颜色
stopBtn.setBackground(Color.red);
stop = true; //停止接收信息
}
}
public static void main(String[] args) {
Receive rec = new Receive();
rec.setSize(460,200);
}
}
运行结果:
收藏
收藏
0 条评论
下一页