Java学习笔记——自己的类(用户存储)

来源:互联网 发布:linux嗅探工具 编辑:程序博客网 时间:2024/05/16 02:41

前言:哎,说来话长,那个地图编辑器做不下去了,自己也很懒,那书也看了才一半。前几天又开始了新的历程,想做一个IM软件出来,如今服务器和客户端是基本做好了,就等了进一步的改进。这里先贴一个用于储存在线用户的类,当然也提供基本的获取添加的方法。还没试验过。

       里面包含一个内部类。内部类包括名称,标识号码,用户自己连接成功的socket,双人聊天客户端数组等等的数据区域。名称当然是用户的昵称了,标识号码就是唯一的一个userID,连接成功的socket就是客户端socket的referrence,而双人聊天客户端只是一个设想。现在是基于聊天室。外部的基本类里面定义了一个内部类的数组,一个PrintStream的数组,这个是和UserData一一对应的,而把它独立出来纯粹为了方便全发的速度。剩下的也就是当前数组下标和最大人数以及当前用户数量了。其他的一些方法不一一列举了,主要就是增加用户,删除用户,查找用户这些基本操作。

      现在讲讲主要的操作流程。当一个客户端和服务器建立连接后,首先查询数据库,看用户ID和密码是否匹配。如果是就把相关的数据储存到userDataList中,已当前current指针下标添加,添加一个current自加一。实际用户数量也自加一。当客户端离开后,首先用该用户的userID在userDataList中查找,并返回相应的数组下标,然后删除,用户数量自动减一,注意,current并不减一,它永远代表最后一个数据的数组下标。当部分用户登陆几次退出后,肯定会造成userDataList的current为最大数组下标,也就是说不能再添加用户了。这个时候如果没有用户离开过,那么这个数组是完全真实填满的。如果有用户推出,那么数组中间就有空闲,不是被数据填满的,还有位置可以添加。但是添加永远是对current+1做数据存放的,所以就分两种情况:1.真实填满,数组扩容。2.虚假填满,整理数组为无空隙且紧密排列,这样就能在current后空出位置添加用户。需要注意的是,扩容和整理数组都非常耗时。相对来说整理的耗费的时间小于扩容。

import java.io.PrintStream;
import java.net.Socket;

/**
 *
 *    用户列表数据结构
 *    做了线程同步 synchronized
 *
 *
 
*/

public class UserListData {
    
    
// 在线用户列表
    private UserData[] userDataList = null;
    
// 记录在线用户所有输出,方便群发
    private PrintStream[] toClientOut = null;
    
// 指明当前的数组下标
    private int current = -1;
    
// 指明当前实际在线用户数量
    private int currentUserNo = 0;
    
    
private int maxUsr = 0;
    
    
/**
     *
     *    UserData:内部类,定义了单个用户的信息
     *    property:
     *        名称,标识号码,用户自己连接成功的socket,双人聊天客户端数组
     *    Method:
     *        添加双人聊天客户端
     *        移除双人聊天客户端
     *        调整方法暂且不用
     *
     
*/

    
class UserData {
        String name 
= null;                    // 记录用户的名称
        long userID = 0;                    // 记录用户唯一一个标记数字
        Socket clientSoc = null;            // 用户的socket
        
        Socket[] toTalkClientSocArr 
= null;    // 正在和用户双人交谈的数组
        long[] toTalkClientID = null;        // 对应的userID
        private int current = 0;            // 交谈中的人在数组中的下标
        private int currentNo = 0;            // 记录双人交谈的人数
        
        
public UserData (String name, long id, Socket soc) {
            
this.name = name;
            
this.userID = id;
            
this.clientSoc = soc;
            
// 设定最多一个人只能和20个人双人对话
            toTalkClientSocArr = new Socket[20];
            toTalkClientID 
= new long[20];
            
/* 初始化
            for (int i = 0; i<20; i++) {
                toTalkClientSocArr[i] = null;
            }
            //
*/

        }

        
        
public UserData (String name, long id, Socket soc, int num) {
            
this.name = name;
            
this.userID = id;
            
this.clientSoc = soc;
            
            toTalkClientSocArr 
= new Socket[num];
            toTalkClientID 
= new long[num];
            
/* 初始化
            for (int i = 0; i<num; i++) {
                toTalkClientSocArr[i] = null;
            }
            //
*/

        }

        
        
public synchronized boolean addTalkClient (Socket soc, long id) {
            
// 判断是否超出长度
            if (toTalkClientSocArr.length < 20{
                
// 0开始数组下标,后自加
                toTalkClientSocArr[current++= soc;
                toTalkClientID[current 
- 1= id;
                currentNo 
++;
                
return true;
            }

            
return false;
        }

        
        
public synchronized boolean removeTalkClient (int index) {
            
if (toTalkClientSocArr.length < index + 1 || toTalkClientSocArr[index] == null{
                
return false;
            }

            
// 移除
            toTalkClientSocArr[index] = null;
            toTalkClientID[index] 
= 0;
            
// 客户数目减少
            currentNo --;
            
// 把current移动到最后一个非null数据上
            
// 如果刚好删除的是最后一个数据
            if (index == current) {
                
// 判断当当前数据为空且不是数组首位时自减1,并判再判断是否为空或者到首位
                while(toTalkClientSocArr[current] == null && current != 0{
                    current 
--;
                }

            }

            
else {
                
// 不是当前被删除,那么直接自减,后有排列方法
                current --;
            }

            
return true;
        }

        
        
// 整理成没有空隙(null)的数组,重新调整后可能会改变当初插入的位置
        public synchronized Socket[] coordinateTalkClientSocArr() {
            Socket[] newArr 
= new Socket[toTalkClientSocArr.length];
            
int j = 0;
            
for (int i = 0; i < toTalkClientSocArr.length; i++{
                
if (toTalkClientSocArr[i] != null{
                    newArr[j
++= toTalkClientSocArr[i];
                }

            }

            current 
= j - 1// 移到末尾
            toTalkClientSocArr = newArr;
            
return toTalkClientSocArr;
        }

        
        
// 返回当前数组下标    
        public int getCurrent () {
            
return this.current;
        }

        
        
// 返回该用户当前双人聊天的数目
        public int getTalkClientNo () {
            
return this.currentNo;
        }


        
/**
         * Method getUserID
         *
         *
         * 
@return
         *
         
*/

        
public long getUserID() {
            
// TODO: 在这添加你的代码
            return this.userID;
        }


        
/**
         * Method searchTalkClient
         *
         *
         * 
@param id
         *
         * 
@return
         *
         
*/

        
public int searchTalkClient(long id) {
            
// TODO: 在这添加你的代码
            for (int i = 0; i<maxUsr; i++{
                
if (id == toTalkClientID[i]) {
                    
return i;
                }

            }

            
return -1;
        }

    
    }

    
    
/**
     *
     *    get name by index
     *
     *
     
*/

    
public String getNameAt (int index) {
        
if (index <= userDataList.length) {
            
return userDataList[index].name;
        }

        
return "out of length!";
    }

    
    
/**
     *
     *    返回指定的UserData
     *
     
*/

    
public UserData getUserDataAt (int index) {
        
if (index <= userDataList.length) {
            
return userDataList[index];
        }

        
return new UserData(""-1null);
    }

    
    
/**
     *
     *    get total user number
     *
     *
     
*/

    
public int getTotalUserNo () {
        
return currentUserNo;
    }

    
    
/**
     *
     *    get current position
     *
     *
     
*/

    
public int getCurrentIndex () {
        
return this.current;
    }

    
    
/**
     *
     *    add a name to names[]
     *    添加一个名字到数组中,如果数组满了就扩容为原来的两倍
     *    判断方法见文档说明
     *
     
*/

    
public synchronized void addUserData (String name, long id, Socket soc, PrintStream out) {
        
// 假满,真满,未满
        if (current == maxUsr - 1 && current > currentUserNo - 1{
            
// 数组其实未满,需调整,中间有空隙
            this.coordinateUserList ();
            
// 调整后再增加
        }

        
if (currentUserNo == maxUsr) {
            
// 数组真实填满并扩大数组两倍原数量
            this.addMoreUserNo ();
        }

        
// 游标指针后移一位
        current++;
        
// 总数增加一个
        currentUserNo++;
        
// 赋值
        userDataList[current] = new UserData(name, id, soc);
        toClientOut[current] 
= out;
    }

    
    
/**
     *
     *    append more space to store name
     *    必须数据容量满了并且没有null后才能调用
     *    扩容为两倍 maxUsr *= 2;
     
*/

    
public synchronized void addMoreUserNo () {
        UserData[] bigArray 
= null;
        
        bigArray 
= new UserData[maxUsr * 2];
        
for (int i = 0; i<maxUsr; i ++{
            bigArray[i] 
= userDataList[i];
        }

        userDataList 
= bigArray;
        maxUsr 
*= 2;
    }

    
    
/**
     *
     *    set names to no null element and return it 
     *
     *
     
*/

    
public String[] getNameArray () {
        String[] newStr 
= null;
        
if (current > currentUserNo - 1{
            
this.coordinateUserList();
        }

        newStr 
= new String[currentUserNo];
        
for (int i = 0; i<currentUserNo; i++{
            newStr[i] 
= userDataList[i].name;
        }

        
return newStr;
    }

    
    
/**
     *
     *    整理后current指针被影响,要修改回到正确位置
     *    所有用户的out也需要被重定向
     *
     *
     
*/

    
public synchronized void coordinateUserList() {
        UserData[] ud 
= new UserData[maxUsr];
        PrintStream[] ps 
= new PrintStream[maxUsr];
        
// 整理成数据之间没有null的数组
        int j = 0;
        
for (int i = 0; i<= current; i++{
            
if (userDataList[i] != null{
                ud[j] 
= this.userDataList[i];
                ps[j] 
= this.toClientOut[i];
                j
++;
            }

        }

        
// 指针移动到末尾
        current = j - 1;
        
// 重新指向
        this.userDataList = ud;
        
this.toClientOut = ps;
    }

    
    
/**
     *
     *    search a user in the array
     *
     *
     
*/

    
public int search(long id) {
        
for (int i = 0; i <= current; i++{
            
if (userDataList[i].userID == id) {
                
return i;
            }

        }

        
return -1;
    }

    
    
/**
     *
     *    userDataList toClientOut
     *
     *
     
*/

    
public synchronized boolean removeUserData(int index) {
        
if (index >= current) {
            System.out.println (
"数组越界......");
            
return false;
        }

        
this.userDataList[index] = null;
        
this.toClientOut[index] = null;
        
return true;
    }

    
    
/**
     *
     *    Construction
     *
     *
     
*/

    
public UserListData (int num) {
        userDataList 
= new UserData[num];
        
this.maxUsr = num;
    }


    
/**
     * Method getOutPutArr
     *    得到所有成员的输出句柄
     *
     * 
@return
     *
     
*/

    
public PrintStream[] getOutPutArr() {
        
// TODO: 在这添加你的代码
        if (this.current > this.currentUserNo - 1{
            
// 数组下标大于现有用户数量,需要调整
            this.coordinateUserList();
        }

        
return this.toClientOut;
    }

}

 

原创粉丝点击