21 字符流与字节流+22 多线程+23 网络编程

第10天 IO流

今日内容介绍
 标准输入流 & 转换流 & 打印流
 对象操作流
 Properties集合

第1章标准输入流 & 转换流 & 打印流

1.1标准输入输出流
public static final InputStream in:标准输入流
public static final PrintStream out:标准输出流

 package com.itheima_05;
/** 标准输入输出流:public static final InputStream in:字节输入流,用来读取键盘录入的数据public static final int x;InputStream is = System.in;Scanner sc = new Scanner(System.in);public static final PrintStream out:字节输出流,将数据输出到命令行System.out.println();*/
public class SystemInOutDemo {}1.2转换流
1.2.1OutputStreamWriter:将字节输出流转换为字符输出流
1.2.1.1案例代码一:package com.itheima_05;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;/** 需求:读取项目根目录下的SystemInOutDemo.java,并输出到命令行* * 数据源:项目根目录下的SystemInOutDemo.java  BufferedReader* 目的地:命令行  System.out* * * 由于标准输出流是一个字节输出流,所以只能输出字节或者字节数组,但是我们读取到的数据则是字符串,如果想进行输出还需要转换成字节数组* 我们要想通过标准输出流输出字符串,把标准输出流转换成一种字符输出流即可,OutputStreamWriter* * OutputStreamWriter(OutputStream out) :转换流,把字节输出流转换成字符输出流* * */
public class OutputStreamWriterDemo {public static void main(String[] args) throws IOException   {//method2();//创建输入流对象BufferedReader br = new BufferedReader(new FileReader("SystemInOutDemo.java"));//创建输出流对象//OutputStream os = System.out;//Writer w = new OutputStreamWriter(System.out);//多态,父类型引用指向子类对象//BufferedWriter bw = new BufferedWriter(w);BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));//进行数据的读写String line;//用于存储读取到的数据while((line = br.readLine()) != null) {bw.write(line);bw.newLine();}//释放资源bw.close();br.close();}private static void method2() throws FileNotFoundException, IOException {//创建输入流对象BufferedReader br = new BufferedReader(new FileReader("SystemInOutDemo.java"));//创建输出流对象//OutputStream os = System.out;Writer w = new OutputStreamWriter(System.out);//多态,父类型引用指向子类对象//进行数据的读写String line;//用于存储读取到的数据while((line = br.readLine()) != null) {w.write(line);w.write("\r\n");}//释放资源w.close();br.close();}private static void method() throws FileNotFoundException, IOException {//创建输入流对象BufferedReader br = new BufferedReader(new FileReader("SystemInOutDemo.java"));//创建输出流对象OutputStream os = System.out;String line;//用于存储读取到的数据while((line = br.readLine()) != null) {os.write(line.getBytes());os.write("\r\n".getBytes());}//释放资源os.close();br.close();}
}

1.2.2InputStreamReader:将字节输入流转换为字符输入流
1.2.2.1案例代码二:

package com.itheima_05;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;/** 需求:读取键盘录入的数据,并输出到项目根目录下的a.txt文件中* * 数据源:读取键盘录入的数据    System.in* 目的地:项目根目录下的a.txt  FileWriter* * * * 转换流:需要把字节输入流转换成字符输入流,InputStreamReader* InputStreamReader(InputStream in) */
public class InputStreamReaderDemo {public static void main(String[] args) throws IOException  {//创建输入流对象InputStream is = System.in;Reader r = new InputStreamReader(is);//创建输出流对象FileWriter fw = new FileWriter("a.txt");//读写数据char[] chs = new char[1024];int len;while((len = r.read(chs)) != -1) {fw.write(chs,0,len);fw.flush();}//释放资源fw.close();is.close();}private static void method() throws IOException {//创建输入流对象InputStream is = System.in;//创建输出流对象FileWriter fw = new FileWriter("a.txt");//读写数据byte[] bys = new byte[1024];int len;//用于存储读取到的字节个数while((len = is.read(bys)) != -1) {fw.write(new String(bys,0,len));fw.flush();}//释放资源fw.close();is.close();}
}

1.3打印流
打印流添加输出数据的功能,使它们能够方便地打印各种数据值表示形式.
字符打印流 PrintWriter
void print(String str): 输出任意类型的数据,
void println(String str): 输出任意类型的数据,自动写入换行操作
1.3.1案例代码三:

package com.itheima_06;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;/** 打印流:*         PrintStream*        PrintWriter*            可以自动换行,println()*            不能输出字节,但是可以输出其他任意类型*             通过某些配置,可以实现自动刷新(只有在调用 println、printf 或 format才有用)*             也是包装流,不具备写出功能*           可以把字节输出流转换成字符输出流* * 注意:只能输出不能输入* *  */
public class PrintWriterDemo {public static void main(String[] args) throws IOException  {//创建打印流对象PrintWriter pw = new PrintWriter("b.txt");//写出数据pw.write("hello");pw.write("world");pw.write("java");//释放资源pw.close();}
}

1.3.2案例代码四:
利用打印流实现自动换行与自动更新

package com.itheima_06;import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;/*
* 打印流的特有功能:
*       自动换行 使用方法println()实现自动换行
*       自动刷新  创建PrintWriter对象时启动自动刷新开关,并且使用println等3个方法可以实现自动刷新
*
* 注意:创建FileWriter对象时boolean参数是是否追加,
*       而创建打印流对象的boolean类型参数是是否自动刷新
*/
public class PrintWriterDemo2 {public static void main(String[] args) throws IOException  {//method();//创建打印流对象//PrintWriter pw = new PrintWriter("d.txt");PrintWriter pw = new PrintWriter(new FileWriter("d.txt"),true);pw.println("hello");pw.println("world");pw.println("java");//释放资源//pw.close();}private static void method() throws FileNotFoundException {//创建打印流对象PrintWriter pw = new PrintWriter("c.txt");/*pw.write("hello");pw.write("world");pw.write("java");*/pw.print("hello");pw.println("world");pw.println("java");//释放资源pw.close();}
}

1.3.3案例代码五:
利用打印流将根目录下的SystemInOutDemo.java复制到d:\SystemInOutDemo.java下

package com.itheima_06;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;/** 使用打印流复制文本文件* * 数据源   SystemInOutDemo.java    BufferedReader* 目的地 d:\\SystemInOutDemo.java    PrintWriter* */
public class PrintWriterDemo3 {public static void main(String[] args) throws IOException  {//创建输入流对象BufferedReader br = new BufferedReader(new FileReader("SystemInOutDemo.java"));//创建打印流对象PrintWriter pw = new PrintWriter(new FileWriter("d:\\SystemInOutDemo.java"),true);String line;//用于存储读取到的每行数据while((line = br.readLine()) != null) {pw.println(line);}//释放资源pw.close();br.close();}}

第2章对象操作流

2.1概述
用于从流中读取对象的
ObjectInputStream 称为 反序列化流,利用输入流从文件中读取对象
ObjectOutputStream 称为 序列化流,利用输出流向文件中写入对象
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。

package com.itheima_07;
/*  * 对象操作流:可以用于读写任意类型的对象*       ObjectOutputStream*                 writeObject *               ObjectOutputStream(OutputStream out) *      ObjectInputStream*              readObject*                 ObjectInputStream(InputStream in)* * 注意:*        使用对象输出流写出对象,只能使用对象输入流来读取对象*      只能将支持 java.io.Serializable 接口的对象写入流中* */
public class ObjectOutputStreamDemo2 {public static void main(String[] args)  {}}
2.2利用序列化流读写对象
package com.itheima_07;import java.io.Serializable;public class Student implements Serializable {/*** */String name;int age;public Student(String name,int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age +"]";}
}package com.itheima_07;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;/*    * 使用对象输出流和读对象输入流写对象* Exception in thread "main" java.io.NotSerializableException: com.itheima_07.Student* Serializable:序列号,是一个标识接口,只起标识作用,没有方法*              当一个类的对象需要IO流进行读写的时候,这个类必须实现该接口* * Exception in thread "main" java.io.EOFException:当输入过程中意外到达文件或流的末尾时,抛出此异常。* */
public class ObjectOutputStreamDemo {public static void main(String[] args) throws IOException, ClassNotFoundException  {//method();//创建对象输入流的对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));//读取对象/*Object obj = ois.readObject();System.out.println(obj);Object obj2 = ois.readObject();System.out.println(obj2);Object obj3 = ois.readObject();System.out.println(obj3);*/try {while(true) {Object obj = ois.readObject();System.out.println(obj);}} catch(EOFException e) {System.out.println("读到了文件的末尾");}//释放资源ois.close();}private static void method() throws IOException, FileNotFoundException {//创建对象输出流的对象//FileOutputStream fos = new FileOutputStream("a.txt");//ObjectOutputStream oos = new ObjectOutputStream(fos);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));//创建学生对象Student s = new Student("zhangsan",18);Student s2 = new Student("lisi",19);//写出学生对象oos.writeObject(s);oos.writeObject(s2);//释放资源oos.close();}}

2.2.1案例代码六:

package com.itheima_02;import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;/** 使用字符流复制文本文件* * 数据源       IODemo.java* 目的地        d:\\IODemo.java*    */
public class FileCopyDemo {public static void main(String[] args) throws IOException  {//创建字符输入流对象FileReader fr = new FileReader("IODemo.java");//创建字符输出流对象FileWriter fw = new FileWriter("d:\\IODemo.java");//一次读写一个字符/*int ch;while((ch = fr.read()) != -1) {fw.write(ch);fw.flush();}*///一次读写一个字符数组int len;//用于存储读到的字符个数char[] chs = new char[1024];while((len = fr.read(chs)) != -1) {fw.write(chs,0,len);fw.flush();}//释放资源fw.close();fr.close();}
}

2.3解决对象输入流读取对象出现异常的问题
2.3.1案例代码七:

package com.itheima_07;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;/** 解决对象输入流读取对象出现异常的问题* */
public class ObjectOutputStreamDemo3 {public static void main(String[] args) throws IOException, ClassNotFoundException   {//method();//创建对象输入流的对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("b.txt"));//读取数据Object obj = ois.readObject(); //System.out.println(obj);//向下转型,获取具体的子类对象ArrayList<Student> list = (ArrayList<Student>) obj;for (Student student : list) {System.out.println(student);}//释放资源ois.close();}private static void method() throws IOException, FileNotFoundException {//创建对象输出流的对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("b.txt"));//创建集合对象ArrayList<Student> list = new ArrayList<Student>();//添加学生对象list.add(new Student("wangwu",30));list.add(new Student("zhaoliu",28));//写出集合对象oos.writeObject(list);//释放资源oos.close();}
}

2.4解决读写对象版本不一致问题

2.4.1案例代码八:

package com.itheima_07;import java.io.Serializable;public class Student implements Serializable {/*** */private static final long serialVersionUID = 6361890890437825953L;String name;int age;String gender;public Student(String name,int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";}}package com.itheima_07;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;/** 解决对实现序列化接口出现的黄色警告问题* Exception in thread "main" java.io.InvalidClassException* 当 Serialization 运行时检测到某个类具有以下问题之一时,抛出此异常。 该类的序列版本号与从流中读取的类描述符的版本号不匹配 该类包含未知数据类型 该类没有可访问的无参数构造方法 * */
public class ObjectOutputStreamDemo4 {public static void main(String[] args) throws IOException, ClassNotFoundException  {//method();method2();}//读取学生对象private static void method2() throws IOException, FileNotFoundException, ClassNotFoundException {//创建对象输入流的对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c.txt"));//读取对象Object obj = ois.readObject();System.out.println(obj);//释放资源ois.close();}//写出学生对象private static void method() throws IOException, FileNotFoundException {//创建对象输出流的对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c.txt"));//创建的学生对象Student s = new Student("qianqi",28);//写出学生对象oos.writeObject(s);//释放资源oos.close();}}

第3章Properties集合

3.1Properties介绍
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
特点:
1、Hashtable的子类,map集合中的方法都可以用。
2、该集合没有泛型。键值都是字符串。
3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
4、有和流技术相结合的方法。

3.2利用Properties存储键值对
3.2.1案例代码九:

   package com.itheima_08;import java.util.Map;
import java.util.Properties;
import java.util.Set;/** Properties:表示了一个持久的属性集,属性列表中每个键及其对应值都是一个字符串* * 构造方法:*         Properties() */
public class PropertiesDemo2 {public static void main(String[] args) {//创建属性列表对象Properties prop = new Properties();//添加映射关系prop.put("CZBK001", "zhangsan");prop.put("CZBK002", "lisi");prop.put("CZBK003", "wangwu");//遍历属性列表//获取所有的key,通过key获取valueSet<Object> keys = prop.keySet();for (Object key : keys) {Object value = prop.get(key);System.out.println(key + "=" + value);}System.out.println("------------------");//获取所有的结婚证对象Set<Map.Entry<Object,Object>> entrys = prop.entrySet();for (Map.Entry<Object, Object> entry : entrys) {Object key = entry.getKey();Object value = entry.getValue();System.out.println(key + "=" + value);}}
}

3.3Properties与流结合使用
3.3.1案例代码十:

package com.itheima_08;import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;/** Properties和IO流结合的功能: void load(Reader reader) void list(PrintWriter out)void store(Writer writer, String comments) **/
public class PropertiesDemo2 {public static void main(String[] args) throws IOException{//method();//method2();//创建属性列表对象Properties prop = new Properties();//添加映射关系prop.setProperty("CZBK001", "zhangsan");prop.setProperty("CZBK002", "lisi");prop.setProperty("CZBK003", "wangwu");//创建输出流对象FileWriter fw = new FileWriter("e.txt");//void store(Writer writer, String comments) prop.store(fw, "hello world");//释放资源fw.close();}private static void method2() throws FileNotFoundException, IOException {//创建属性列表对象Properties prop = new Properties();//创建一个输入流对象FileReader fr = new FileReader("d.txt");//void load(Reader reader) prop.load(fr);//释放资源fr.close();System.out.println(prop);}private static void method() throws FileNotFoundException {//创建属性列表对象Properties prop = new Properties();//添加映射关系prop.setProperty("CZBK001", "zhangsan");prop.setProperty("CZBK002", "lisi");prop.setProperty("CZBK003", "wangwu");//创建打印流对象PrintWriter out = new PrintWriter("d.txt");//void list(PrintWriter out)  prop.list(out);//释放资源out.close();}
}

第4章编码表

4.1编码表的概述
编码表:把计算机底层的二进制数据转换成我们能看到的字符

  •  ASCII
    
  •  GB2312 --- GBK
    
  •  Unicode 所有的字符都占2个字节
    
  •  UTF-8   长度可变的码表
    
  • ANSI:本地编码表 gbk
  • Java中的字符串默认使用的ANSI(gbk)
  • 乱码:编码保持前后一致即可解决
    4.2Java中字符串的编码
    4.2.1常用方法
    构造方法(字节数组转字符串):
    String():初始化一个新创建的 String 对象,使其表示一个空字符序列
    String(byte[] bytes) 使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
    String(byte[] bytes, Charset charset) 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
    成员方法(字符串转字节数组)
    getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
    getBytes(Charset charset) 使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组

4.2.2案例代码十一

package com.itheima_09;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;/** 编码表:把计算机底层的二进制数据转换成我们能看到的字符*         ASCII* *        GB2312  --- GBK*        Unicode 所有的字符都占2个字节*        UTF-8   长度可变的码表* * ANSI:本地编码表    gbk* Java中的字符串默认使用的ANSI(gbk)* * 乱码:编码保持前后一致即可解决* */
public class EncoderDemo {public static void main(String[] args) throws IOException   {//method();FileInputStream fis = new FileInputStream("a.txt");byte[] bys = new byte[1024];int len = fis.read(bys);//System.out.println(new String(bys,0,len));System.out.println(new String(bys,0,len,"UTF-8"));}private static void method() throws UnsupportedEncodingException, FileNotFoundException, IOException {String s = "高薪就业";//byte[] bys = s.getBytes();//通过默认编码转换成数组byte[] bys = s.getBytes("UTF-8");FileOutputStream fos = new FileOutputStream("a.txt");fos.write(bys);fos.close();}}

4.3字符流中的编码
4.3.1常见对象
InputStreamReader(InputStream in, CharsetDecoder dec) 创建使用给定字符集解码器的 InputStreamReader

OutputStreamWriter(OutputStream out, CharsetEncoder enc) 创建使用给定字符集编码器的 OutputStreamWriter
4.3.2案例代码十二

package com.itheima_09;import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;/** 字符流中的编码* * 字符流 = 字节流 + 编码* */
public class EncoderDemo2 {public static void main(String[] args) throws IOException {//method();OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8");//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));String s = "迎娶白富美";osw.write(s);osw.close();}private static void method() throws IOException, UnsupportedEncodingException {FileWriter fw = new FileWriter("b.txt");String s = "月薪过万";byte[] bys = s.getBytes("UTF-8");//fw.write(s);fw.write(new String(bys));fw.close();}}

第11天 多线程

今日内容介绍
 多线程概述
 线程实现
 多线程安全问题产生 & 解决方案

第1章 多线程概述

学习多线程之前,我们先要了解几个关于多线程有关的概念。
A:进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
B:线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
C:简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
什么是多线程呢?即就是一个程序中有多个线程在同时执行。

第2章线程实现

2.1实现线程一:继承Thread类
该如何创建线程呢?通过API中搜索,查到Thread类。通过阅读Thread类中的描述。Thread是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

A:创建线程的步骤:
1.定义一个类继承Thread。
2.重写run方法。
3.创建子类对象,就是创建线程对象。
4.调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法
2.1.1案例代码一:

package com.itheima_01;public class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}}
}package com.itheima_01;
/** 多线程的实现方式:*       方式1:一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例* * Thread*        String getName()      返回该线程的名称。 *       void   setName(String name) 改变线程名称,使之与参数 name 相同。* * * CPU执行程序的随机性*/
public class ThreadDemo2 {public static void main(String[] args) {//创建线程实例MyThread mt = new MyThread();//修改线程名字mt.setName("张三");//启动线程mt.start();//创建线程实例MyThread mt2 = new MyThread();mt2.setName("老王");//启动线程mt2.start();}
}

2.2实现线程二:实现Runnable接口
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。
为何要实现Runnable接口,Runable是啥玩意呢?继续API搜索。
查看Runnable接口说明文档:Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法,需要由接口实现类重写该方法。

创建线程的步骤。
1、定义类实现Runnable接口。
2、覆盖接口中的run方法。。
3、创建Thread类的对象
4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
5、调用Thread类的start方法开启线程。
2.2.1案例代码二:

package com.itheima_02;public class MyThread2 implements Runnable {int num;public MyThread2(int num) {this.num = num;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {//Thread t = Thread.currentThread();//System.out.println(t.getName() + ":" + i);//链式编程System.out.println(Thread.currentThread().getName() + ":" + i + num);}}}

第3章多线程安全问题产生&解决方案

3.1多线程卖票案例
需求:用三个线程模拟三个售票窗口,共同卖100张火车票,每个线程打印出卖第几张票
3.1.1 案例代码三:

 package com.itheima_03;
public class TicketThread implements Runnable {int tickets = 100;//火车票数量@Overridepublic void run() {//出售火车票while(true) {//当火车票小于0张,则停止售票if(tickets > 0) {/** t1,t2,t3* 假设只剩一张票* t1过来了,他一看有票,他就进来了,但是他突然肚子不舒服,然后他就去上卫生间了* t2也过来了,他一看也有票,他也进来了,但是他的肚子也不舒服,他也去上卫生间了* * t1上完了卫生间回来了,开始售票*    tickets = 0;* t2也上完卫生间回来了,他也进行售票*  tickets = -1;* * */try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" +tickets--);}}}}

3.2多线程安全问题解决
3.2.1使用同步代码块解决
格式:
synchronized(锁对象){
//需要同步的代码
}

3.2.1.1案例代码四:

   package com.itheima_04;
/** 问题出现的原因:*        要有多个线程*         要有被多个线程所共享的数据*      多个线程并发的访问共享的数据* * 在火车上上厕所* 张三来了,一看门是绿的,他就进去了,把门锁上了,门就变红了* 李四来了,一看门市红色的,他就只能憋着* 张三用完了厕所,把锁打开了,门就变成了绿色* 李四一看门变绿了,他就进去了,把门锁上,门就变红了* 王五来了,一看们是红色的,他也只能憋着* 李四用完测试了,把锁打开了,肚子又不舒服了,扭头回去了,又把门锁上了,* * synchronized:同步(锁),可以修饰代码块和方法,被修饰的代码块和方法一旦被某个线程访问,则直接锁住,其他的线程将无法访问* * 同步代码块:*           synchronized(锁对象){* *           }* * 注意:锁对象需要被所有的线程所共享* * * 同步:安全性高,效率低* 非同步:效率高,但是安全性低* */
public class TicketThread implements Runnable {int tickets = 100;//火车票数量Object obj = new Object();@Overridepublic void run() {//出售火车票while(true) {synchronized (obj) {if(tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" +tickets--);}}}}}
package com.itheima_04;public class TicktetTest {public static void main(String[] args) {//创建线程对象TicketThread tt = new TicketThread();Thread t = new Thread(tt);t.setName("窗口1");Thread t2 = new Thread(tt);t2.setName("窗口2");Thread t3 = new Thread(tt);t3.setName("窗口3");//启动线程对象t.start();t2.start();t3.start();}
}

3.2.2使用同步方法解决
格式:
修饰符 synchronized 返回值 方法名(){

}
3.2.2.1案例代码五:

package com.itheima_05;
/** 同步方法:使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部锁住,其他线程则无法访问* * synchronized* 注意:*         非静态同步方法的锁对象是this*       静态的同步方法的锁对象是当前类的字节码对象*/
public class TicketThread implements Runnable {static int tickets = 100;// 火车票数量Object obj = new Object();@Overridepublic void run() {// 出售火车票while (true) {/*synchronized (obj) {method();}*///method();method2();}}private synchronized void method() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + tickets--);}}private static synchronized void method2() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + tickets--);}}}
package com.itheima_05;public class TicktetTest {public static void main(String[] args) {//创建线程对象TicketThread tt = new TicketThread();Thread t = new Thread(tt);t.setName("窗口1");Thread t2 = new Thread(tt);t2.setName("窗口2");Thread t3 = new Thread(tt);t3.setName("窗口3");//启动线程对象t.start();t2.start();t3.start();}
}

3.3线程生命周期图


第11天 面向网络编程

今日内容介绍
 网络编程概述
 UDP
 TCP

第1章网络编程概述

1.1网络协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
网络通信协议有很多种,目前应用最广泛的是TCP/IP协议(Transmission Control Protocal/Internet Protoal传输控制协议/英特网互联协议),它是一个包括TCP协议和IP协议,UDP(User Datagram Protocol)协议和其它一些协议的协议组,在学习具体协议之前首先了解一下TCP/IP协议组的层次结构。
在进行数据传输时,要求发送的数据与收到的数据完全一样,这时,就需要在原有的数据上添加很多信息,以保证数据在传输过程中数据格式完全一致。TCP/IP协议的层次结构比较简单,共分为四层,如图所示。

图1-1TCP/IP网络模型
上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解。
链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。

1.2IP地址和端口号
要想使网络中的计算机能够进行通信,必须为每台计算机指定一个标识号,通过这个标识号来指定接受数据的计算机或者发送数据的计算机。
在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,如:00001010000000000000000000000001。由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,如 “192.168.1.100”。
随着计算机网络规模的不断扩大,对IP地址的需求也越来越多,IPV4这种用4个字节表示的IP地址面临枯竭,因此IPv6 便应运而生了,IPv6使用16个字节表示IP地址,它所拥有的地址容量约是IPv4的8×1028倍,达到2128个(算上全零的),这样就解决了网络地址资源数量不够的问题。
通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。在计算机中,不同的应用程序是通过端口号区分的。端口号是用两个字节(16位的二进制数)表示的,它的取值范围是065535,其中,01023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用。
接下来通过一个图例来描述IP地址和端口号的作用,如下图所示。

从上图中可以清楚地看到,位于网络中一台计算机可以通过IP地址去访问另一台计算机,并通过端口号访问目标计算机中的某个应用程序。
1.3InetAddress
了解了IP地址的作用,我们看学习下JDK中提供了一个InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法,下表中列出了InetAddress类的一些常用方法。

1.3.1案例代码一:

  package com.itheima_01;import java.net.InetAddress;
import java.net.UnknownHostException;/** InetAddress:此类表示互联网协议 (IP) 地址。 * */
public class InetAddressDemo {public static void main(String[] args) throws UnknownHostException   {//static InetAddress getByName(String host) //InetAddress address = InetAddress.getByName("itheima");InetAddress address = InetAddress.getByName("192.168.1.107");//ip地址是唯一的//System.out.println(address);//itheima/192.168.1.107 ipconfigString hostAddress = address.getHostAddress();//192.168.1.107 返回IP地址String hostName = address.getHostName();//itheima 返回主机名System.out.println(hostAddress);System.out.println(hostName);}
}

第2章UDP协议

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP的交换过程如下图所示。

2.1DatagramPacket
前面介绍了UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。UDP通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接收货物时都需要使用集装箱来装载货物,UDP通信也是一样,发送和接收的数据也需要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。
想要创建一个DatagramPacket对象,首先需要了解一下它的构造方法。在创建发送端和接收端的DatagramPacket对象时,使用的构造方法有所不同,接收端的构造方法只需要接收一个字节数组来存放接收到的数据,而发送端的构造方法不但要接收存放了发送数据的字节数组,还需要指定发送端IP地址和端口号。
接下来根据API文档的内容,对DatagramPacket的构造方法进行逐一详细地讲解。

使用该构造方法在创建DatagramPacket对象时,指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号。很明显,这样的对象只能用于接收端,不能用于发送端。因为发送端一定要明确指出数据的目的地(ip地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数据即可。

使用该构造方法在创建DatagramPacket对象时,不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(address)和端口号(port)。该对象通常用于发送端,因为在发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。
上面我们讲解了DatagramPacket的构造方法,接下来对DatagramPacket类中的常用方法进行详细地讲解,如下表所示。

2.2DatagramSocket
DatagramPacket数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还需要有码头。在程序中需要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包,发送数据的过程如下图所示。

在创建发送端和接收端的DatagramSocket对象时,使用的构造方法也有所不同,下面对DatagramSocket类中常用的构造方法进行讲解。

该构造方法用于创建发送端的DatagramSocket对象,在创建DatagramSocket对象时,并没有指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。

该构造方法既可用于创建接收端的DatagramSocket对象,又可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。
上面我们讲解了DatagramSocket的构造方法,接下来对DatagramSocket类中的常用方法进行详细地讲解。

2.3UDP实现
2.3.1案例代码二:

 package com.itheima_02;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;/** 使用UDP协议发送数据创建发送端Socket对象创建数据并打包发送数据释放资源* * DatagramSocket:此类表示用来发送和接收数据,基于UDP协议的* * DatagramSocket() :创建Socket对象并随机分配端口号* DatagramSocket(int port) :创建Socket对象并指定端口号*/
public class SendDemo {public static void main(String[] args) throws IOException  {//创建发送端Socket对象DatagramSocket ds = new DatagramSocket();//创建数据并打包/** DatagramPacket :此类表示数据报包* 数据 byte[]* 设备的地址 ip* 进程的地址  端口号DatagramPacket(byte[] buf, int length, InetAddress address, int port) */String s = "hello udp,im comming!";byte[] bys = s.getBytes();int length = bys.length;InetAddress address = InetAddress.getByName("itheima");//发送给当前设备int port = 8888;//打包DatagramPacket dp = new DatagramPacket(bys,length,address,port);//发送数据ds.send(dp);//释放资源ds.close();}
}
package com.itheima_02;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;/** 使用UDP协议接收数据创建接收端Socket对象接收数据解析数据输出数据释放资源*/
public class ReceiveDemo {public static void main(String[] args) throws IOException {//创建接收端Socket对象DatagramSocket ds = new DatagramSocket(8888);//接收数据//DatagramPacket(byte[] buf, int length) byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys,bys.length);System.out.println(1);ds.receive(dp);//阻塞System.out.println(2);//解析数据//InetAddress getAddress() : 获取发送端的IP对象InetAddress address = dp.getAddress();//byte[] getData()  :获取接收到的数据,也可以直接使用创建包对象时的数组byte[] data = dp.getData();//int getLength()  :获取具体收到数据的长度int length = dp.getLength();//输出数据System.out.println("sender ---> " + address.getHostAddress());//System.out.println(new String(data,0,length));System.out.println(new String(bys,0,length));//释放资源ds.close();}
}

第3章TCP协议

TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建socket对象。
区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。
而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。
3.1ServerSocket
通过前面的学习知道,在开发TCP程序时,首先需要创建服务器端程序。JDK的java.net包中提供了一个ServerSocket类,该类的实例对象可以实现一个服务器段的程序。通过查阅API文档可知,ServerSocket类提供了多种构造方法,接下来就对ServerSocket的构造方法进行逐一地讲解。

使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。
接下来学习一下ServerSocket的常用方法,如表所示。

ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。
3.2Socket
讲解了ServerSocket对象可以实现服务端程序,但只实现服务器端程序还不能完成通信,此时还需要一个客户端程序与之交互,为此JDK提供了一个Socket类,用于实现TCP客户端程序。
通过查阅API文档可知Socket类同样提供了多种构造方法,接下来就对Socket的常用构造方法进行详细讲解。

使用该构造方法在创建Socket对象时,会根据参数去连接在指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串类型的IP地址。

该方法在使用上与第二个构造方法类似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。
在以上Socket的构造方法中,最常用的是第一个构造方法。
接下来学习一下Socket的常用方法,如表所示。
方法声明 功能描述
int getPort() 该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号
InetAddress getLocalAddress() 该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回
void close() 该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源
InputStream getInputStream() 该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据
OutputStream getOutputStream() 该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据
在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。
接下来通过一张图来描述服务器端和客户端的数据传输,如下图所示。

3.3TCP协议实现
3.3.1案例代码三:

package com.itheima_04;import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;/** 使用TCP协议发送数据创建发送端Socket对象(创建连接)获取输出流对象发送数据释放资源Socket(InetAddress address, int port) Exception in thread "main" java.net.ConnectException: Connection refused: connect*/
public class ClientDemo {public static void main(String[] args) throws IOException {//创建发送端Socket对象(创建连接)Socket s = new Socket(InetAddress.getByName("itheima"),10086);//获取输出流对象OutputStream os = s.getOutputStream();//发送数据String str = "hello tcp,im comming!!!";os.write(str.getBytes());//释放资源//os.close();s.close();}
}
package com.itheima_04;import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;/** 使用TCP协议接收数据创建接收端Socket对象监听(阻塞)获取输入流对象获取数据输出数据释放资源ServerSocket:接收端,服务端SocketServerSocket(int port) Socket accept() */
public class ServerDemo {public static void main(String[] args) throws IOException  {//创建接收端Socket对象ServerSocket ss = new ServerSocket(10086);//监听(阻塞)Socket s = ss.accept();//获取输入流对象InputStream is = s.getInputStream();//获取数据byte[] bys = new byte[1024];int len;//用于存储读到的字节个数len = is.read(bys);//输出数据InetAddress address = s.getInetAddress();System.out.println("client ---> " + address.getHostName());System.out.println(new String(bys,0,len));//释放资源s.close();//ss.close();}
}

3.4TCP相关案例
3.4.1案例代码四:
使用TCP协议发送数据,服务端将接收到的数据转换成大写返回给客户端

package com.itheima_05;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;/*需求:使用TCP协议发送数据,并将接收到的数据转换成大写返回客户端发出数据服务端接收数据服务端转换数据服务端发出数据客户端接收数据*/
public class ClientDemo {public static void main(String[] args) throws IOException {//创建客户端Socket对象Socket s = new Socket(InetAddress.getByName("itheima"),10010);//获取输出流对象OutputStream os = s.getOutputStream();//发出数据os.write("tcp,im comming again!!!".getBytes());//获取输入流对象InputStream is = s.getInputStream();byte[] bys = new byte[1024];int len;//用于存储读取到的字节个数//接收数据len = is.read(bys);//输出数据System.out.println(new String(bys,0,len));//释放资源s.close();}
}
package com.itheima_05;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerDemo {public static void main(String[] args) throws IOException {//创建服务端Socket对象ServerSocket ss = new ServerSocket(10010);//监听Socket s = ss.accept();//获取输入流对象InputStream is = s.getInputStream();//获取数据byte[] bys = new byte[1024];int len;//用于存储读取到的字节个数len = is.read(bys);String str = new String(bys,0,len);//输出数据System.out.println(str);//转换数据String upperStr = str.toUpperCase();//获取输出流对象OutputStream os = s.getOutputStream();//返回数据(发出数据)os.write(upperStr.getBytes());//释放资源s.close();//ss.close();//服务端一般不关闭}
}

3.4.2案例代码五:
客户端:
1.提示用户输入用户名和密码,将用户输入的用户名和密码发送给服务端
2.接收服务端验证完用户名和密码的结果
服务端:
1.接收客户端发送过来的用户名和密码
2.如果用户名不是itheima或者 密码不是123456,就向客户端写入”登录失败”
否则向客户端写入登录成功

package com.itheima_06;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;/** 模拟用户登录*/
public class ClientTest {public static void main(String[] args) throws  IOException  {//创建客户端Socket对象//Socket s = new Socket(InetAddress.getByName("itheima"),8888);Socket s = new Socket("itheima",8888);//获取用户名和密码BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入用户名:");String username = br.readLine();System.out.println("请输入密码:");String password = br.readLine();//获取输出流对象//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));PrintWriter out = new PrintWriter(s.getOutputStream(),true);//写出数据out.println(username);out.println(password);//获取输入流对象BufferedReader serverBr = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取服务器返回的数据String result = serverBr.readLine();System.out.println(result);//释放资源s.close();}
}
package com.itheima_06;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;public class ServerTest {public static void main(String[] args) throws IOException {//创建服务器端Socket对象ServerSocket ss = new ServerSocket(8888);//监听Socket s = ss.accept();//获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取用户名和密码String username = br.readLine();String password = br.readLine();//判断用户名和密码是否正确boolean flag = false;if("itheima".equals(username) && "123456".equals(password)) {flag = true;}//获取输出流对象PrintWriter out = new PrintWriter(s.getOutputStream(),true);//返回判断信息if(flag) {out.println("登陆成功");}else {out.println("登陆失败");}//释放资源s.close();//ss.close();//服务器一般不关闭}
}

3.4.3案例代码六:

 将用户名和密码封装到一个User类中,提供对应的构造方法和getter/setter方法新建一个UserDB类里面定义一个集合,在集合中添加以下User对象
new User("zhangsan","123456");new User("lisi","654321");new User("itheima","itheima");new User("admin","password");客户端:
1.提示用户输入用户名和密码,将用户输入的用户名和密码发送给服务端
2.接收服务端验证完用户名和密码的结果服务端:
1.服务端将客户端发送过来的用户名密码封装成User对象
2.集合中如果包括这个User对象,想客户端写入” 登录成功”
否则向客户端写入”登录失败”package com.itheima_07;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;/** 模拟用户登录改写(面向对象版本)*/
public class ClientTest {public static void main(String[] args) throws  IOException  {//创建客户端Socket对象Socket s = new Socket("itheima",8888);//获取用户名和密码BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入用户名:");String username = br.readLine();System.out.println("请输入密码:");String password = br.readLine();//获取输出流对象PrintWriter out = new PrintWriter(s.getOutputStream(),true);//写出数据out.println(username);out.println(password);//获取输入流对象BufferedReader serverBr = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取服务器返回的数据String result = serverBr.readLine();System.out.println(result);//释放资源s.close();}
}
package com.itheima_07;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;public class ServerTest {public static void main(String[] args) throws IOException {//创建服务器端Socket对象ServerSocket ss = new ServerSocket(8888);//监听Socket s = ss.accept();//获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取用户名和密码String username = br.readLine();String password = br.readLine();//判断用户名和密码是否正确boolean flag = false;/*if("itheima".equals(username) && "123456".equals(password)) {flag = true;}*/List<User> users = UserDB.getUsers();User user = new User(username,password);if(users.contains(user)) {//匹配成功flag = true;}//获取输出流对象PrintWriter out = new PrintWriter(s.getOutputStream(),true);//返回判断信息if(flag) {out.println("登陆成功");}else {out.println("登陆失败");}//释放资源s.close();//ss.close();//服务器一般不关闭}
}

笔记整理5----Java语言高级(五--完结)21 字符流与字节流+22 多线程+23 网络编程相关推荐

  1. Java语言高级(第四部分)File类与IO流 ->(个人学习记录笔记)

    文章目录 第六章 File类与IO流 1. File类 1.1 概述 1.2 构造方法 1.3 常用方法 获取功能的方法 绝对路径和相对路径 判断功能的方法 创建删除功能的方法 1.4 目录的遍历 2 ...

  2. Kubernetes、C语言小白变怪兽、C++ Primer Plus、TCP/IP网络编程、JavaScript高级程序设计

    Kubernetes.C语言小白变怪兽.C++ Primer Plus.TCP/IP网络编程.JavaScript高级程序设计 链接:https://pan.baidu.com/s/1EkSjIT0F ...

  3. Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)

    Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...

  4. Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制)

    原文:Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制) 异常机制和File类 异常机制 基本概念 异常就是"不正常"的含义,在 Java 语言中主要指 ...

  5. android xml java混合编程_Java学习中注解与多线程,网络编程与XML技术

    本部分内容主要有集合框架及泛型,实用类,输入和输出处理,注解与多线程,网络编程与XML技术.初次学习这部分会感觉很难,主要是概念难于理解,最好是多看看例子,多练习.下面是个人的总结 拉勾IT课小编为大 ...

  6. java 字符流与字节流区别_JAVA 字符流与字节流的区别

    Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...

  7. java binaryreader_Java字符流与字节流区别与用法分析

    本文实例讲述了Java字符流与字节流区别与用法.分享给大家供大家参考,具体如下: 字节流与字符流主要的区别是他们的的处理方式 流分类: 1.Java的字节流 InputStream是所有字节输入流的祖 ...

  8. java中字符流 字节流_理解Java中字符流与字节流的区别

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个"流动的方向",通常可 ...

  9. Java多线程与网络编程综合使用

    处理多线程与网络编程最为经典的例子莫过于聊天室,那我就聊天室案例作为一个回顾. 首先,我们来看以下代码: package MultiTCP;import java.io.DataOutputStrea ...

最新文章

  1. docker stats命令源码分析结果
  2. windows系统禁止更改服务启动类型_Win10系统关闭自动更新方法
  3. go get如何删除_Go 每日一库之 xorm
  4. AJAX ControlToolkit学习日志-Tabs(27)
  5. 专注于 web报表, web打印, 自定义web表单, web工作流管理系统 方面的技术
  6. c语言中不带任何修饰符的浮点变量,江苏省计算机等级考试二级C语言笔试辅导题目...
  7. 2013第39周一Web打印
  8. Broadleaf概念
  9. python—多进程的消息队列
  10. 信号与系统【奥本海目】第二版笔记
  11. Babelua 调试
  12. 攻防世界——MISC——pdf
  13. BZOJ3717 [PA2014]Pakowanie
  14. Hbuilder和HbuilderX连接夜神模拟器(nox),调试程序
  15. C++递归完成汉诺塔游戏(超详细解读)
  16. 记录微博图床403解决方法
  17. 【报告分享】轻食餐饮发展指南——从入门到可持续经营-美团(附下载)
  18. 京东淘宝手机销售量排行
  19. 人工智能——离线情况下自动给视频添加字幕,支持中文,英文,日文等等
  20. Chrome Extension 介绍

热门文章

  1. 滚筒洗衣机尺寸 2022
  2. Weather Guru 2.3.8 中文版 菜单栏天气预报小工具
  3. 面试问为什么跳槽,该怎么回答?
  4. 关于 App Store 苹果商店价格的那些事(历上最全版)
  5. GTD待办事项管理器都有那些功能
  6. 国产论坛系统 Discuz! 收藏该软件 我的收藏夹/设置
  7. RISC-V架构解析
  8. 小昭的早晨——微信小程序开发伊始
  9. c语言检测状态是否变化,C语言数组状态研究
  10. 目标检测: Camvid 语义标签转化为bbox标签