常用类库
一. 泛型
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定 义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
定义一个泛型类:
public class ClassName<T>
{ private T data;
public T getData() { return data; }
public void setData(T data) { this.data = data; }
}
泛型接口
public interface IntercaceName<T>{ T getData(); }
实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下:
指定类型:
public class Interface1 implements IntercaceName<String>
{
private String text;
@Override
public String getData() { return text; } }
不指定类型:
public class Interface1<T> implements IntercaceName<T> { private T data;
@Override
public T getData() { return data; }
}
通配符?
类型通配符是使用?代替方法具体的类型实参。
1 <? extends Parent> 指定了泛型类型的上届
2 <? super Child> 指定了泛型类型的下届
3 <?> 指定了没有限制的泛型类型
Maths
static double abs(double a) 返回 double值的绝对值。
static float abs(float a) 返回 float值的绝对值。
static int abs(int a) 返回 int值的绝对值。
static long abs(long a) 返回 long值的绝对值。
static double acos(double a) 返回值的反余弦值; 返回的角度在0.0到pi的范围内。
static int addExact(int x, int y) 返回其参数的总和,如果结果溢出 int则抛出异常。
static long addExact(long x, long y) 返回其参数的总和,如果结果溢出 long则抛出异常。
static double asin(double a) 返回值的反正弦值; 返回的角度在-pi / 2到pi / 2的范围内。
static double atan(double a) 返回值的反正切值; 返回的角度在-pi / 2到pi / 2的范围内。
static double atan2(double y, double x) 返回从直角坐标(转换角度 theta x , y )为极坐标 (R,θ-)。
static double cbrt(double a) 返回 double值的多维数据集根。
static double ceil(double a) 返回大于或等于参数且等于数学整数的最小值(最接近负无穷大) double 。
static double copySign(double magnitude, double sign) 返回带有第二个浮点参数符号的第一个浮点参数。
static float copySign(float magnitude, float sign) 返回带有第二个浮点参数符号的第一个浮点参数。
static double cos(double a) 返回角度的三角余弦值。
static double cosh(double x) 返回 double值的双曲余弦值。
static int decrementExact(int a) 返回参数递减1,如果结果溢出 int则抛出异常。
static long decrementExact(long a) 返回参数递减1,如果结果溢出 long则抛出异常。
static double exp(double a) 返回Euler的数字 e ,其值 double值。
static double expm1(double x) 返回 e x -1。
static double floor(double a) 返回小于或等于参数且等于数学整数的最大值(最接近正无穷大) double 。
static int floorDiv(int x, int y) 返回小于或等于代数商的最大值(最接近正无穷大) int 。
static long floorDiv(long x, int y) 返回小于或等于代数商的最大值(最接近正无穷大) long 。
static long floorDiv(long x, long y) 返回小于或等于代数商的最大值(最接近正无穷大) long 。
static int floorMod(int x, int y) 返回 int参数的floor模数。
static int floorMod(long x, int y) 返回 long和 int参数的floor数。
static long floorMod(long x, long y) 返回 long参数的floor模数。
static double fma(double a, double b, double c) 返回三个参数的融合乘法加法; 也就是说,返回与第三个参数相加的前两个参数的精确乘积,然后舍入一次到最接近的double 。
static float fma(float a, float b, float c) 返回三个参数的融合乘法加法; 也就是说,返回与第三个参数相加的前两个参数的精确乘积,然后舍入一次到最接近的float 。
static int getExponent(double d) 返回 double表示中使用的无偏指数。
static int getExponent(float f) 返回 float表示中使用的无偏指数。
static double hypot(double x, double y) 返回sqrt( x 2 + y 2 ),没有中间溢出或下溢。
static double IEEEremainder(double f1, double f2) 根据IEEE 754标准规定,计算两个参数的余数运算。
static int incrementExact(int a) 返回以1递增的参数,如果结果溢出 int则抛出异常。
static long incrementExact(long a) 返回以1递增的参数,如果结果溢出 long则抛出异常。
static double log(double a) 返回 double值的自然对数(基数 e )。
static double log10(double a) 返回 double值的基数10对数。
static double log1p(double x) 返回参数和的总和的自然对数。
static double max(double a, double b) 返回两个 double值中较大的 double 。
static float max(float a, float b) 返回两个 float值中较大的 float 。
static int max(int a, int b) 返回两个 int值中较大的 int 。
static long max(long a, long b) 返回两个 long值中较大的 long 。
static double min(double a, double b) 返回两个 double值中较小的 double 。
static float min(float a, float b) 返回两个 float值中较小的 float 。
static int min(int a, int b) 返回两个 int值中较小的 int 。
static long min(long a, long b) 返回两个 long值中较小的 long 。
static int multiplyExact(int x, int y) 返回参数的乘积,如果结果溢出 int则抛出异常。
static long multiplyExact(long x, int y) 返回参数的乘积,如果结果溢出 long则抛出异常。
static long multiplyExact(long x, long y) 返回参数的乘积,如果结果溢出 long则抛出异常。
static long multiplyFull(int x, int y) 返回参数的确切数学乘积。
static long multiplyHigh(long x, long y) 返回 long作为两个64位因子的128位乘积的最高64位。
static int negateExact(int a) 返回参数的否定,如果结果溢出 int则抛出异常。
static long negateExact(long a) 返回参数的否定,如果结果溢出 long则抛出异常。
static double nextAfter(double start, double direction) 返回第二个参数方向上第一个参数旁边的浮点数。
static float nextAfter(float start, double direction) 返回第二个参数方向上第一个参数旁边的浮点数。
static double nextDown(double d) 返回负无穷大方向上与 d相邻的浮点值。
static float nextDown(float f) 返回负无穷大方向上与 f相邻的浮点值。
static double nextUp(double d) 返回正无穷大方向上与 d相邻的浮点值。
static float nextUp(float f) 返回正无穷大方向上与 f相邻的浮点值。
static double pow(double a, double b) 返回第一个参数的值,该值是第二个参数的幂。
static double random() 返回带有正号的 double值,大于或等于 0.0且小于 1.0 。
static double rint(double a) 返回与 double值最接近的 double值,该值等于数学整数。
static long round(double a) 返回与参数最接近的 long ,并将关系四舍五入为正无穷大。
static int round(float a) 返回与参数最接近的 int ,并将关系四舍五入为正无穷大。
static double scalb(double d, int scaleFactor) 返回 d ×2 scaleFactor舍入,就像通过单个正确舍入的浮点乘以双 scaleFactor值集的成员一样。
static float scalb(float f, int scaleFactor) 返回 f ×2 scaleFactor舍入,就像通过单个正确舍入的浮点乘以浮点值集的成员一样。
static double signum(double d) 返回参数的signum函数; 如果参数为零,则为零;如果参数大于零,则为1.0;如果参数小于零,则为-1.0。
static float signum(float f) 返回参数的signum函数; 如果参数为零则为零,如果参数大于零则为1.0f,如果参数小于零则为-1.0f。
static double sin(double a) 返回角度的三角正弦值。
static double sinh(double x) 返回 double值的双曲正弦值。
static double sqrt(double a) 返回 double值的正确舍入正平方根。
static int subtractExact(int x, int y) 返回参数的差异,如果结果溢出 int则抛出异常。
static long subtractExact(long x, long y) 返回参数的差异,如果结果溢出 long则抛出异常。
static double tan(double a) 返回角度的三角正切。
static double tanh(double x) 返回 double值的双曲正切值。
static double toDegrees(double angrad) 将以弧度测量的角度转换为以度为单位测量的近似等效角度。
static int toIntExact(long value) 返回long参数的值; 如果值溢出int则抛出异常。
static double toRadians(double angdeg) 将以度为单位测量的角度转换为以弧度为单位测量的近似等效角度。
static double ulp(double d) 返回参数的ulp大小。
static float ulp(float f) 返回参数的ulp大小。
源自jdk11的API文档
Arrays
static byte[] copyOf(byte[] original, int newLength) 使用零复制指定的数组,截断或填充(如有必要),以使副本具有指定的长度。
static void sort(char[] a) 将指定的数组按升序排序
static String toString() 返回指定数组内容的字符串表示形式。
static boolean equals(boolean[] a, boolean[] a2) 如果两个指定的布尔数组彼此 相等 ,则返回 true 。
BigDecimal
static BigDecimal valueOf(double val) 转换一个 double成 BigDecimal ,使用 double通过所提供的规范的字符串表示 Double.toString(double)方法。
其他类型的数也可以
String
String(byte[] bytes, int offset, int length, String charsetName) 通过使用指定的字符集解码指定的字节子 String构造新的 String 。
String(byte[] bytes, int offset, int length, Charset charset) 通过使用指定的charset解码指定的字节子String构造新的String 。
String(byte[] bytes, String charsetName) 构造一个新的String由指定用指定的字节的数组解码charset 。
String(byte[] bytes, Charset charset) 构造一个新的String由指定用指定的字节的数组解码charset 。
String(char[] value) 分配新的 String ,使其表示当前包含在字符数组参数中的字符序列。
String(char[] value, int offset, int count) 分配一个新的 String ,其中包含字符数组参数的子数组中的字符。
String(int[] codePoints, int offset, int count) 分配新的 String ,其中包含 Unicode code point数组参数的子数组中的字符。
String(String original) 初始化新创建的String对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。
String(StringBuffer buffer) 分配一个新字符串,其中包含当前包含在字符串缓冲区参数中的字符序列。
String(StringBuilder builder) 分配一个新字符串,其中包含当前包含在字符串构建器参数中的字符序列。
char charAt(int index) 返回指定索引处的 char值。
int compareTo(String anotherString) 按字典顺序比较两个字符串。
static String copyValueOf(char[] data) 相当于 valueOf(char[]) 。
int indexOf(int ch) 返回指定字符第一次出现的字符串中的索引。
int length() 返回此字符串的长度。
static String valueOf(boolean b) 返回 boolean参数的字符串表示形式。
String substring(int beginIndex) 返回一个字符串,该字符串是此字符串的子字符串。
String[] split(String regex, int limit) 将此字符串拆分为给定 regular expression的匹配 项 。
Date
Date() 分配 Date对象并对其进行初始化,使其表示分配时间,测量 Date到毫秒。
Date(long date) 分配 Date对象并初始化它以表示自标准基准时间(称为“纪元”)以来的指定毫秒数,即1970年1月1日00:00:00 GMT。
Date(String s) 已过时。 截至JDK 1.1版,由DateFormat.parse(String s)取代。
void setTime(long date) 使用给定的毫秒时间值设置现有的 Date对象。
LocalDate toLocalDate() 使用此 Date对象中的年,月和日创建 LocalDate实例。
String toString() 以日期转义格式yyyy-mm-dd格式化日期。
static Date valueOf(String s) 将JDBC日期转义格式的字符串转换为 Date值。
static Date valueOf(LocalDate date) 从LocalDate对象获得Date的实例, Date具有相同的年,月和月的值作为给定的LocalDate 。
二.Collections
类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口是使用的最重点的接口。 所有的类集操作的接口或类都在 java.util 包中。
Collections接口
public interface Collection extends Iterable
但是,在开发中不会直接使用 Collection 接口。而使用其操作的子接口:List、Set
方法
Lists接口
方法:
这些是对Collections方法的补充
ArrayLists接口
是比较常用的接口
可以发现,此时的对象数组并没有长度的限制,长度可以任意长,只要是内存够大就行。
常规使用示例
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo02
{
public static void main(String[] args) {
List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型
all.add("hello "); // 增加内容,此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
all.add("world"); // 增加内容,此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是:");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
}
}
}
Vector接口
使用
package org.listdemo.vectordemo;
import java.util.List;
import java.util.Vector;
public class VectorDemo01
{
public static void main(String[] args)
{
List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型
all.add("hello "); // 增加内容,此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
all.add("world"); // 增加内容,此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是:");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
}
}
}
Vector和ArrayLists区别
三.Set
Set 接口也是 Collection 的子接口,与 List 接口最大的不同在于,Set 接口里面的内容是不允许重复的。
那么在此接口中有两个常用的子类:HashSet、TreeSet
Hashset
HashSet 属于散列的存放类集,里面的内容是无序存放的。
public class HashSetDemo01
{ public static void main(String[] args)
{
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
System.out.println(all);
Object obj[] = all.toArray(); // 将集合变为对象数组
for (int x = 0; x < obj.length; x++) {
System.out.print(obj[x] + "、");
}
}
}
Treeset
使用
import java.util.Set;
import java.util.TreeSet;
public class TreeSetDemo01 {
public static void main(String[] args)
{
Set<String> all = new TreeSet<String>(); // 实例化Set接口对象
all.add("D");
all.add("X");
all.add("A");
System.out.println(all);
}
}
如何使用并进行排序?
如果现在要是想进行排序的话,则必须在 Person类中实现 Comparable 接口。
比如用TreeSet实现排序Person
Person类
public class Person implements Comparable<Person>
{
private String name;
private int age;
public int compareTo(Person per)
{
if (this.age > per.age) { return 1; }
else if (this.age < per.age) { return -1; }
else { return 0; }
}
public Person() { }
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String toString() { return "姓名:" + this.name + ",年龄:" + this.age; }
}
测试
import java.util.Set;
import java.util.TreeSet;
public class TreeSetPersonDemo01
{
public static void main(String[] args) {
Set<Person> all = new TreeSet<Person>();
all.add(new Person("张三", 10));
all.add(new Person("李四", 10));
all.add(new Person("王五", 11));
all.add(new Person("赵六", 12));
all.add(new Person("孙七", 13));
System.out.println(all);
}
}
如何去掉重复元素?
此时已经不存在重复元素了,所以如果要想去掉重复元素需要依靠 hashCode()和 equals()方法共同完成
import java.util.HashSet;
import java.util.Set;
public class HashSetPersonDemo01 {
public static void main(String[] args) {
Set<Person> all = new HashSet<Person>();
all.add(new Person("张三", 10));
all.add(new Person("李四", 10));
all.add(new Person("李四", 10));
all.add(new Person("王五", 11));
all.add(new Person("赵六", 12));
all.add(new Person("孙七", 13));
System.out.println(all);
}
}
public boolean equals(Object obj) {
if (this == obj) { return true; }
if (!(obj instanceof Person)) { return false; }
Person per = (Person) obj;
if (per.name.equals(this.name) && per.age == this.age) { return true; }
else {
return false;
}
}
public int hashCode() {
return this.name.hashCode() * this.age;
}
Iterator
方法
但是在使用 Iterator 输出的时候有一点必须注意,在进行迭代输出的时候如果要想删除当前元素,则只能使用 Iterator 接口中的 remove()方法,而不能使用集合中的 remove()方法
错误代码示例:
Collection<String> all = new ArrayList<String>();
Iterator<String> iter = all.iterator();
while (iter.hasNext()) {// 判断是否有下一个元素
String str = iter.next(); // 取出当前元素
if (str.equals("C")) {
iter.remove(); // 错误的,调用了集合中的删除
} else {
System.out.print(str + " ");
}
正确代码
Collection<String> c=。。。。
Iterator<String> i=c.iterator();
while(i.hasNext()){
String s=i.next();//s是使用next()返回的元素
i.remove();//remove方法会删除使用next()方法返回 的元素,也就是s
}
foreach的使用
Collection<String> all = new ArrayList<String>();
all.add("A"); all.add("B"); all.add("C"); all.add("D"); all.add("E");
for (String str : all)
{
System.out.println(str) ;
}
四.Map
以上的 Collection 中,每次操作的都是一个对象,如果现在假设要操作一对对象,则就必须使用 Map 了,类似于以 下一种情况:
· 张三 123456
· 李四 234567
常用方法
Hashmap
此类继承了 AbstractMap 类,同时可以被克隆,可以被序列化下来
查找单元素
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(1, "张三B"); // 新的内容替换掉旧的内容
map.put(2, "李四");
map.put(3, "王五");
String val = map.get(6);
System.out.println(val);
}
查找全部Key或value
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(2, "李四");
map.put(3, "王五");
Set<Integer> set = map.keySet(); // 得到全部的key
Collection<String> value = map.values(); // 得到全部的value
Iterator<Integer> iter1 = set.iterator();
Iterator<String> iter2 = value.iterator();
System.out.print("全部的key:");
while (iter1.hasNext()) {
System.out.print(iter1.next() + "、");
}
System.out.print("\n全部的value:");
while (iter2.hasNext()) {
System.out.print(iter2.next() + "、");
}
}
HashTable
Hashtable 是一个最早的 keyvalue 的操作类,本身是在 JDK1.0的时候推出的。其基本操作与 HashMap 是类似的。
import java.util.Hashtable;
import java.util.Map;
public class HashtableDemo01 {
public static void main(String[] args) {
Map<String, Integer> numbers = new Hashtable<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
Integer n = numbers.get("two");
if (n != null) {
System.out.println("two = " + n);
}
}
}
区别
TreeMap
TreeMap 子类是允许 key 进行排序的操作子类,其本身在操作的时候将按照 key 进行排序,另外,key 中的内容可以 为任意的对象,但是要求对象所在的类必须实现 Comparable 接口。
public static void main(String[] args) {
Map<String, String> map = new TreeMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到单个key
System.out.println(i + " --:> " + map.get(i));
}
}
输出Map元素
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
for (Map.Entry<String, String> me : map.entrySet()) {
System.out.println(me.getKey() + " --> " + me.getValue());
}
}
五.分析 equals、hashCode 与内存泄露
Java 语言对 equals()的要求如下,这些要求是必须遵循的:
- 对称性:如果 x.equals(y)返回是“true”,那么 y.equals(x)也应该返回是“true”。
- 反射性:x.equals(x)必须返回是“true”。
- 类推性:如果 x.equals(y)返回是“true”,而且 y.equals(z)返回是“true”,那么 z.equals(x)也应该返回是“true”。
- 还有一致性:如果 x.equals(y)返回是“true”,只要 x 和 y 内容一直不变,不管你重复 x.equals(y)多少次,返回都是 “true”。
- 任何情况下,x.equals(null),永远返回是“false”;x.equals(和 x 不同类型的对象)永远返回是“false”。
hashCode 的约定(很重要):
- 在一个应用程序执行期间,如果一个对象的 equals 方法做比较所用到的信息没有被修改的话,则对该对象调用 hashCode 方法多次,它必须始终如一地返回同一个整数。
- 如果两个对象根据 equals(Objecto)方法是相等的,则调用这两个对象中任一对象的 hashCode 方法必须产生相同的整 数结果。 3. 如果两个对象根据 equals(Objecto)方法是不相等的,则调用这两个对象中任一个对象的 hashCode 方法,不要求产生 不同的整数结果。但如果能不同,则可能提高散列表的性能。
在 java 的集合中,判断两个对象是否相等的规则是:
(1)判断两个对象的 hashCode 是否相等 如果不相等,认为两个对象也不相等,完毕 如果相等,转入 2 (这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们
这里将其做为必需的。后面会重点讲到这个问题。)
(2)判断两个对象用 equals 运算是否相等 如果不相等,认为两个对象也不相等 如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
五.File
废话不多说,先上个讲ArrayList读入文件和读出文件的代码
写入文件
注意:book类的toString要自己重写,不然后面从文件中拿出一堆字符串的时候不好提取和处理数据
ArrayList<Book> bookArrayList = new ArrayList<>();
Book a1=new Book(1,1,"A",new Date());
Book a2=new Book(1,2,"B",new Date());
bookArrayList.add(a1);
bookArrayList.add(a2);
//创建输出缓冲流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("E:/Test/test.txt"));
for(int i=0;i<bookArrayList.size();i++) {
String line = bookArrayList.get(i).toString();
System.out.println(line);
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
从文件读出
//创建输入缓冲流对象
BufferedReader br = new BufferedReader(new FileReader("E:/Test/test.txt"));
ArrayList<String> array=new ArrayList<String>();
ArrayList<Book> bookArrayList2 = new ArrayList<>();
String bookline=null;
while((bookline = br.readLine()) != null) {
array.add(bookline);
//bookline是从文件中读到的原始字符串(是存入的book类的toString),读到之后再后续进行处理
String[] strs=bookline.split("'");
for(String str:strs)
{
System.out.println("strs为"+str);
}
}
//释放资源
br.close();
for(int x=0;x<array.size();x++) {
System.out.println(array.get(x));
}
File类
构造方法
构造方法摘要
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
File(URI uri) 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。
使用方法
createNewFile() 当且仅当具有此名称的文件尚不存在时,以原子方式创建由此抽象路径名命名的新空文件。
getName() 返回此抽象路径名表示的文件或目录的名称。
getParent() 返回此抽象路径名父项的路径名字符串,如果此路径名未指定父目录,则返回 null 。
getParentFile() 返回此抽象路径名父项的抽象路径名,如果此路径名未指定父目录,则返回 null 。
mkdirs() 创建此抽象路径名指定的目录,包括任何必需但不存在的父目录。
FileInputSteram类
构造方法
FileInputStream(File file) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj) 使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中实际文件的现有连接。
FileInputStream(String name) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的路径名 name命名。
使用方法
read() 从此输入流中读取一个字节的数据。
int read(byte[] b) 从此输入流 b.length最多 b.length字节的数据读 b.length字节数组。
int read(byte[] b, int off, int len) 从此输入流 len最多 len字节的数据读入一个字节数组。
close() 关闭此文件输入流并释放与该流关联的所有系统资源。
FileoutputStream类
构造方法
OutputStream(OutputStream out) 创建在指定的基础输出流之上构建的输出流过滤器。
使用方法
void close() 关闭此输出流并释放与该流关联的所有系统资源。
void flush() 刷新此输出流并强制将任何缓冲的输出字节写出到流中。
void write(byte[] b) 将 b.length个字节写入此输出流。
void write(byte[] b, int off, int len) 将 len字节从指定的 byte数组(从偏移量 off开始)写入此输出流。
void write(int b) 将指定的 byte写入此输出流。
Buffedreader类
构造方法
Reader() 创建一个新的字符流阅读器,其关键部分将在阅读器本身上同步。
Reader(Object lock) 创建一个新的字符流阅读器,其关键部分将在给定对象上同步。
常规的使用方法
close() 关闭流并释放与其关联的所有系统资源。
read() 读一个字符。
int read(char[] cbuf) 将字符读入数组。
abstract int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
int read(CharBuffer target) 尝试将字符读入指定的字符缓冲区。
BuffedWriter类
构造方法
BufferedWriter(Writer out) 创建使用默认大小的输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个使用给定大小的输出缓冲区的新缓冲字符输出流。
常规使用方法
void flush() 刷新流。
void newLine() 写一个行分隔符。
void write(char[] cbuf, int off, int len) 写一个字符数组的一部分。
void write(int c) 写一个字符。
void write(String s, int off, int len) 写一个字符串的一部分。
序列化
****参考博客原址:https://blog.csdn.net/wangloveall/article/details/7992448/
当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
假定一个Student类,它的对象需要序列化,可以有如下三种方法:
方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。
序列化步骤
步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:
ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“D:\objectfile.obj”));
步骤二:通过对象输出流的writeObject()方法写对象:
out.writeObject(“Hello”);
out.writeObject(new Date());
反序列化步骤
步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:
ObjectInputStream in = new ObjectInputStream(new fileInputStream(“D:\objectfile.obj”));
步骤二:通过对象输出流的readObject()方法读取对象:
String obj1 = (String)in.readObject();
Date obj2 = (Date)in.readObject();
编码示例:
有学生类
package com.jieke.io;
import java.io.Serializable;
/**
*Title:学生类
*Description:实现序列化接口的学生类
*Copyright: copyright(c) 2012
*Filename: Student.java
*@author Wang Luqing
*@version 1.0
*/
public class Student implements Serializable
{
private String name;
private char sex;
private int year;
private double gpa;
public Student()
{
}
public Student(String name,char sex,int year,double gpa)
{
this.name = name;
this.sex = sex;
this.year = year;
this.gpa = gpa;
}
public void setName(String name)
{
this.name = name;
}
public void setSex(char sex)
{
this.sex = sex;
}
public void setYear(int year)
{
this.year = year;
}
public void setGpa(double gpa)
{
this.gpa = gpa;
}
public String getName()
{
return this.name;
}
public char getSex()
{
return this.sex;
}
public int getYear()
{
return this.year;
}
public double getGpa()
{
return this.gpa;
}
}
把Student类的对象序列化到文件O:\Java\com\jieke\io\student.txt,并从该文件中反序列化,向console显示结果
import java.io.*;
/**
*Title:应用学生类
*Description:实现学生类实例的序列化与反序列化
*Copyright: copyright(c) 2012
*Filename: UseStudent.java
*@author Wang Luqing
*@version 1.0
*/
public class UseStudent
{
public static void main(String[] args)
{
Student st = new Student("Tom",'M',20,3.6);
File file = new File("O:\\Java\\com\\jieke\\io\\student.txt");
try
{
file.createNewFile();
}
catch(IOException e)
{
e.printStackTrace();
}
try
{
//Student对象序列化过程
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(st);
oos.flush();
oos.close();
fos.close();
//Student对象反序列化过程
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Student st1 = (Student) ois.readObject();
System.out.println("name = " + st1.getName());
System.out.println("sex = " + st1.getSex());
System.out.println("year = " + st1.getYear());
System.out.println("gpa = " + st1.getGpa());
ois.close();
fis.close();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
结果如下:
name = Tom
sex = M
year = 20
gpa = 3.6
采用Java序列化与反序列化技术,一是可以实现数据的持久化,在MVC模式中很是有用;二是可以对象数据的远程通信。
六.多线程
用得少了,就不上代码,简单的把知识点写一下
Callable使用步骤
1. 编写类实现Callable接口 , 实现call方法
class XXX implements Callable<T> {
@Override
public <T> call() throws Exception { return T; }
}
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread,启动线程 new Thread(future).start();
Runnable 与 Callable的相同点
都是接口
都可以编写多线程程序
都采用Thread.start()启动线程
Runnable 与 Callable的不同点
Runnable没有返回值;Callable可以返回执行结果 Callable接口的call()允许抛出异常;Runnable的run()不能抛出
线程与进程
进程
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
线程
是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少 有一个线程 线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分 成若干个线程
同步和异步
同步:排队执行 , 效率低但是安全.
异步:同时执行 , 效率高但是数据不安全.
七.网络编程
网络 编程程序的分类
1.B/S 程序 : 浏览器与服务器程序
2.C/S 程序 : 客户端与服务器程序
TCP 协议 的 C/S程序
ServerSocket
用于创建服务器 . 创建完毕后, 会绑定一个端口号.
然后此服务器可以等待客户端连接 .
每连接一个客户端 , 服务器就会得到一个新的Socket对象, 用于跟客户端进行通信
构造方法
ServerSocket(int port); ****
创建一个基于TCP/IP协议的服务器 , 并绑定指定的端口号. 注意: 参数port的范围是: 0-65535 (建议1025-65535)
常用方法
Socket accept(); **** 等待客户端连接 . 此方法会导致线程的阻塞! 直到一个新的客户端连接成功, return Socket对象后, 线程在继续执行. void close(); 释放占用的端口号 , 关闭服务器
Socket
是两台计算机之间通信的端点 , 是网络驱动提供给应用程序编程的一种接口 一套标准, 一种机制 .
构造方法
Socket(String ip,int port) **** 创建一个套接字, 并连接指定ip和端口号的 服务器. 参数1. 服务器的ip地址 参数2. 服务器软件的端口号…
使用方法
-
OutputStream getOutputStream(); 返回的是 , 指向通信的另一端点的输出流
-
InputStream getInputStream(); 返回的是 , 指向通信的另一端点的输入流 - void close(); 关闭套接字
注意:
在网络编程时, 获取输入输出流的操作 ,对于客户端与服务器来说是相对的
客户端的输入流, 输入的是服务器的输出流 输出的内容.
客户端的输出流, 输出到了服务器的输入流中.
所以 在使用时, 需要注意以下一点规则:
客户端与服务器获取流的顺序必须是相反的:
例如: 客户端先得到了输入流 , 那服务器必须先获取输出流
使用示例:
客户端: //1. 连接服务器
Socket socket = new Socket("127.0.0.1",8888);
//2. 得到输出流
//2.1 得到输出流 OutputStream os = socket.getOutputStream();
//2.2 将输出流, 转换为打印流 PrintStream ps = new PrintStream(os);
//3. 得到输入流
//3.1 得到输入流 InputStream is = socket.getInputStream();
//3.2 将字节输入流, 转换为字符输入流 , 并转换为逐行读取流
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//4. 循环接收用户输入
Scanner input = new Scanner(System.in);
while(true) {
System.out.println("请输入要发送给服务器的内容:");
String text1 = input.nextLine();
//5. 将用户输入的内容, 发送给服务器
ps.println(text1);
//6. 接收服务器回复的消息
String text2 = br.readLine();
System.out.println(text2);
if("886".equals(text1)) {
break;
}
}
服务器:
public static void main(String[] args) throws Exception {
//1. 启动服务器, 并侦听8888端口号
ServerSocket server = new ServerSocket(8888);
//2. 打印提示
System.out.println("服务器已启动 , 等待客户端连接中...");
//3. 等待客户端连接
Socket socket = server.accept();
System.out.println("一个客户端连接成功:"+socket.getInetAddress().toString());
//4. 获取输入流
//4.1 获取输入流
InputStream is = socket.getInputStream();
//4.2 将输入的字节流 ,转换为字符流
InputStreamReader isr = new InputStreamReader(is);
//4.3 将字符流, 转换为逐行读取流
BufferedReader br = new BufferedReader(isr);
//5. 获取输出流
//5.1 获取输出流 OutputStream os = socket.getOutputStream();
//5.2 将字节输出流, 转换为打印流 PrintStream ps = new PrintStream(os);
while(true) {
//6. 循环读取一行行的数据 ,读取操作会导致线程的阻塞, 直到客户端真的发送了数据, //服务器才能接到, 顺序继续执行下面的代码
String text = br.readLine();
//7. 将这个文字, 再打印给客户端
ps.println("服务器:"+text);
if("886".equals(text))
{
break;
}
}
}
综合应用
多线程实现客户端和服务端的简单通信:
快递查询系统
快递类
public class EMAIL {
private int LocationX;//x坐标
private int LocationY;//Y坐标
private String NUMBER;//单号
private String Company;//公司
private String ID;//取件码
public EMAIL(int locationX, int locationY, String NUMBER, String company, String ID) {
LocationX = locationX;
LocationY = locationY;
this.NUMBER = NUMBER;
Company = company;
this.ID = ID;
}
@Override
public String toString() {
String locationx=String.valueOf(LocationX);
String locationy=String.valueOf(LocationY);
return
locationx +'\''+
locationy + '\''+
NUMBER + '\'' +
Company+'\''+
ID+'\'' ;
}
public int getLocationX() {
return LocationX;
}
public void setLocationX(int locationX) {
LocationX = locationX;
}
public int getLocationY() {
return LocationY;
}
public void setLocationY(int locationY) {
LocationY = locationY;
}
public String getNUMBER() {
return NUMBER;
}
public void setNUMBER(String NUMBER) {
this.NUMBER = NUMBER;
}
public String getCompany() {
return Company;
}
public void setCompany(String company) {
Company = company;
}
public String getID() {
return ID;
}
public void setID(String ID) {
this.ID = ID;
}
}
客户端
public class expresscli {
public static void main(String[] args) throws IOException {
Socket client = new Socket("127.0.0.1",9000);
//2. 得到输出流
//2.1 得到输出流
OutputStream os = client.getOutputStream();
//2.2 将输出流, 转换为打印流
PrintStream ps = new PrintStream(os);
//3. 得到输入流
//3.1 得到输入流
InputStream is = client.getInputStream();
//3.2 将字节输入流, 转换为字符输入流 , 并转换为逐行读取流
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//4. 循环接收用户输入
Scanner input = new Scanner(System.in);
//System.out.println("请输入你的身份:1:管理员 2:用户 3:退出图书");
System.out.println("请输入你的身份:1:管理员 2:用户 3:退出");
while(true) {
String text1 = input.nextLine();
//5. 将用户输入的内容, 发送给服务器
ps.println(text1);
//6. 接收服务器回复的消息
String text2 = br.readLine();
System.out.println(text2);
if("成功退出系统".equals(text2)) {
client.close();
break;
}
}
}
}
服务端线程类
public class expressThreadSer implements Runnable{
private Socket accept;
//测试类中传入服务器的侦听accept()侦听到的客户端对象
public expressThreadSer(Socket accept){
this.accept = accept;
}
@Override
public void run() {
try {
expressServer.ServerMethod(accept);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端主要入口main方法
public class expressThreadSerDemo {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9000);
//循环放在此处是为了,当每次客户端与服务器通信完成时,服务器不停止运行,而是又再一次进入侦听状态,侦听是否还有服务器向自己发送信息;
while (true) {
Socket accept = server.accept();
Thread thread = new Thread(new ThreadServer(accept));
thread.start();
}
}
}
服务端主要服务方法ServerMethod
与客户端交互
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class expressServer {
static List<EMAIL> EMAILArrayList=new ArrayList<EMAIL>();
public static void ServerMethod(Socket socket) throws IOException {
/* InputStream in = accept.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s + Thread.currentThread().getName());
OutputStream out = accept.getOutputStream();
out.write("连接成功!".getBytes());
accept.close();*/
BufferedReader br2 = new BufferedReader(new FileReader("E:/Test/test2.txt"));
/* //1. 启动服务器, 并侦听8888端口号
ServerSocket server = new ServerSocket(8890);
//2. 打印提示
System.out.println("服务器已启动 , 等待客户端连接中...");
//3. 等待客户端连接
Socket socket = server.accept();*/
System.out.println("一个客户端连接成功:"+socket.getInetAddress().toString());
//4. 获取输入流
//4.1 获取输入流
InputStream is = socket.getInputStream();
//4.2 将输入的字节流 ,转换为字符流
InputStreamReader isr = new InputStreamReader(is);
//4.3 将字符流, 转换为逐行读取流
BufferedReader br = new BufferedReader(isr);
//5. 获取输出流
//5.1 获取输出流
OutputStream os = socket.getOutputStream();
//5.2 将字节输出流, 转换为打印流
PrintStream ps = new PrintStream(os);
String bookline=null;
ArrayList<String> array=new ArrayList<String>();
while((bookline = br2.readLine()) != null) {
array.add(bookline);
String[] strs=bookline.split("'");
int kk=0;//计数变量
int locationx=0;
int locationy=0;
String NUMBER="";
String COMPANY="";
String ID="";
for(String str:strs)
{
System.out.println("strs为"+str);
//ps.println("strs为"+str);
if(kk==0)
{
locationx=Integer.valueOf(str);
}
else if(kk==1)
{
locationy=Integer.valueOf(str);
}
else if(kk==2)
{
NUMBER=str;
}
else if(kk==3)
{
COMPANY=str;
}
else if(kk==4)
{
ID=str;
}
kk++;
if(kk==5) {
EMAIL email=new EMAIL(locationx,locationy,NUMBER,COMPANY,ID);
EMAILArrayList.add(email);
kk=0;
}
}
}
//释放资源
br2.close();
System.out.println("队列大小为"+EMAILArrayList.size());
for(int x=0;x<EMAILArrayList.size();x++) {
System.out.println("读取成功");
System.out.println(EMAILArrayList.get(x).getNUMBER());
}
String KEY=null;//用户身份标识
while(true)
{
//System.out.println("请输入你的身份:1:管理员 2:用户 3:退出");
System.out.println("进入了身份验证");
KEY=br.readLine();
System.out.println("KEY为"+KEY);
if(KEY.equals("1"))
{
System.out.println("KEY EQUALS 1");
}
else if(KEY.equals("2"))
{
System.out.println("KEY EQUALS 2");
}
else if(KEY.equals("3"))
{
System.out.println("KEY EQUALS 3");
}
if(KEY.equals("1"))
{
//System.out.println("请输入功能:录入物品 删除物品 修改快递 查看快递");
ps.println("请输入功能:录入物品 删除物品 修改快递 查看快递");
String Info=br.readLine();
if(Info.equals("录入物品"))
{
int X=0;//初始化坐标 存储输入的x,y坐标
int Y=0;
while(true)//坐标查重
{
ps.println("请输入物品的x坐标");
String x=br.readLine();
X=Integer.parseInt(x);
ps.println("请输入物品的Y坐标");
String y=br.readLine();
Y=Integer.parseInt(y);
boolean isExist=false;
for(EMAIL EMAIL:EMAILArrayList)
{
if((EMAIL.getLocationY()==X)&&(EMAIL.getLocationY()==Y))
{
isExist=true;
ps.println("坐标重复,请重新输入");
}
}
if(isExist==false)break;
}
ps.println("请输入物品的单号");
String NUMBER=br.readLine();
ps.println("请输入物品公司");
String Company=br.readLine();
String ID=null;
while(true)//取件码查重
{
ps.println("请输入物品取件码");
ID=br.readLine();
boolean isExist=false;
for(EMAIL EMAIL:EMAILArrayList)
{
if(EMAIL.getNUMBER().equals(ID))
{
isExist=true;
ps.println("取件码重复,请重新输入");
}
}
if(isExist==false)break;
}
EMAIL EMAIL=new EMAIL(X,Y,NUMBER,Company,ID);
EMAILArrayList.add(EMAIL);
ps.println("录入成功 请输入你的身份:1:管理员 2:用户 3:退出");
}
else if(Info.equals("删除物品"))
{
ps.println("请输入物品的单号");
String NUMBER=br.readLine();
boolean isDelete=false;//删除是否成功
for(EMAIL EMAIL:EMAILArrayList)
{
if(EMAIL.getNUMBER().equals(NUMBER))
{
ps.println("成功删除物品 请输入你的身份:1:管理员 2:用户 3:退出");
isDelete=true;
EMAILArrayList.remove(EMAIL);
break;
}
}
if(isDelete==false) ps.println("未找到对应物品 请输入你的身份:1:管理员 2:用户 3:退出");
}
else if(Info.equals("修改快递"))
{
ps.println("请输入物品的单号");
String NUMBER=br.readLine();
boolean isUpdate=false;//查找是否成功
for(EMAIL EMAIL:EMAILArrayList)
{
if(EMAIL.getNUMBER().equals(NUMBER))
{
//ps.println("成功查找到物品");
isUpdate=true;
ps.println("成功查找到物品 请输入修改后的快递单号");
String ID=br.readLine();
EMAIL.setNUMBER(ID);
ps.println("修改成功 请输入你的身份:1:管理员 2:用户 3:退出");
break;
}
}
if(isUpdate==false) ps.println("未找到对应物品 请输入你的身份:1:管理员 2:用户 3:退出");
}
else if(Info.equals("查看快递"))
{
System.out.println("进入了查看快递");
for(EMAIL EMAIL:EMAILArrayList)
{
ps.println("快递x坐标为"+EMAIL.getLocationX()+" "+"快递Y坐标为"+EMAIL.getLocationY()+" "+"快递单号为"+EMAIL.getNUMBER()+"快递公司为"+EMAIL.getCompany()+" "+"快递取件码为"+EMAIL.getID()+"按任意键查询下一个");
String space=br.readLine();
/* System.out.print("快递Y坐标为"+EMAIL.getLocationY()+" ");
System.out.print("快递单号为"+EMAIL.getNUMBER()+" ");
System.out.print("快递公司为"+EMAIL.getCompany()+" ");
System.out.println("快递取件码为"+EMAIL.getID());*/
}
System.out.println("查看完成");
ps.println("查询完成 请输入你的身份:1:管理员 2:用户 3:退出");
}
else
{
ps.println("请输入正确的功能 请输入你的身份:1:管理员 2:用户 3:退出");
}
}
else if(KEY.equals("2"))
{
//System.out.println("请输入取件码");
ps.println("请输入取件码");
String ID=br.readLine();
boolean isFind=false;//是否找到
for(EMAIL EMAIL:EMAILArrayList)
{
if(EMAIL.getNUMBER().equals(ID))
{
isFind=true;
/* System.out.println("找到对应物品");
System.out.println("位置为"+EMAIL.getLocationX()+" "+EMAIL.getLocationY());
System.out.println("单号为"+EMAIL.getNUMBER());
System.out.println("公司为"+EMAIL.getCompany());*/
ps.println("找到对应物品"+"位置为"+EMAIL.getLocationX()+" "+EMAIL.getLocationY()+"单号为"+EMAIL.getNUMBER()+"公司为"+EMAIL.getCompany());
EMAILArrayList.remove(EMAIL);
break;
}
}
if(isFind==false)
{
ps.println("没有找到对应物品");
}
}
else if(KEY.equals("3"))
{
// System.out.println("退出系统");
ps.println("成功退出系统");
break;
}
}
//结束存储信息
//创建输出缓冲流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("E:/Test/test2.txt"));
for(int i=0;i<EMAILArrayList.size();i++) {
String line = EMAILArrayList.get(i).toString();
System.out.println(line);
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
}
}