当年我们一起追过的Java,Java SE 个人笔记

版权声明: https://blog.csdn.net/weixin_41219914/article/details/84521940

目录

JDK的安装和配置运行Java程序

java基本语法

面向对象

异常

多线程

API(Application Programming Interface)各种功能的类说明

集合类

 IO输入输出

GUI图形用户界面

网络编程


Java SE基础笔记

java是一门面向对象的高级程序设计语言,抛弃指针,运算符重载等C++特性而使用引用来开发的一门语言。本文从个人学习角度需求进行记录,不涉及具体实现代码,只做基本内容使用的说明。同时部分以C语言作为参考与对比

JDK的安装和配置运行Java程序

JDK目录:

bin目录:放置一些可执行的程序如javac.exe,java.exe,jar.exe,javadoc.exe等

db目录:小型的数据库,纯java实现

jre目录:Java Runtime Enviroment(Java运行环境)

include目录:C/C++库

src.zip放置JDK核心类的源代码

java运行操作

javac.exe是java编译器工具,可以将java文件编写成java字节码文件,源文件扩展名为.java,编译后为.class

java.exe是java运行工具,它会启动一个JVM进程,一个虚拟的运行系统

编译java文件    javac xx.java     运行java文件       java  xx

不使用任何IDE编译,通过安装的JDK进行编译:

打开CMD命令窗口,然后通过cd命令进入安装路径,使用javac命令编译,使用java命令运行

JDK配置

我的电脑-->属性-->系统属性-->编辑-->编辑系统变量进行编辑

path直接添加安装路径\bin,classpath需要创建然后使用安装路径\bin  path调用的是java工具,classpath是查找类


java基本语法

java分为结构定义语句和功能执行语句,必须使用分号

java区分大小写,且是行内执行,不能跨行

注释为          // 单行注释                 /*        */多行注释             以及文档注释/**           */

文档注释可以添加一些文档说明,如个人或者公司等

javadoc -d . -version -author Person.java

帮助文档可以在网上下一个CHM格式的文档,或者使用eclipse,在里面配置一个jdk.zip文档。

java书写规范

1.包名所有字母一律小写

2.类名和接口名每个单词的首字母都要大写

3.常量名所有字母都大写,单词之间用下划线连接

4.变量名和方法名的第一个单词首字母小写,从第二个单词开始每个单词首字母大写

Java关键字
abstract boolean break byte case catch char const class continue
default do double else extends final finally float for goto
if implements import instanceof int interface long native new package
private protected public return short static strictfp super switch this
throw throws transient try void volatile while synchronized  

Java中的常量1.整型常量        2.浮点数常量       3.字符常量       4.字符串常量        5.布尔常量        6.null常量       

变量的类型

 
数据类型
基本数据类型 引用数据类型
数值型 字符型(char) 布尔型(boolean) 类(class) 接口(interface) 数组 枚举(enum) 注解(annotation)

数值型可分为1.整数类型                 byte(1b)        short(2b)        int(4b)        long(8b)  一般为int,特定需要时添加后缀

                      2.浮点类型                float(4b)        double(8b)       一般为double,需要特定指出float时添加f  

逻辑运算符
& 两值皆为真则真,两值运算皆执行
| 一值为真则真,两值皆运算
^ 异或 一真一假为真,两真或两假为假
取反
&& 短路与 和与一样,但前一值为假即不执行后一值判断
|| 短路或 前值为真则不运算
位运算符
& 按位与 两值为1则1,否则为0
| 按位或 一值为1则1,否则为0
^ 按位异或 只有一值为真时才真,否则为假
~ 取反 一位取反
<< 左移 数值加上左移位数
>> 右移 根据符号位补0或1

算术运算符++/--在变量前为这先执行自增后执行其它运算,在变量之后为先以当前值进行运算,行内代码执行完成后进行自增

赋值运算符+=/-=等二元简写运算符形式如:a+=b--->a=a+b    

语句:

if(        ){       }        else if(        ){        }        else{        }

switch(        ) {case:        }

while(    true    ){        }                                               do{        }while(  true      )

for(  ;  ;){     }

break        continue

方法重载为方法名相同,参数个数或者类型不同

数组int[] arr=new int[];


面向对象

面向对象的特性1.封装性        2.继承性        3.多态性

类是对象的抽象,可以定义成员变量即属性,成员行为即方法

类名 对象名称 =new 类名() new开启引用地址 ,类名后的括号用于构造方法的创建,每一个类均有一个或多个构造方法

对象.对象成员                             访问对象的属性或者方法

类的封装——使用private私有属性,除所在类外不能访问,但可通过公有的方法访问私有属性的值,起到对私有属性的保护

构造方法:1.方法名和类名相同       2.在方法名前面没有返回值类型的声明        3.方法不带有返回值       实例化对象时自动调用构造方法

this关键字用于访问该对象的成员

this()调用构造方法,只能在构造方法里面调用其他构造方法,必须位于构造方法的第一行,并且不能两个构造方法互相调用。构造方法相当于一个static静态方法,在创建对象时自动创建,并且与super调用父类相冲突,只能选择其中一个

java自动垃圾回收,但也可以通过System.gc()通知虚拟机进行垃圾回收    当对象在内存中被释放时,其finalize()方法会被自动执行

static静态

静态变量:static创建的数据为各个类的实例所共享,通过类名.变量名访问    即属于类的范围,类引用时创建(按需要调用)

静态方法:static方法,通过类名.方法名调用,静态的成员均不需要创建对象就能直接调用(按需要调用)

静态代码块:当类被加载时,静态代码块会执行,由于类只加载一次,因此代码块就执行一次

单例模式

class Single{
    private static Single INSTANCE=new Single();    //私有静态实例,由于是静态,类加载时创建且唯一
    private Single();                                 //私有构造方法,不能通过new创建新对象
    public static Single getInstance(){               //公有静态方法,引用类。方法调用方法体  
        return INSTANCE;
    }
}

内部类——成员内部类,静态内部类,方法内部类

成员内部类:成员内部类可以访问外部类的所有成员,同样,外部类成员通过创建内部类对象访问内部类数据,在其他类中,需要创建外部类对象才能访问内部类。内部类就是一个类里面还包含一个新创建的类。

class Outclass{                  //外部类
    class Inner{                 //内部类
    }
}

由于编译时内部类需要创建外部类然后生成关联文件到内部类上,因此要访问内部类的形式如下:

外部类名.内部类名      变量名=new 外部类名().内部类名()        

静态内部类

class Outclass{                  //外部类
    static class Inner{          //静态内部类
    }
}

外部类名.内部类名       变量名=new  外部类名.内部类名();

内部类与静态内部类的差别,首先需要说明类和对象的差别:类是对象的抽象,因此创建对象需要调用关于该类的构造方法,但注册在该类的静态成员会随着类的引用而生成,不需要创建对象。静态成员只能访问静态成员。静态内部类只能定义静态成员,非静态内部类不能定义静态成员。这涉及到一个类的生成、对象生成、静态成员创建的顺序。

方法内部类:在成员方法中定义的类,只能在方法中被调用

class outer{
    public void test(){
        class Inner{
        }
    }
}

方法内部类可以调用外部类的成员变量,调用方法内部类需要通过外部类创建对象调用该方法,然后在方法中调用内部类。       

继承

子类会自动拥有父类所有可继承的属性和方法,使用extends关键字继承父类

子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限

当子类重写父类的方法时,子类不能直接访问父类的方法,需要通过super.方法名()访问父类中的方法

子类实例化时会默认调用父类的无参构造方法,也可以通过super(实参)指定调用父类中的其余构造方法。当父类不存在无参构造方法时,当心子类自动调用父类构造方法。因此创建类时定义一个无参的构造方法会减少被继承时的错误。

所有类都继承Object。

final关键字——可用于修饰类、变量、和方法

  • final修饰的类不能被继承
  • final修饰的方法不能被子类重写
  • final修饰的变量是常量(成员变量和局部变量),只能赋值一次
  • final修饰的成员变量不会对其初始化,因此在定义时需要初始化变量

抽象类和接口

abstract void 方法名();                                //定义抽象方法

当定义抽象方法时该类必须是抽象类,但定义抽象类可以不是抽象方法,抽象类不可以被实例化,因为抽线类可能含有抽线方法,抽线方法没有实体,不可以被调用

接口是所有方法都是抽象的,定义接口使用的关键字是interface,需要区分方法和变量的定义,方法是抽象的,变量是实体的,接口默认为public abstract 而接口变量为 public static final全局常量

一个普通类(非抽象或者接口类型)实现或者继承抽象类或者接口时需要实现所有抽象方法

普通类,所有方法皆实体         抽象类,方法可以是实体或者抽象           接口,所有方法皆抽象

class普通类所有方法都有实体 abstract  class抽象类可以有抽象方法 interface接口没有实体方法

因此 某类extends继承无论是类还是interface接口,会继承所有可使用方法,并且可通过super调用继承的类或接口成员(不包括未实现的方法),但implement实现接口需要实现所有的方法,但抽象类因为可以拥有抽象方法,可以不实现接口的所有方法。抽象类和普通类的区别是抽象类可以有抽象方法,并且不能被实例化,即不能使用new一个对象,同样,抽象类一样可以继承类或者接口

多态

允许使用一个父类类型的变量来引用子类类型的对象

interface Interface{
    void method();                       //接口抽象方法
}
class First implements Interface{
    public void method(){                //实体方法1
    ……
    }
}
class Second implements Interface{
    public void method(){                //实体方法2
    …………
    }
}
class Test{
    public static void main(String[] args){
    Interface fir=new First();           //实例化方法1对象,使用Interface类型变量fir引用
    Interface sed=new Second();          //实例化方法2对象,使用Interface类型变量sed引用
    methods(fir);                        //输出方法1实体
    method(sec);                         //输出方法2实体
    }

    public static void methods(Interface an){            
    an.method()                          //调用方法
    }

}

实例化不同类型的对象虽然都是同一个类型引用,但不能互相访问

判断一个对象是否为某个类的实例或者子类实例 对象 instanceof 类或接口

匿名内部类

方法调用时,参数为新创建的实例,并将该类写入

Otherclass.method(new Innerclass( ){   类的代码块 });因此不需要创建对象名,但重复调用时困难。


异常

图表不全,只能表示大概的异常类,可参考API

主要以RuntimeException

Throwable常用方法
方法声明 功能描述
String getMessage() 返回此throwable的详细信息字符串
void printStackTrace() 将次throwable及其追踪输出到标准错误流
void printStackTrace(PrintStream s) 将此throwable及其追踪输出到指定的输出流

try{ 需要执行的代码块 }catch{ 异常捕获,Exception类及其子类  }finally{   是否异常都要执行  }           

throws——方法中扔出的Exception类    throw——具体步骤扔出异常对象   

要么在运行时try catch解决异常,要么使用throws将异常抛出给操作                                       

是专门用来存放类的,关键字package,导入包为import

private——只能被该类的成员访问,其他类无法直接访问

defoult——默认,该类或者类的成员只能被本包访问

protected——同一个包可以访问,不同包中该类的子类访问

public——不受限制


多线程

线程与进程的区别;进程,一个程序开始执行到结束运行叫进程为其分配内存等资源,线程是对于CPU而言,每次执行一个进程然后切换到另一个进程,由于太快所以感觉是同步进行。

线程的创建一个是继承Thread类,然后覆写run()方法。另一种是实现Runnable接口,重写run()方法,然后创建一个Thread类并在构造方法Thread(Runnable Target)传入一个Runnable接口引用。

Runnable接口,只有一个run()方法。可创建一个实现对象,然后开启多个线程调用同一个实例对象实现多线程操作。

Thread.currentThread()方法得到当前的线程的实例对象,getName()可以过得线程的名称,构造方法Thread(对象,名称)为线程命名。

新创建的线程默认都是前台线程,某个线程启动之前(.start)调用了setDaemon(true)方法开启后台线程。

线程分为5个周期,除新建状态和死亡状态是单向外,其余3个就绪状态,阻塞状态,运行状态都可以互相转换

1.新建状态(New):创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其他Java对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特性

2.就绪状态(Runnable):当线程对象调用了start()方法后,该线程就进入就绪状态(也称可运行状态)。处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,能否获得CPU的使用权开始运行,还需要等待系统的调度。

3.运行状态(Running):如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态。当一个线程启动后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就结束了),当使用系统分配的时间后,系统就会剥夺线程占用的CPU资源,让其他线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才能转换到运行状态。

4.阻塞状态(Blocked):一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被清除后,线程才可以转入就绪状态。

  • 当线程试图获得某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获得其他线程所持有的锁
  • 当线程调用一个阻塞的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须等这个阻塞的IO方法返回
  • 当线程调用了某个对象的wait()方法时,会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程
  • 当线程调用了Thread的sleep(long millis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,线程就会自动进入就绪状态
  • 当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态

5.死亡状态(Terminated):线程的run()方法正常执行完毕或者贤臣抛出一个未捕获的异常/错误,线程就进入死亡状态。一旦进入死亡状态,线程就不再拥有运行的资格,也不能再转换到其他状态。

CPU调度分为分时模式,抢占模式,Java默认使用的是抢占模式。

static int MAX_PRIORITY 表示线程的最高优先级

static int MIN_PRIORITY  表示线程的最低优先级

static int NORM_PRIORITY biaoshi 表示线程的普通优先级

线程有限级 对象. setPriority(int newPriority)方法设置  

线程休眠 对象.sleep(time),进入阻塞状态,会抛出异常,需要捕获异常 休眠需要注意同步问题。

线程让步,回到就绪状态,只有与当前线程优先级相同或者更高才能获得运行yield()对象.yield()

线程插队 join()对象.join()

synchronized(lock)锁对象,当锁为1时执行,执行期间将为0,其他线程遇到锁为0时进入阻塞

可使用同步代码块或者同步方法 synchronized(lock){代码块} ;需要注意同步对象创建不能放在run()方法中   

synchronized 返回值类型 方法名 (){        }     注意死锁

同步代码块锁为自己创建的对象,同步方法为当前调用的对象,静态方法为该对象的类名.class获得

void notify()——唤醒此同步锁上等待的第一个调用wait()方法的线程

void notifyAll()——唤醒此同步锁上调用wait()方法的所有线程

void wait()——使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()方法,或notifyAll()方法唤醒该线程为止


API(Application Programming Interface)各种功能的类说明

String

构造方法String()创建一个空的字符串       String(char[] value) 根据字符数组创建对象       String(String value)根据字符串内容创建对象

String类常用方法
int index(int ch) 返回指定字符在此字符串中第一次出现处的索引
int lastIndexOf(int ch) 返回指定字符串在此字符串中最后一次出现处的索引
char charAt(int index) 返回字符串中index位置上的字符,其中index的取值范围是:0~(字符串长度-1)
boolean endsWith(String suffix) 判断此字符串是否以指定的字符串结尾
int length() 返回此字符串的长度
boolean equals(Object anObject) 将此字符串与指定的字符串比较
boolean isEmpty() 当且仅当字符串长度为0时返回true
boolean startsWith(String prefix) 判断此字符串是否以指定的字符串开始
boolean contains(CharSequence cs) 判断此字符串是否包含指定的字符序列
String toLowerCase() 使用默认语言环境的规则将String中的所有字符都转换为小写
String toUpperCase() 使用默认语言环境的规则将String中的所有字符都转换为大写
String valueOf() 返回int参数的字符串形式
char[] toCharArray() 将此字符串转换为一个字符数组
String replace(CharSequence oldstr,CharSequemce newstr) 返回一个新的字符串,它是通过用newstr替换此字符串中出现的所有oldstr得到的
String[] split(String regex) 根据参数regex将原来的字符串分割为若干个子字符串
String substring(int beginIndex) 返回一个新字符串,它包含字符串中索引beginIndex后的所有字符
String substring(int beginIndex,int endIndex) 返回一个新字符串,它包含字符串从中索引beginIndex到索引endIndex之间的所有字符
String trim() 返回一个新字符串,它去除了原字符串首尾的空格

StringBuffer(长度可变的String)

StringBuffer类常用方法
方法说明 功能描述
StringBuffer append(char c) 添加参数到StringBuffer对象中
StringBuffer insert(int offset,String str) 将字符串中的offset位置插入字符串str
StringBuffer deleteCharAt(int index) 移除此序列指定位置的字符
StringBuffer delete(int start,int end) 删除StringBuffer对象中指定范围的字符串序列
StringBuffer replace(int start,int end,String s) 在StringBuffer对象中替换指定的字符或字符串序列
void setCharAt(int index,char ch) 修改指定位置index处的字符序列
String toString() 返回StringBuffer缓冲区中的字符串
StringBuffer reverse() 将此字符序列用其反转形式取代

System

System类的常用方法
方法说明 功能说明
static  void exit(int status) 该方法用于终止当前正在运行的Java虚拟机,其中参数status表示状态码,若状态码非0,则表示异常终止
static long gc() 运行垃圾回收器,并对垃圾进行回收
static long currentTimeMillis() 返回以毫秒为单位的当前时间
static void arraycopy(object src,int srcPos,Object dest, int destPos,int length) 从src引用的指定源数组复制到dest引用的数组,复制从指定的位置开始,到目标数组的指定位置结束
static Properties getProperties() 取得当前的系统属性
static String getProperty(String key) 获得指定键描述的系统属性

Runtime类

Runtime run=Runtime.getRuntime()    对象方法提供availableProcessors freeMemory maxMemory exec等方法,以调用计算机信息

Math类和Random类

Math的静态方法

  • Math.abs()        //绝对值
  • Math.ceil()        //大于参数的最小整数
  • Math.floor()       //小于参数的最大整数
  • Math.round()    //四舍五入
  • Math.max()      //最大值
  • Math.min()      //最小值
  • Math.random()   // 随机数,大于等于0小于1

Random

Random random=new Random()

对象方法用于返回指定类型的随机数,构造方法传入固定值则生成同样的序列,不指定参数时每次生成不一样的随机数

  • boolean nextBoolean() ——随机生成Boolean类型的随机数
  • double nextDouble()——随机生成double类型的随机数
  • float nextFloat()——随机生成float类型的随机数
  • int nextInt()——随机生成int类型的随机数
  • int nextInt(int n)——随机生成0~n之间int类型的随机数
  • long nextLong()——随机生成long类型的随机数

包装类

首先需要说明为什么会有包装类,因为基本类型的和对象类型运行在内存的不同位置,相对来说,基本类型的调用相对频繁,同样是存放在内存上,但访问和创建的方式不一样,调用的方式也不一样。但对象拥有基本类型没有的方法,因此有时需要将基本类型包装起来使用。

基本类型的包装类

byte Byte long Long char Character float Float
int Integer double Double short Short boolean Boolean

装箱是将基本类型转换为对象的形式,拆箱是将对象类型转换为基本类型

类 引用变量=new 类(基本类型)

Integer类型的一些方法

Integer类的常用方法
toBinaryString(int i) 以二进制无符号整数形式返回一个整数参数的字符串
toHexString(int i) 以十六进制无符号整数形式返回一个整数参数的字符串
toOctalString(int i) 以八进制无符号整数形式返回一个整数参数的字符串
valueOf(int i) 返回一个表示指定的int值的Integer实例
valueOf(String s) 返回保存指定的String值的Integer对象
parseInt(String s) (静态方法)将字符串参数作为有符号的十进制整数进行解释
intValue() 将Integer类型的值以int类型返回

其中,除Character类外都有静态方法valueOf将字符串转换为包装类型,都有静态方法parseXXX将字符串转换为基本类型

Date

对象 只建议两个构造方法,其余都过时,一个无参的构造方法返回当前时间对象,另一个带有参数的构造方法创建指定时间的对象Date date = new Date()或Date data = new Date(long date)

Calendar

Calendar为一个抽象类,不能被实例化,通过静态方法返回一个Calendar对象,准确说是返回一个继承该类的对象,引用了多态的形式

Calendar的常用方法
方法声明 功能描述
int get(int field) 返回指定日历字段的值
void add(int field,int amount) 根据日历规则,为指定的日历字段增加或减去指定的时间量
void set(int field,int value) 为指定日历字段设置指定值
void set(int year,int month,int date) 设置Calendar对象的年、月、日三个字段的值
void set(int year,int month,int date,int hourOfDay,int minute,int second) 设置Calendar对象的年、月、日、时、分、秒六个字段的值

Calendar.YEAR     Calendar.MONTH    Calendar.SECOND    Calendar.DATE     Calendar.Hour    Calendar.MINUTE

Calendar.setLenient模式 月份默认为0开始,因此得到月份需要添加1


集合类

单列集合Collection

  • List:元素有序、元素可重复(ArrayList/LinkedList)
  • Set:元素无序、不可重复(HashSet/TreeSet)

双列集合Map

  • HashMap
  • TreeMap

Collection

Collection接口

方法声明 功能描述 boolean add(Object o) 向集合中添加一个元素 boolean addAll(Collection c) 将指定Collection中的所有元素添加到该集合中 void clear() 删除该集合中的所有元素 boolean removbe(Object o) 删除该集合中指定的元素 boolean removeAll(Colection c) 删除指定集合中的所有元素 boolean isEmpty() 判断该集合是否为空 boolean contains(Object o) 判断该集合中是否包含某个元素 boolean containsAll(Collection c) 判断该集合中是否包含指定集合中的所有元素 Iterator iterator() 返回在集合的元素上进行迭代的迭代器,用于便利该集合所有元素

int size()

获得该集合元素个数

list接口,元素允许重复,有序,存入和取出顺序一致

List集合常用方法
方法声明 功能描述
void add(int index,Object element) 将元素element插入在List集合的index处
boolean addAll(int index,Collection c) 将集合c所包含的所有元素插入到List集合的index处
Object get(int index) 返回集合索引index处的元素
Object remove(int index) 删除index索引处的元素
Object set(int index,Object element) 将索引index处元素替换成element对象,并将替换后的元素返回
int indexOf(Object o) 返回对象o在List集合中出现的位置索引
int lastIndexOf(Object o) 返回对象o在List集合中最后出现的位置索引
List subList(int fromIndex,int toIndex) 返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合

ArrayList为List的一个实现类,可理解为长度可变的数组,查找方便,但增删不方便

LinkedList是List的另一个实现类,双向链表,增减方便

LinkedList方法
方法声明 功能描述
void add(int index,E element) 在此列表中指定的位置插入指定的元素
void addFirst(Object o) 将指定元素插入此列表的开头
void addLast(Object o) 将指定元素添加到此列表的结尾
Object getFirst() 返回此列表的第一个元素
Object getLast() 返回此列表的最后一个元素
Object removeFirst() 移除并返回此列表的第一个元素
Object removeLast() 移除并返回此列表的最后一个元素

Iterator接口用于遍历列表元素,通过列表元素的 iterator()方法返回一个Iterator的引用对象,调用该对象的hasNext()方法判断是否具有下一个元素,如果存在则调用next()方法输出,修改元素需要使用迭代器自身的方法

ListInerator接口为Inerator的子类 listname.listIterator(起始位置)返回一个ListIterator对象

  • void add(Object o)               将指定的元素插入列表(可选操作)
  • boolean hasPrevious()        如果以逆向遍历列表,列表迭代器有多个元素,则返回true
  • Object previous()                返回列表中的前一个元素
  • void remove()                     从列表中移除由next或previous返回的最后一个元素(可选操作)

同样for语句可遍历列表,但不能修改其中的值

Set

  • HashSet根据对象的哈希值进行存储位置,良好的存取和查找性能,需要重写hashCode方法和equals方法
  • TreeSet二叉树排序    需要重写compareTo方法确定排序方法

Vector线程安全

Map接口

Map集合常用方法表
方法声明 功能描述
void put(Object key,Object value) 将指定的值与此映射中的指定键关联(可选操作)
Object get(Object key) 返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
boolean containsKey(Object Key) 如果此映射包含指定键的映射关系,则返回true
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回true
Set keySet() 返回此映射中包含的键的Set视图
Collection<V> values() 返回此映射中包含的值的Collection视图
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的Set视图

HashMap,键值关系的列表,键相同时,以后值覆盖前值达到元素的不重复,根据哈希值存储位置

LinkedHashMap对应于LinkedList,属于双向列表

TreeMap二叉树原理

Properties集合   线程安全 setProperty getProperty

泛型

对集合中存储或者取出的元素进行限制,避免出现类型不匹配的错误

Collections类常用方法(注意是多了一个s)
方法声明 功能描述

static <T> boolean addAll(Collection <? super T>c,T...elements)

将所有指定元素添加到指定的collection中
statci void reverse(List list) 反转指定List集合中元素的顺序
static void shuffle(List list) 对List集合中的元素进行随机排序(模拟玩扑克中的"洗牌")
static void short(List list) 根据元素的自然顺序对List集合中的元素进行排序
static void swap(List list,int i,int j) 将指定List集合中i处元素和j处元素进行交换
static int binarySearch(List list,Object key) 使用二分法搜索指定对象在List集合中的索引,查找的List集合中的元素就必须是有序的
static Object max(Collection col) 根据元素的顺序,返回给定集合中的最大的元素
static Object min(Collection col) 根据元素的顺序,返回给定集合中的最小的元素
static booleanreplaceAll(List list,Object oldVal,Object newVal) 用一个新的newVal元素替换List集合中所有的旧值oldVal

Arrays类

static void sort()                                      排序

static int binarySearch(Object[] a,Object key)      查找指定元素的索引值,只能对排序的数组进行查找

static int[] copyOfRange(int[] original,int from,int to)    用于将包括开始的元素,不包括结束的元素复制到新的数组中

static void fill(Object[] a,Object val)                 用一个元素替换所有元素

static String toString(int[] arr)                           把数组转换为字符串


 IO输入输出

字节流        两个抽象子类----(二进制)InputStream(字节输入流)    OutPutStream(字节输出流)

字符流        Reader(字符输出流)    Write字符输出流

字符流常用方法
方法声明 功能描述
InputStream
int read() 从输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数
int read(byte[]) 从输入流读取若干字节,把他们保存到参数b指定的字节数组中,并返回的整数表示读取字节数
int read(byte[],int off,int len) 从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的下标,len表示读取的字节
void close() 关闭此输入流并释放与该流关联的所有系统资源
OutputStream
void write(int b) 向输出流写入一个字节
void write(byte[] b) 把参数b指定的字节数组的所有字节写到输出流
void write(byte[] b,int off,int len) 将指定byte数组从偏移量off开始的len个字节写入输出流
void flush() 刷新此输出流并强制写出所有缓冲的输出字节
void close() 关闭此输出流并释放与此流相关的所有系统资源

文件操作FileInputStream("文件名")/FileOutputStream("文件名",boolean)

字节缓冲流BufferedInputStream(InputStream in[,size])/BufferedOutputStream


字符读取FileRead/FileWrite

字符缓冲流BufferedReader/BufferedWrite  重要方法BufferedReader的重要方法readLine(),newLine()

LineNumberReader它是BufferedReader的子类.

InputStreamReader OutputStreamWriter 字节输入转字符  字符输出转字节

ObjectInputStream和ObjectOutputStream对象输入或输出流,需要实现Serializable接口 保存对象参数

DateInputStream和DataOutputStream保存基本类型的类,参数为BufferedOutputStream更方便

PrintStream对象,打印基本类型或者是对象类型等,调用其print方法即可输出

System类三个常量in.out.err标准输入输出流

void setIn(InputStream in) 对标准输入流重定向

void setOut(PrintStream out) 对标准输出流重定向

void setErr(PrintStream out) 对标准错误输出流重定向

GUI图形用户界面

  • AWT
  •         Component非菜单类
  •                 Container容器类
  •                          Window    不依赖其他容器独立存在的容器
  •                                Frame    具有标题栏的窗口
  •                                Dialog    对话框
  •                                        FileDialog
  •                          Panel    不能独立存在
  •                 Button    
  •                 label
  •                 CheckBox
  •                 TextComponent
  •                         TextArea
  •                         TextField
  •         MenuComponent
  •                 MenuBar
  •                 MenuItem
  •                         Menu

事件监听器

如:WindowListener接口         1.windowActivted(激活)        2.windowClosed(关闭)      3.windowDeactived(失活)    4.windowDeiconified(取消图标化)       5.windowIconified(图标化)    6.windoiwOpened(开启)    7.windowClosing(关闭)   

参数均为WindowEvent类型

事件适配器

windowAdapter类适配器,实现了接口的方法,但没有具体代码块,因此调用时需要重写特定的方法

事件分类

  • WindowEvent     MouseEvent     KeyEvent     ActionEvent

WindowEvnet 需要实现的方法                  1.windowActivted(激活)        2.windowClosed(关闭)      3.windowDeactived(失活)    4.windowDeiconified(取消图标化)       5.windowIconified(图标化)    6.windoiwOpened(开启)    7.windowClosing(关闭)   

 MouseEvent            1.mousePressed(鼠标按下)           2.mouseReleased(鼠标松开事件)      3.mouseEnter(鼠标进入按钮区域)

4.mouseClick(鼠标点击)         5.mouseExited(鼠标移出按钮区域) MouseEvent类下的getButton获得具体鼠标的操作, 常量BUTTON1      BUTTON2       BUTTON3代表值

Key        静态方法static  getKeyText   返回值

布局管理器  FlowLayout(流式布局管理器)    BorderLayoput(边界布局管理器)    GirdLayout(网格布局管理器)

GirdBagLayout(网格包布局管理器)    CaedLayout(卡片管理器)

由左到右布局FlowLayout布局管理器的构造方法   

  • FlowLayout()——组件默认居中对齐,水平、垂直间距默认为5个单位
  • FlowLayout(int align)——指定组件相对于容器的对齐方式,水平、垂直间距默认为5个单位 FlowLayout.LETF(居左)  FlowLayout.CENTER(水平居中)    FlowLayout.RIGHT(居右对齐)
  • FlowLayout(int align,int hgap,int vgap)——指定组件的对齐方式和水平、垂直间距

上下左右中五种布置方式BorderLayout边界布局管理器

添加组件方法add(Componept comp,Object constraints)第一个位组件,第二位常量 EAST SOUTH WEST NORTH CENTER,每一个区域只能放置一个组件

格子的形式设置布局GridLayout网格布局管理器构造方法

  • GridLayout()——默认只有一行,每个组件占一列
  • GridLayout(int rows,int cols)——指定容器的行数和列数
  • GridLayout(int rows,int cols,int hgap,int vgap)——指定容器的行数和列数以及组件之间的水平、垂直间距

最灵活的各个包大小不一样的布局管理器GridBagLayout

  • 创建容器与布局文件Component GirdBagLayoput,容器关联布局setLayout
  • 创建约束对象GridBagLayout,并设置
  • 布局文件setConstraints关联组件与约束对象
  • 容器添加组件

通俗讲就是设置容器,为容器添加网格包布局管理器,创建一个约束对象,设置约束对象的值,然后使用布局文件对象setConstraints方法将需要添加的组件绑上约束对象,从而设置其属性,最后在容器中添加该组件

GridBagConstraints常用属性
属性 作用
gridx和gridy 设置组件的左上角所在网格的横向和纵向索引。如果将gridx和gridy的值设置为GridBagConstraints.RELATIVE(默认值),表示当前组件紧跟在上一个组件后面
gridwidth和gridheight 设置组件横向、纵向跨越几个网格,两个属性的默认值都是1。如果把两个属性的值设为GridBagConstraints.REMAINER,表示当前组件在其行或其列上为最后一个组件,如果把这两个属性的值设为GridBagConstraints.RELATIVE,表示当前组件在其行或列上为倒数第二个组件
fill

如果当前组件的显示区域大于组件需要的大小,设置是否以及如何改变组件大小,该属性接受以下几个属性值:

  • NONE:默认,不改变组件大小
  • HORIZONTAL:使组件水平方向足够长以填充显示区域,但高度不变
  • VERTICAL:使组件垂直方向足够高以填充显示区域,但长度不变
  • BOTH:使组件足够大,以填充整个显示区域
weightx和weighty 设置组件占领容器中多余的水平方向和垂直方向空白的比例(也称为权重)。假设容器的水平方向放置三个组件,其weightx分别为1、2、3,当容器宽度增加60个像素时,这三个容器分别增加10、20和30的像素。这两个属性的默认值是0,即不占领多余的空间

卡片布局CardLayout,同一窗口布置多个界面

CardLayput常用方法
方法声明 功能描述
void first(Container Parent) 显示parent容器的第一张卡片
void last(Container parent) 显示parent容器的最后一张卡片
void previous(Container parent) 显示parent容器的前一张卡片
void next(Container parent) 显示parent容器的下一张卡片
void show(Container parent,Stringname) 显示parent容器中名称为name的组件,如果不存在,则不会发生任何操作

通过cardLayout对象的next或者previous等方法实现组件之间的切换

不使用布局管理器setLayout(nul)

必须调用setLocation方法(定位)/setSize方法(设置大小)方法/setBounds方法(位置x,y,大小x,y)。

AWT绘图

Graphics常用方法
方法声明 方法描述
void setColor(Color c) 将此图形上下文的当前颜色设置为指定颜色Color.RED
void setFont(Font f) 将此图形上下文的字体设置为指定字体(三个参数,分别是字体名称,字体样式Font.PLAINT/Font.ITALIC/FOnt.BOLD,字体大小
void drawLine(int x1,int y1,int x2,int y2

以(x1,y1)和(x2,y2)为端点绘制一条线段

void drawRect(int x,int y,int width,int height) 绘制指定矩形的边框。矩形的左边缘和右边缘分别位于x和x+width,上边缘分别位于y+yheight

void drawOval(int x,int y,int width,int height)

绘制椭圆的边框,得到一个圆或椭圆,它刚好能放入由x,y、width和height参数指定的矩形中。椭圆覆盖区域的宽度为width+1像素,高度为height+1像素

void fillRect(int x,int y,int width,int height)

用当前元颜色填充指定的矩形。该矩形左边缘和右边缘分别位于x和x+width-1,上边缘和下边缘分别位于y和y+height-1
void fillOval(int x,int y,int weight,int height) 用当前颜色填充外接指定矩形的椭圆

void drawString(String str,int x,int y)

使用此图形上下文的当前字体和颜色绘制指定的文本str。最左侧字符左下角位于(x,y)坐标

Swing

JFrame设置关闭的方法容器.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)

JDialog设置 JDialog(Frame owner)——构造方法,用来创建一个非模态的对话框,owner为对话框所有者(顶级窗口JFrame)

JDiolog(Frame owner,String title)——构造方法,创建一个具有指定标题的非模态对话框

JDiolog(Frame owner,boolean modal)——创建一个指定模式的无标题对话框

模态即为用户提供需要处理的对话框,处理完成后才能与其他窗口交互,非模态允许用户在处理对话框的同时与其他窗口交互

JPanel:无边框,不能移动、放大、缩小或者关闭的面板,默认布局为FlowLayout

JscrollPane:只能添加一个组件,带有滚动条。

JScrollPane构造方法和方法
方法声明 功能描述
JScrollPane() 创建一个空的JScrollPane
JScrollPane(Component view) 创建一个显示组件的JScrollPane面板,只要组件的内容超过视图大小就会显示水平和垂直滚动条
JScrollPane(Component view,int vsbPolicy,int hsbPolicy)

创建一个显示指定容器、并具有指定滚动条策略的JScrollPene。参数vsbPolicy和hsbPolicy分别表示垂直滚动条策略和水平滚动条策略,应指定为ScrollPaneConstants的静态常量。

  • HORIZONTAL_SCROLLBAR_AS_NEEDED:表示水平滚动条只在需要时显示,是默认策略。
  • HORIZONTAL_SCROLLBAR_NEVER:表示水平滚动条永远不显示
  • HORIZONTAL_SCROLLBAR_ALWAYS:表示水平滚动条一直显示
  • HORIZONTAL可以换成VERTICAL表示垂直滚动条
  • 该常量为ScrollPaneConstants类的常量,需要添加该类的引用,即ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
void setHorizontalBarPolicy(int policy) 指定水平滚动条策略,即水平滚动条何时显示在滚动面板上
void setVerticalBarPolicy(int policy) 指定垂直滚动条策略,即垂直滚动条何时显示在滚动面板上
void setViewportView(Component view) 设置在滚动面板显示的组件,添加组件

文本框JTextComponent抽象类,子类JTextField和JtextArea

密码框属于JTextField的子类,方法相似

文本框的常用方法
JTextComponent常用方法
方法描述 功能说明
String getText() 返回文本组件中所有的文本内容
void getSelectedText() 返回文本组件中选定的文本内容
void selectAll() 在文本组件中选中所有内容
void setEditable() 设置文本组件为可编辑或者不可编辑状态
void replaceSelection(String content) 用给定的内容替换当前选定的内容
JTextField构造方法
JTextField() 创建一个空的文本框,初始字符串为null
JTextField(int columns) 创建一个具有指定列数的文本框,初始字符串为null
JTextField(String text) 创建一个显示指定初始字符串的文本框
JTextField(String text,int column) 创建一个具有指定列数、并显示指定初始字符串的文本框
JTextArea构造方法
JTextArea() 创建一个空的文本域
JTextArea(String text) 创建一个显示指定初始字符串的文本域
JTextArea(int rows,int columns) 创建具有指定行和列的空文本域
JTextArea(String text,int rows,int columns) 创建显示指定初始文本并指定了行列的文本域
void append() 为文本框添加文本

按钮组件

JButton、JCheckBox、JradioButton等属于AbstractButton抽象类的子类或者间接子类

AbstractButton常用方法
方法描述  功能说明
Icon getIcon和void setIcon(Icon icon) 设置或者获取按钮的图标
String getText()和void setText(String text) 设置或者获取按钮的文本
void setEnable(boolean b) 启用(当b为true)或禁用(当b为false)按钮
setSelected(boolean b) 设置按钮的状态,当b为true时,按钮时选中状态,反之为未选中状态
boolean isSelect() 返回按钮的状态(true为选中,反之为未选中)
JcheckBox构造方法(多选)
JcheckBox() 创建一个没有文本信息,初始状态未被选中的复选框
JCheckBox(String text) 创建一个带有文本信息,初始状态未被选定的复选框
JCheckBox(String text,boolean selected) 创建一个带有文本信息,并指定初始状态(选中/未选中)的复选框
JradioButton构造方法(单选)
JRadioButton() 创建一个没有文本信息、初始状态未被选中的单选框
JradioButton(String text) 创建一个带有文本信息、初始状态未被选中的单选框
JRadioButton(String text,boolean selected) 创建一个带有文本信息,并指定初始状态(选中/未选中)的单选框
JComBox构造方法(列表)
JComboBox() 创建一个没有可选项的组合框
JComboBOx(Object[] items) 创建一个组合框,将Object数组中的元素作为组合框的下拉列表选项
JComboBox(Vector items) 创建一个组合框,将Vector集合中的元素作为组合框的下拉列表选项
JComboBox常用方法
void addItem(Object anObject) 为组合框添加选项
void insertItemAt(Object anObject,int index) 在指定的索引处插入选项
Object getItemAt(int index) 返回指定索引处选项,第一个选项的索引为0
int getItemCount() 返回组合框中选项的数目
Object getSelectedItem() 返回当前所选项
void removeAllItems 删除组合框中所有的选项
void removeItem(Object object) 从组合框中删除指定选项
void removeItemAt(int index) 移除指定索引处的选项
void setEditable(boolean aFlag) 设置组合框的选项是否可编辑,aFlag为true则可编辑,反之则不可编辑

ButtonGroup为单选框捆绑组件,逻辑上将单选组件捆绑在一起,并不是一个框架

菜单组件

下拉式菜单

JMenuBar(菜单栏)、JMenu(菜单)、JMenuItem(菜单项)        JMenuBar为水平菜单,在水平菜单中添加JMenu菜单,在JMenuItem添加单独的菜单项。

JMenu常用方法
方法声明 功能描述
void JMenuItem add(IMenuItem menuItem) 将菜单项添加到菜单末尾,返回此菜单项
void addSeparator() 将分隔符添加到菜单的末尾
JMenuItem getItem(int pos) 返回指定索引处的菜单项,第一个菜单项的索引为0
int getItemCount() 返回菜单上的项数,菜单项和分隔符都计算在内
void JMenuItem insert(JMenuItem menuItem,int pos) 在指定索引处插入菜单项
void insertSeparator(int pos) 在指定索引处插入分隔符
void remove(int pos) 从菜单中移除指定索引处的菜单项
void remove(JMenuItem menuItem) 从菜单中移除指定的菜单项
void removeAll() 从菜单中移除所有的菜单项

容器通过setJMenuBar,而JMenuBar和JMenu通过add添加各自的组件

弹出式菜单

JPopupMenu菜单,相当于JMenu,添加JMenuItem组件生成弹出列表

网络编程

TCP/IP协议中分为应用层、传输层、网络层、链路层

  • 链路层:用于定于物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、双绞线提供的驱动
  • 网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络
  • 传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议
  • 应用层:主要负责应用程序的协议,如HTTP协议、FTP协议

IP4采用4个字节表示,IP6采用16个字节表示,访问应用程序需要用到两个字节的端口号,0~1023为知名的网络服务和应用

InetAddress

InetAddress类常用方法
方法声明 功能描述
InetAddress getByName(String host) 参数host表示指定的主机,该方法用于在给定主机名的情况下确定主机的IP地址
InetAddress getLocalhost() 创建一个表示本机的InetAddress对象
String getHostName() 得到IP地址的主机名,如果是本机则是计算机名,不是本机则是主机名,如果没有则是IP地址
boolean isReachable(int timeout) 判断指定的时间内地址是否可以到达
String getHostAddress 得到字符串格式的原始IP地址

UDP协议和TCP协议

UDP协议是无连接通信协议,在数据传输时,数据的发送端和接受端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接受端是否存在,就会发出数据,同样接受端在收到数据时,也不会向发送端反馈是否收到数据。一般用于音频、视频等,数据可能会丢失,但不会造成太大影响的应用,消耗资源小,通信效率高

TCP协议是面向连接的通信协议。首先客户端发送连接请求,然后服务器响应请求,最后客户端确认请求。

DategramPacket类,用于包装发送或者是接受的数据,根据发送和接收的构造方法创建不同用户端的对象。

DatagramSocket类,用于发送或者接收数据。

DatagramPacket类构造方法和常用方法
方法声明 功能描述
DatagramPacket(byte[] buf,int length) 创建DatagramPacket对象时,指定了封装数据的字节数组和数据大小,用于接受端
DatagramPacket(byte[] buf,int length,InetAddress add,int port) 创建DatagramPacket对象,指定了封装数据的字节数组和数据大小,并指定ip地址和端口号
DatagramPacket(byte[] buf,int offest,int length) 与第一个方法类似,只是指定从offest开始接受
DatagramPacket(byte[] buf,int offset,InetAddress addr,int port) 与第二个方法类似,只是增加了从offset开始发送数据
InetAddress  getAddress() 该方法用于返回发送端或者接收端的IP地址,如果是发送端的DatagramPacket对象,则返回接收端的IP,反之,返回发送端的IP地址
int  getPort() 该方法用于返回发送端或者接收端的端口号,如果是发送端的DatagramPacket对象,就返回接收端的端口号,反之,就返回发送端的端口号
byte[]  getData() 该方法用于返回将要接收或者将要发送的数据,如果是发送端的DatagramPacket对象,就返回将要发送的数据,反之,就返回接收到的数据
int getLength() 该方法用于返回接收或者将要发送数据的长度,如果是发送端的DatagramPacket对象,就返回将要发送的数据长度,反之,就返回接受到数据的长度
DatagramSocket类构造方法和常用方法
方法声明 功能描述
DatagramSocket() 该构造方法用于创建发送端的DatagramSocket对象,在创建DatagramSocket对象时,并没有指定端口号,此时,系统会分配一个没有被其他网络程序所使用的端口号
DatagramSocket(int port) 该构造方法既可用于创建接收端的DatagramSocket对象,又可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口
DatagramSocket(int port,InetAddress addr) 使用该构造在创建DatagramSocket时,不仅指定了端口号,还指定了相关的IP地址,这种情况适用于计算机多块网卡的情况,可以明确规定数据通过哪块网卡向外发送和接收哪块网卡的数据
void receive(DatagramPacket P) 该方法用于将接收到的数据填充到Datagram
void send(DatagramPacket P) 该方法用于发送DatagramPacket数据包,发送的数据包中包含将要发送的数据,数据的长度,远程主机的IP地址和端口号
void close() 关闭当前的Socket,通知驱动程序释放为这个Socket保留的资源

注意:若端口号给占用时,命令窗口输入netstat-anb命令查看当前计算机端口占用情况。

package UDP;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.*;
import javax.swing.*;

public class UDPSend extends JFrame{
	private static final int DEFAULT_PORT=8899;
	//把主窗口分为NORTH、CENTER、SOUTH三个部分
	private JLabel stateLB;                  //显示监听状态
	private JTextArea centerTextArea;        //显示聊天记录
	private JPanel southPanel;               //最下面的面板
	private JTextArea inputTextArea;         //聊天输入框
	private JPanel bottomPanel;              //放置IP输入框,按钮等
	private JTextField ipTextField;          //IP输入框
	private JTextField remotePortTF;         //端口号输入框
	private JButton sendBT;                  //发送按钮
	private JButton clearBT;                 //清除聊天记录按钮
	private DatagramSocket datagramSocket;   //用于后面功能的实现
	
	private void setUpUI() {                 //初始化Swing窗口
		//窗口初始化
		setTitle("GUI聊天");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(400,400);                    //设置窗口大小
		setResizable(false);                 //窗口大小不可调整
		setLocationRelativeTo(null);         //窗口居中
		//窗口的NORTH部分
		stateLB=new JLabel("当前还未启动监听");  
		stateLB.setHorizontalAlignment(JLabel.RIGHT);
		//窗口的CENTER部分
		centerTextArea=new JTextArea();       //聊天记录显示区域
		centerTextArea.setEditable(false);
		centerTextArea.setBackground(new Color(211,211,211));
		//窗口的SOUTH部分
		southPanel=new JPanel(new BorderLayout());
		inputTextArea=new JTextArea(5,20);    //内容输入区域
		bottomPanel=new JPanel(new FlowLayout(FlowLayout.CENTER,5,5));
		ipTextField=new JTextField("127.0.0.1",8);
		remotePortTF=new JTextField(String.valueOf(DEFAULT_PORT),3);
		sendBT=new JButton("发送");
		clearBT=new JButton("清屏");
		bottomPanel.add(ipTextField);
		bottomPanel.add(remotePortTF);
		bottomPanel.add(sendBT);
		bottomPanel.add(clearBT);
		southPanel.add(new JScrollPane(inputTextArea),BorderLayout.CENTER);
		southPanel.add(bottomPanel,BorderLayout.SOUTH);
		//添加窗口NORTH、CENTER、SOUTH部分组件
		add(stateLB,BorderLayout.NORTH);
		add(new JScrollPane(centerTextArea),BorderLayout.CENTER);
		add(southPanel,BorderLayout.SOUTH);
		setVisible(true);
	}
	
	private void setListener() {
		//为sendBT按钮添加事件监听器
		sendBT.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				//获取发送的目标IP地址和端口号
				final String ipAddress=ipTextField.getText();
				final String remotePort=remotePortTF.getText();
				if(ipAddress==null||ipAddress.trim().equals("")) {
					JOptionPane.showMessageDialog(UDPSend.this, "请输入IP地址和端口号");
					return;
				}
				//判断IP地址和端口号是否为空
				if(datagramSocket==null||datagramSocket.isClosed()) {
					JOptionPane.showMessageDialog(UDPSend.this,"监听不成功");
					return;
				}
			//获得需要发送的内容
			String  sendContent=inputTextArea.getText();
			byte[] buf=sendContent.getBytes();
			try {
				//将发送的内容显示在自己的聊天信息记录中
				centerTextArea.append("我对"
				+ipAddress+":"+remotePort+"说\n"+inputTextArea.getText()+"\n\n");
				//添加内容后使滚动条自动滚动到最底端
				centerTextArea.setCaretPosition(centerTextArea.getText().length());
				//发送数据
				datagramSocket.send(new DatagramPacket(buf, buf.length,
						InetAddress.getByName(ipAddress),Integer.parseInt(remotePort)));
				inputTextArea.setText("");
			}catch (IOException el) {
				JOptionPane.showMessageDialog(UDPSend.this, "出错了,发送不成功");
				el.printStackTrace();
			}
			}
		});
		
		//为clearBT按钮添加事件监听器
		clearBT.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				centerTextArea.setText("");  //清空聊天记录的内容
			}
		});
	}
	
	private void initSocket() {
		int port=DEFAULT_PORT;
		while(true) {
			try {
				if(datagramSocket!=null&&datagramSocket.isClosed()) {
					datagramSocket.close();
				}
				try {     //判断端口号是否在1~65535之间
					port=Integer.parseInt(JOptionPane.showInputDialog(this,"请输入端口号",
							"端口号",JOptionPane.QUESTION_MESSAGE));
					if(port<1||port>65535) {
						throw new RuntimeException("端口号超出范围");
					}
				}catch(Exception e) {
					JOptionPane.showMessageDialog(null, "你输入的端口号不正确,请输入1~65535之间的数");
					continue;      //端口不正确重新填写
				}
			//启动DatagramSocket
			datagramSocket=new DatagramSocket(port);
			startListen();        //调用startListen方法
			//在stateLB中显示程序监听的端口号
			stateLB.setText("已在"+port+"端口监听");
			break;
			}catch(SocketException e) {
				JOptionPane.showMessageDialog(this, "端口已被占用,请重新设置端口");
				stateLB.setText("当前还未启动监听");
			}
		}
	}
	
	private void startListen() {
		new Thread() {
			private DatagramPacket p;
			public void run() {
				byte[] buf=new byte[1024];
				p=new DatagramPacket(buf, buf.length);
				while(!datagramSocket.isClosed()) {
					try {
						datagramSocket.receive(p);       //接收聊天信息
						//添加聊天记录框
						centerTextArea.append(p.getAddress().getHostAddress()+":"+
						((InetSocketAddress)p.getSocketAddress()).getPort()+"对我说:\n"
								+new String(p.getData(),0,p.getLength())+"\n\n");
						//使滚动条自动滚动到最底端
						centerTextArea.setCaretPosition(centerTextArea.getText().length());
					}catch (IOException e) {
						// TODO: handle exception
						e.printStackTrace();
					}
				}
			}
		}.start();
	}
	
	//构造函数
	public UDPSend() {
		setUpUI();
		initSocket();
		setListener();
	}
	
	public static void main(String args[]) {
		// TODO Auto-generated method stub
		new UDPSend();
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41219914/article/details/84521940