Java学习笔记_Day023_枚举类型、网络编程、InetAddress、UDP和TCP协议详解
程序员文章站
2024-03-23 14:20:28
...
Java学习笔记_Day023_枚举类型、网络编程、InetAddress、UDP和TCP协议详解
课程内容
- 枚举类型
- 网络编程
- JDK8新特性
一、枚举类型
(一)概述
- 就是用于描述对象个数是有限个的类型
- 单例设计模式设计出来的类只有一个对象;将单例设计模式的对象个数,从一个变为多个就是枚举(即便是多个对象,对象的个数也是有限的),枚举也可以叫做多例模式。
- 声明3、声明一个枚举类型,使用的关键字enum,枚举类型声明出来也是一个类型,编译过后也是一个.class文件,只不过是补充了一些内容
(二)自己实现枚举的第一种格式和使用枚举格式完成
- 自己实现:使用【懒汉式第二种方式】,在一个类中多定义几个对象,就是枚举
- 枚举实现:
(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)使用enum声明一个枚举类型
(2)在枚举类型中声明一个成员变量
(3)可以为成员变量提供get、set方法
(4)构造方法也可以提供,但必须是私有的
(5)在枚举类型的第一行,提供枚举项 -
注意事项:
(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)使用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();
}
(五)枚举实现的常用方法
- 所有使用enum关键字声明的枚举类型,全都是Enum类型的子类
- 常用方法:
(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;
}
}
二、网络编程
- 网络:全称:计算机网络,由在不同的地理位置、不同的计算机互联形成的一个计算机系统。
- 网络编程:在已经拥有的完备成熟的网络系统中,在整个系统之上,使用网络进行编程,是针对应用层的设计活动。
三、网络编程的三要素
(一)概述
- 在网络编程中,必须要使用的三个基本的通信数据
- IP地址、端口号、通信协议
(二)IP地址
- IP地址是计算机在网络中的唯一标志
- 分类:
(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地址
(三)端口号
- 也是一个数字,用于标记一台电脑中的某个进程
- 端口号的取值范围:0~65535
- 意味着计算机中至多能够运行65536个进程,当程序运行的时候,计算机会分配一个独一无二的端口号给进程,我们通过端口号,就可以找到指定的进程,当进程结束时,端口号会被回收
- 分配:可以计算机随机分配,也可以用户指定
- 常用的端口号:
(1)操作系统:0~1024之间
(2)MySQL:3306
(3)Tomcat:8080
(4)QQ:4000
(5)Oracle:1521
(四)通信协议
- 用于定义通信双方在交互时,对信息的封装和解析的规则,就是协议
- 网络分层:分工,每一层都可以做独立的事情
(1)应用层:http、https协议等(规定数据如何封装以及解析)
(2)传输层:UDP协议、TCP协议(更多关注的是端对端的传输)
(3)网络层:IP地址(如何完成两台设备之间的传输)
(4)物理层:底层的硬件设备、数据完整性的校验
四、InetAddress
-
InetAddress类的对象表示IP地址
-
对象获取方式:
(1)getByName(String host) 根据主机名称返回对象包含IP地址
(2)getByAddress(byte[] addr) 给定装有ip地址的数组,返回InetAddress类对象
(3)getAllByName(String host) 根据主机明后才能获取所有当前类型对象的数组
(4)getLocalHost() 获取本机的主机名和IP地址的对象 -
常用方法:
(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协议
(一)概述
- UDP协议和TCP协议都是传输层协议,都是端到端的协议
- 区别:
(1)UDP协议:面向无连接。像发短信、送信、寄快递等都是面向无连接。效率高,不安全,先发送的消息未必先收到。只区分发送端和接收端,而不像TCP协议区分客户端和服务器端。
(2)TCP协议:面向连接。打电话,先发送的消息一定先到达,安全,效率低,区分客户端和服务器端。在连接的时候,要经理三次握手。
(二)Socket编程
- Socket:是两台计算机之间的通信端,类似生活中的快递站、邮局、码头
- Socket也叫作套接字,套接字编程:网络编程、通信点编程
(1)UDP中要是用到的套接字是:DatagramSocket
(2)在TCP协议中,客户端要使用的是Socket,服务器端要是用的是ServerSocket和Socket
(三)UDP编程
- 要用到的通信点:DatagramSocket
- 构造方法:
(1)DatagramSocket() 不指定端口号,直接创建通信点对象,端口号随机分配,一般用于发送端
(2)DatagramSocket(int port) 指定端口号,创建通信点对象,一般用于接收端 - 成员方法:
(1)send(DatagramPacket p) 将一个数据报包进行发送
(2)receive(DatagramPacket p) 从通信点接收数据报包 - 数据
(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编程
- 客户端要使用的是Socket,服务器端要是用的是ServerSocket和Socket
- 客户端和服务器端Socket对象的区别:
(1)客户端使用Socket的构造方法直接创建Socket对象
(2)服务器端不能直接使用Socket创建通信点对象,而是通过ServerSocket对象,从端口捕获客户端的响应,专门为这个客户端生成一个Socket对象 - 构造方法:
(1)Socket(InetAddress address, int port) 创建一个通信点对象,专门用于和制定IP的主机中指定的进程进行通信
(2)只要这个对象创建成功,就说明这个连接已经建立好了,也就说明客户端已经连接上了服务器端了,也就已经获取到了服务器返回的响应了
(3)创建对象的过程,就是在请求和服务器连接的过程
(4)ServerSocket(int port) 创建一个服务器通信点对象
(5)ServerSocket要配合accept()方法使用
(6)accept()方法是专门用于接收客户端请求,并且返回一个对应Socket对象的方法 - 传输操作:
(1)getOutputStream() 返回此套接字的输出流
(2)getInputStream() 返回此套接字的输入流
(3)一旦获取到IO流对象,就变成了以IO的方式传输 - 关系:
(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加强
- 让客户端也能接受数据,让服务端也能发送数据
- 我们既然发送的都是文字,不妨将字节流通过转换加强成高效缓冲字符流,并且发送的数据,通过键盘录入
- 让服务器开启多线程
代码示例
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();
}
}
}
总结:网络编程在后期开发中起着举足轻重的作用,一定要好好理解编写格式,枚举类型也非常重要,一定要多加练习!
上一篇: java基础之引用数据类型
下一篇: 基础类型和引用类型的区别