枚举
枚举: 列举出 有穷序列集
枚举类其实用了多例模式,枚举类的实例是有范围限制的。
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编程
来源:CSDN
作者:BigDevil_
链接:https://blog.csdn.net/BigDevil_/article/details/103602993