欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java学习笔记_Day023_枚举类型、网络编程、InetAddress、UDP和TCP协议详解

程序员文章站 2024-03-23 14:20:28
...

Java学习笔记_Day023_枚举类型、网络编程、InetAddress、UDP和TCP协议详解

课程内容

  1. 枚举类型
  2. 网络编程
  3. JDK8新特性

一、枚举类型

(一)概述

  1. 就是用于描述对象个数是有限个的类型
  2. 单例设计模式设计出来的类只有一个对象;将单例设计模式的对象个数,从一个变为多个就是枚举(即便是多个对象,对象的个数也是有限的),枚举也可以叫做多例模式。
  3. 声明3、声明一个枚举类型,使用的关键字enum,枚举类型声明出来也是一个类型,编译过后也是一个.class文件,只不过是补充了一些内容

(二)自己实现枚举的第一种格式和使用枚举格式完成

  1. 自己实现:使用【懒汉式第二种方式】,在一个类中多定义几个对象,就是枚举
  2. 枚举实现:
    (1)使用enum关键字声明一个枚举类型
    (2)在枚举类型中,声明罗列各个对象的名称
    (3)在声明罗列各个对象时,对象之间使用逗号隔开,结束用分号结尾
    (4)在枚举类型中的各个对象,叫做【枚举项】

代码示例

package com.csdn.day023;

public class Demo01_FirstStyleBySingleton {

	public static void main(String[] args) {
		System.out.println(Week11.MON);
	}
}

class Week11 {
	
	//构造方法私有化
	private Week11() {}
	
	public static final Week11 MON = new Week11();
	public static final Week11 TUE = new Week11();
	public static final Week11 WED = new Week11();
}


package com.csdn.day023;

public class Demo02_FirstStyleByEnum {

	public static void main(String[] args) {
		System.out.println(Week12.MON);
	}
}

enum Week12 {
	MON, TUE, WED;//枚举项
}

(三)自己实现枚举的第二种格式和使用枚举格式完成

  1. 自己实现:加入一个成员变量

  2. 枚举实现:
    (1)使用enum声明一个枚举类型
    (2)在枚举类型中声明一个成员变量
    (3)可以为成员变量提供get、set方法
    (4)构造方法也可以提供,但必须是私有的
    (5)在枚举类型的第一行,提供枚举项

  3. 注意事项:
    (1)枚举类型中,枚举项必须写在第一行,第一行的标志:第一个分号前
    (2)枚举类型中所有的构造方法必须是私有的

代码示例

package com.csdn.day023;

public class Demo03_SecondStyleBySingleton {

	public static void main(String[] args) {
		Week21 mon = Week21.MON;
		
		System.out.println(mon.getName());
	}
}

class Week21 {
	
	private String name;
	
	//构造方法私有化
	private Week21() {}
	
	private Week21(String name) {
		this.name = name;
	}
	
	public static final Week21 MON = new Week21("星期一");
	public static final Week21 TUE = new Week21("星期二");
	public static final Week21 WED = new Week21("星期三");

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}
package com.csdn.day023;

public class Demo04_SecondStyleByEnum {

	public static void main(String[] args) {
		Week22 mon = Week22.MON;
		
		System.out.println(mon.getName());
	}
}

/*
 * 注意事项:
 * 1.枚举类型中,所有的枚举项,必须要写在第一行,
 * 第一行的标志,是第一个分号之前	
 * 2.枚举类型中,可以有成员变量,构造方法,成员方法,
 * 但是,构造方法必须是私有
 * 
 * */
enum Week22 {
	MON("星期一"), TUE("星期二"), WED("星期三");
	
	private String name;//枚举类型中,所有的枚举项,必须要写在第一行,第一行的标志,是第一个分号之前	
	
	private Week22(){}
	
	private Week22(String name){
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

(四)(四)自己实现枚举的第三种格式和使用枚举格式完成

  1. 自己实现:在类中,再添加一个抽象方法
  2. 枚举实现:
    (1)使用enum声明一个枚举类型
    (2)在枚举类型中,声明一个成员变量
    (3)提供成员变量的get、set方法
    (4)枚举类型中定义一个抽象方法
    (5)枚举项必须写在第一行,并且,枚举项使用匿名内部类的格式实现枚举类型中的抽象方法

代码示例

package com.csdn.day023;

public class Demo05_ThirdStyleBySingleton {

	public static void main(String[] args) {
		Week31 mon = Week31.MON;
		
		mon.printName();
	}
}

abstract class Week31 {
	
	private String name;
	
	//构造方法私有化
	private Week31() {}
	
	private Week31(String name) {
		this.name = name;
	}
	
	public static final Week31 MON = new Week31("星期一") {

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	};
	
	public static final Week31 TUE = new Week31("星期二") {

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	};
	
	public static final Week31 WED = new Week31("星期三") {

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	};

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public abstract void printName();
}
package com.csdn.day023;

public class Demo06_ThirdStyleByEnum {

	public static void main(String[] args) {
		Week32 mon = Week32.MON;
		
		mon.printName();
	}
}

enum Week32 {
	//如果枚举类型中出现了抽象方法,必须通过枚举项集合匿名内部类的格式将抽象方法实现
	MON("星期一") {

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	}, 
	
	TUE("星期二"){

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	}, 
	
	WED("星期三"){

		@Override
		public void printName() {
			System.out.println(getName());
		}
		
	};
	
	private String name;
	
	private Week32() {}
	
	private Week32(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public abstract void printName();
}

(五)枚举实现的常用方法

  1. 所有使用enum关键字声明的枚举类型,全都是Enum类型的子类
  2. 常用方法:
    (1)compareTo(E o) 比较两个枚举类型的顺序
    (2)ordinal() 返回枚举常量的序数
    (3)toString() 返回枚举项的名称,该方法在Enum类中已经重写过了,自定义的enum无法重写
    (4)values() 返回一个数组,数组中的元素是枚举类型的所有枚举项(API中没有,在编译的时候由系统提供,是一个静态方法)

代码示例

package com.csdn.day023;

public class Demo07_EnumMethod {

	public static void main(String[] args) {
		
		Week mon = Week.MON;
		Week tue = Week.TUE;
		Week wed = Week.WED;
		
		System.out.println(mon.compareTo(tue));
		System.out.println(mon.compareTo(wed));
		
		System.out.println(mon.ordinal());
		System.out.println(tue.ordinal());
		System.out.println(wed.ordinal());
		
		System.out.println(mon.toString());
		
		Week[] values = Week.values();
		
		for (Week week : values) {
			System.out.println(week);
		}
	}
}

enum Week {
	MON("星期一"), TUE, WED;
	
	private String name;
	
	private Week() {}
	
	private Week(String name) {
		this.name = name;
	}
}

二、网络编程

  1. 网络:全称:计算机网络,由在不同的地理位置、不同的计算机互联形成的一个计算机系统。
  2. 网络编程:在已经拥有的完备成熟的网络系统中,在整个系统之上,使用网络进行编程,是针对应用层的设计活动。

三、网络编程的三要素

(一)概述

  1. 在网络编程中,必须要使用的三个基本的通信数据
  2. IP地址、端口号、通信协议

(二)IP地址

  1. IP地址是计算机在网络中的唯一标志
  2. 分类:
    (1)IPV4:
    ①构成:点分十进制的构成,由4个0~255的数组组成,来表示一个IP地址,4个字节即32位,能够表示约40亿个IP地址
    ②四个字节中,有2个字节或者3个字节表示所在的子网
    ③一个字节能表示0~255一共256个数字,但是不能全用
    ④0表示子网网号:192.168.1.0就表示当前子网
    ⑤255表示广播地址:广播地址发送的内容所在子网内的所有设备都能接收
    ⑥特殊IP:127.0.0.1,表示本地回环地址,可以访问本机
    ⑦相关命令:ipconfig查看当前网卡信息
    ⑧ping:可以产看网络是否联通
    (2)IPV6:
    ①构成:由8组数字组成,每组数字都是4个16进制数字,每个数字有16中状态,32个数字,最多能表示16^32个IP地址
    ②号称能给地球上每一粒沙子都给一个IP地址

(三)端口号

  1. 也是一个数字,用于标记一台电脑中的某个进程
  2. 端口号的取值范围:0~65535
  3. 意味着计算机中至多能够运行65536个进程,当程序运行的时候,计算机会分配一个独一无二的端口号给进程,我们通过端口号,就可以找到指定的进程,当进程结束时,端口号会被回收
  4. 分配:可以计算机随机分配,也可以用户指定
  5. 常用的端口号:
    (1)操作系统:0~1024之间
    (2)MySQL:3306
    (3)Tomcat:8080
    (4)QQ:4000
    (5)Oracle:1521

(四)通信协议

  1. 用于定义通信双方在交互时,对信息的封装和解析的规则,就是协议
  2. 网络分层:分工,每一层都可以做独立的事情
    (1)应用层:http、https协议等(规定数据如何封装以及解析)
    (2)传输层:UDP协议、TCP协议(更多关注的是端对端的传输)
    (3)网络层:IP地址(如何完成两台设备之间的传输)
    (4)物理层:底层的硬件设备、数据完整性的校验

四、InetAddress

  1. InetAddress类的对象表示IP地址

  2. 对象获取方式:
    (1)getByName(String host) 根据主机名称返回对象包含IP地址
    (2)getByAddress(byte[] addr) 给定装有ip地址的数组,返回InetAddress类对象
    (3)getAllByName(String host) 根据主机明后才能获取所有当前类型对象的数组
    (4)getLocalHost() 获取本机的主机名和IP地址的对象

  3. 常用方法:
    (1)getHostName() 获取主机名称
    (2)getAddress() 获取IP地址的字节数组
    (3)toString() 获取主机名称和IP地址的字符串表示形式

代码示例

package com.csdn.day023;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Demo08_InetAddress {

	public static void main(String[] args) throws UnknownHostException {
		InetAddress host = InetAddress.getLocalHost();
		
		System.out.println(host.getHostName());
		
		byte[] arr = host.getAddress();
		
		for (byte b : arr) {
			System.out.println(b);
		}
		
		System.out.println(host.toString());
	}

	public static void test1() throws UnknownHostException {
		InetAddress name = InetAddress.getByName("Zihuatanejo-PC");
		System.out.println(name);
		
		
		byte[] arr = {10, 10, 60, (byte) 177};
		InetAddress address = InetAddress.getByAddress(arr);
		System.out.println(address);
		
		InetAddress[] arr1 = InetAddress.getAllByName("Zihuatanejo-PC");
		for (InetAddress ele : arr1) {
			System.out.println(ele);
		}
		
		InetAddress host = InetAddress.getLocalHost();
		System.out.println(host);
	}
}

五、UDP协议和TCP协议

(一)概述

  1. UDP协议和TCP协议都是传输层协议,都是端到端的协议
  2. 区别:
    (1)UDP协议:面向无连接。像发短信、送信、寄快递等都是面向无连接。效率高,不安全,先发送的消息未必先收到。只区分发送端和接收端,而不像TCP协议区分客户端和服务器端。
    (2)TCP协议:面向连接。打电话,先发送的消息一定先到达,安全,效率低,区分客户端和服务器端。在连接的时候,要经理三次握手。

(二)Socket编程

  1. Socket:是两台计算机之间的通信端,类似生活中的快递站、邮局、码头
  2. Socket也叫作套接字,套接字编程:网络编程、通信点编程
    (1)UDP中要是用到的套接字是:DatagramSocket
    (2)在TCP协议中,客户端要使用的是Socket,服务器端要是用的是ServerSocket和Socket

(三)UDP编程

  1. 要用到的通信点:DatagramSocket
  2. 构造方法:
    (1)DatagramSocket() 不指定端口号,直接创建通信点对象,端口号随机分配,一般用于发送端
    (2)DatagramSocket(int port) 指定端口号,创建通信点对象,一般用于接收端
  3. 成员方法:
    (1)send(DatagramPacket p) 将一个数据报包进行发送
    (2)receive(DatagramPacket p) 从通信点接收数据报包
  4. 数据
    (1)构造方法:
    ①DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 发送端
    buf:要发送的数据的字节数组
    offset:从数组的哪个位置开始发送数据
    length:发送多少数据
    address:IP地址
    port:端口号
    ②DatagramPacket(byte[] buf, int length) 接收端
    (2)成员方法:
    ①getData() 将接收到的byte[]数组从数据报包中解析出来
    ②getLength() 返回发送了或者接收到的数据的长度

代码示例

package com.csdn.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDP_Send {

	public static void main(String[] args) throws IOException {
		//1.创建发送端的通信点对象
		DatagramSocket ds = new DatagramSocket();
		
		//2.准备数据报包
		byte[] buf = "我请你吃大肠刺身".getBytes();
		int offset = 0;
		int length = buf.length;
		InetAddress address = InetAddress.getLocalHost();
		int port = 8848;
		
		DatagramPacket dp = new DatagramPacket(buf, offset, length, address, port);
		
		//3.通过通信点对象将数据报包发送出去
		ds.send(dp);
	}
}

package com.csdn.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDP_Receive {
	
	public static void main(String[] args) throws IOException {
		//1.创建接收端的通信点对象
		DatagramSocket ds = new DatagramSocket(8848);
		
		//2.使用通信点对象接受网络中的数据
		byte[] buf = new byte[1024];
		int length = buf.length;
		DatagramPacket dp = new DatagramPacket(buf, length);
		
		ds.receive(dp);
		
		//3.从数据报包中将数据解析出来
		byte[] data = dp.getData();
		int len = dp.getLength();
		
		//4.打印数据
		System.out.println(new String(data, 0, len));
	}
}

(四)TCP编程

  1. 客户端要使用的是Socket,服务器端要是用的是ServerSocket和Socket
  2. 客户端和服务器端Socket对象的区别:
    (1)客户端使用Socket的构造方法直接创建Socket对象
    (2)服务器端不能直接使用Socket创建通信点对象,而是通过ServerSocket对象,从端口捕获客户端的响应,专门为这个客户端生成一个Socket对象
  3. 构造方法:
    (1)Socket(InetAddress address, int port) 创建一个通信点对象,专门用于和制定IP的主机中指定的进程进行通信
    (2)只要这个对象创建成功,就说明这个连接已经建立好了,也就说明客户端已经连接上了服务器端了,也就已经获取到了服务器返回的响应了
    (3)创建对象的过程,就是在请求和服务器连接的过程
    (4)ServerSocket(int port) 创建一个服务器通信点对象
    (5)ServerSocket要配合accept()方法使用
    (6)accept()方法是专门用于接收客户端请求,并且返回一个对应Socket对象的方法
  4. 传输操作:
    (1)getOutputStream() 返回此套接字的输出流
    (2)getInputStream() 返回此套接字的输入流
    (3)一旦获取到IO流对象,就变成了以IO的方式传输
  5. 关系:
    (1)客户端发送请求给服务器:客户端将请求从本机内存输出到网络,要用输出流
    (2)服务器接收客户端传来的响应:服务器将网络中的请求读取到服务器的内存,要用输入流

代码示例

package com.csdn.tcp;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class TCP_Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		//1.创建Socket对象,即客户端通信点对象
		Socket s = new Socket("127.0.0.1", 9999);
		
		//2.获取输出流对象,用于将请求从客户端内存传入网络
		OutputStream os = s.getOutputStream();
		
		//3.使用输出流将要传输的内容进行输出
		byte[] b = "松活弹抖闪电鞭".getBytes();
		os.write(b);
		
		s.close();
	}
}

package com.csdn.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCP_Server {
	
	public static void main(String[] args) throws IOException {
		//1.创建服务器套接字对象,绑定到指定端口
		ServerSocket ss = new ServerSocket(9999);
		
		//2.调用accept方法捕获并且针对当前客户端创建Socket对象
		Socket s = ss.accept();
		
		//3.获取套接字的输入流对象,用于将网络中的请求,输入进服务器的内存中
		InputStream is = s.getInputStream();
		
		byte[] b = new byte[1024];
		int len = is.read(b);
		
		//4.将请求解析为文字并打印
		String request = new String(b, 0, len);
		
		System.out.println(request);
		
		s.close();
	}
}

(五)TCP加强

  1. 让客户端也能接受数据,让服务端也能发送数据
  2. 我们既然发送的都是文字,不妨将字节流通过转换加强成高效缓冲字符流,并且发送的数据,通过键盘录入
  3. 让服务器开启多线程

代码示例

package com.csdn.tcpplus;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class TCP_ClientPlus {
	
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1.创建Socket对象
		Socket s = new Socket(InetAddress.getLocalHost(), 9898);
		
		//2.获取输入流和输出流对象
		//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		//3.键盘录入要发送的请求,通过高效缓冲字符输出流发送出去
		Scanner sc = new Scanner(System.in);
		
		String request = sc.nextLine();
		pw.println(request);
		
		//4.通过高效缓冲字符输入流用于读取请求
		String response = br.readLine();
		
		System.out.println(response);
		
		s.close();
	}
}

package com.csdn.tcpplus;

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.Scanner;

public class TCP_ServerPlus {
	
	public static void main(String[] args) throws IOException {
		
		//1.创建ServerSocket对象用于监听端口号
		ServerSocket ss = new ServerSocket(9898);
		
		while (true) {
			//2.调用accept方法获取请求并建立连接
			Socket s = ss.accept();
			
			new Thread() {

				@Override
				public void run() {

					try {
						//3.获取流对象
						BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
						PrintWriter pw = new PrintWriter(s.getOutputStream(), true);

						//4.输入流读取请求
						String request = br.readLine();

						System.out.println(request);

						//5.键盘录入响应并通过流进行返回
						Scanner sc = new Scanner(System.in);

						String response = sc.nextLine();
						pw.println(response);

						s.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
	}
}

总结:网络编程在后期开发中起着举足轻重的作用,一定要好好理解编写格式,枚举类型也非常重要,一定要多加练习!