枚举,网络编程

淺唱寂寞╮ 提交于 2019-12-19 04:15:05

枚举

枚举: 列举出 有穷序列集
枚举类其实用了多例模式,枚举类的实例是有范围限制的。
enum类,反编译后就是一个 class 继承了Enum(注意:我们不能显示继承这个Enum),如果枚举类里定义了抽象方法,他就是abstract类,如果没有抽象方法,他就由final修饰。final修饰的类不能被继承

enum Gender{
	MALE,FEMALE;
}

反编译后大概是这样,必须看

public final class Gender extends java.lang.Enum {
 
  public static final Gender Male;
  public static final Gender Female;
  //为了确保只有固定个数对象且不能被修改,所以用static final修饰
 
  private static final Gender[] $VALUES;
 //这个是一个放所有枚举对象的数组,用values可以获取到。在编译阶段由编译器添加的,包括values()方法
 
  static {//静态代码块,加载类的时候,就挨个创建每个枚举对象,并放进数组里。
    Male = new Gender("Male", 0);
    Female = new Gender("Female", 1);
 
    $VALUES = new Gender[] {Male, Female};
  }

  //编译器会把构造方法设置成下面这样,name是对应的名字,original是索引,从0开始。继承的Enum类中有对应的方法获取名字和索引
  private Gender(String name, int original) {
    super(name, original)
  }
 
 //这个就是编译器加的values方法,clone()的拓展在后边
  public static Gender[] values() {
    return $VALUE.clone();
  }
 
 //返回相同名字的枚举对象
  public static Gender valueOf(String name) {
    return Enum.valueOf(Gender.class, name);
  }
}复制代码

枚举类的书写格式:
1》关键字 enum 表示该类是一个枚举类。
2》该类的第一行写对象的名称,多个对象之间用逗号隔开,最后用分号结束该语句。
3》其他的类的成员都放在对象的下面。
4》如果自定义构造方法,构造方法的权限修饰符是private。
5》该类可以有属性。

values()方法不是Enum类中继承的,是编译器加的静态方法,所以,如果将enum实例向上转型为父类Enum时,values()就找不到了。
valueOf(Class<T> enumType, String name)返回带指定名称的指定枚举类型的枚举常量。
他的compareTo()是比较的枚举对象的索引差值

枚举帖子全: https://blog.csdn.net/weixin_34403693/article/details/91438731

clone()
浅拷贝:我们clone的对象和新对象不是同一对象。但是对象中的引用类型属性的引用是一样的。举例,对象a的数组属性跟克隆的aClone对象的数组属性是同一个。
深拷贝:拷贝的对象及引用类型都不一样。怎么实现?就是引用类型也复制一个放进新对象里。具体看下边这个帖子

clone()拓展:https://blog.csdn.net/xinghuo0007/article/details/78896726

网络编程

InetAddress 描述ip地址的类

获取InetAddress对象方式:
getByName(String host) 根据给定的主机名获取对象
getByAddress()根据ip地址的字节数组获取当前类型对象
getLocalHost() 返回本地主机地址

InetAddress ip = InetAddress.getByName("192.168.123.123");
InetAddress ip2 = InetAddress.getLocalHost();

对象使用方法:
getHostName() 返回主机名称
getHostAddress() 返回ip地址的数字的表示形式
getAddress():获取ip地址的字节数组。

String address = ip.getHostAddress();
String name = ip.getHostName();
byte[] bytes = ip.getAddress();

UDP编程

Java提供的UDP的类:
DatagramSocket 发送端和接收端
DatagramPacket 数据报包
常用方法:
① DatagramSocket() 创建一个数据报包的端点。
② DatagramPacket(byte[] buf, int length, InetAddress address, int port)
发送端需要携带ip地址与端口号,来创建数据报包,接收可不写
注意 : address 表示目的地的电脑的ip地址
port 表示目的地的端口号。
默认数据报包大小不能超过64k。
③send(DatagramPacket p) 发送数据报包。
④ receive(DatagramPacket p) 接收数据
⑤ getLength() 返回接收或者发送的字节数组的读取的数据的长度。

UDP简单的聊天
端口1:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Chat1 {
   private static final String host1 = "10.10.18.148";
   private static final int port1 = 9000;
   private static final int port2 = 9001;
   
   public static void main(String[] args) throws IOException {

   	Scanner scanner = new Scanner(System.in);
   	// 获取Socket对象
   	DatagramSocket socket = new DatagramSocket(port2);
   	boolean flag= true;
   	FutureTask<Object> ft = new FutureTask<Object>(new Callable<Object>() {
   		@Override
   		public Object call() throws Exception {
   			while(flag){
   				//接收
   				byte[] recive = new byte[1024];
   				DatagramPacket pa1 = new DatagramPacket(recive, recive.length);
   				socket.receive(pa1);
   				int len = 0;
   				if ((len = pa1.getLength()) > 0) {
   					System.out.println(pa1.getAddress()+"-9001端口说:"+new String(recive,0,pa1.getLength()));
   				}
   			}
   			return null;
   		}
   	});
   	new Thread(ft).start();
   	
   	while (flag) {
   		System.out.println("请输入信息:");
   		String msg = scanner.nextLine();
   		if (msg.equals("下线")) {
   			break;
   		}
   		// 获取InetAdress
   		InetAddress host1Id = InetAddress.getByName(host1);
   		// 创建报
   		DatagramPacket pa = new DatagramPacket(
   				msg.getBytes(), msg.getBytes().length, host1Id,port1);
   		// 发送
   		socket.send(pa);
   		
   		
   	}
   	socket.close(); 
   	System.out.println("9000关闭");
   }
}

端口2:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Chat2 {
   private static final String host1 = "10.10.18.148";
   private static final int port1 = 9000;
   private static final int port2 = 9001;

   //
   public static void main(String[] args) throws IOException {

   	Scanner scanner = new Scanner(System.in);
   	// 获取Socket对象
   	DatagramSocket socket = new DatagramSocket(port1);
   	boolean flag = true;

   	FutureTask<Object> ft = new FutureTask<Object>(new Callable<Object>() {
   		@Override
   		public Object call() throws Exception {
   			while (flag) {
   				// 接收
   				byte[] recive = new byte[1024];
   				DatagramPacket pa1 = new DatagramPacket(recive, recive.length);
   				socket.receive(pa1);
   				int len = 0;
   				if ((len = pa1.getLength()) > 0) {
   					System.out.println(pa1.getAddress() + "-9000端口说:" + new String(recive, 0, pa1.getLength()));
   				}
   			}
   			return null;
   		}
   	});
   	new Thread(ft).start();
   	while (flag) {
   		// 发送
   		System.out.println("请输入信息:");
   		String msg = scanner.nextLine();
   		if (msg.equals("下线")) {
   			break;
   		}
   		// 获取InetAdress
   		InetAddress host1Id = InetAddress.getByName(host1);
   		// 创建报
   		DatagramPacket pa = new DatagramPacket(msg.getBytes(), msg.getBytes().length, host1Id, port2);

   		// 发送
   		socket.send(pa);
   	}
   	socket.close();
   	System.out.println("9001关闭");
   }
}

两个基本一样,就是收发设置的端口号不一样。
为什么接收用多线程?不用多线程就必须一个发一个接,然后另一个发一个接,不能连续发连续接。
为什么用callable线程?因为callable可以抛异常。
为什么用while(flag)不直接用while(true)?因为如果用true,编译器会认为你一直循环下去,循环下边的代码执行不到,循环下边的代码就会报错。

TCP编程

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!