本帖最后由 小石姐姐 于 2018-4-24 16:11 编辑
多线程/网络编辑/反射
<<<多线程>>>
概念
进程: Process, 当前正在运行的程序,一个应用程序在内存中的执行程序
线程: Thread, 进程中的一个执行控制单元,执行路径;一个进程可以有一个线程,也可以有多个线程
并发: 并行发生, 同时发生, 多线程就可以实现并发
同步: 注意并不是同时的意思, 同步是指一步接一步的执行, 一个执行完毕再开始执行下一个. 单线程就是 同步
异步: 不是一步一步执行, 而是同时执行多步, 每个步骤何时结束不确定. 多线程就是异步
阻塞: 上一行代码正在执行, 还没有执行完毕, 程序就阻塞在这里了, 下一行代码必须等上一行不再阻塞后 才能执行 单线程和多线程的特点
单线程和多线程的特点
单线程: 同一时间只做一件事, 安全性高, 效率低
多线程: 同一时间做多个事情, 安全性低, 效率高
多线程的实现方式
1. 继承 Thread 类, 重写run()方法,start()方法启动
2. 实现 Runnable 接口(仍然是创建Thread类对象), 重写run()方法 ,start()方法启动
java.lang.Thread 类: 实现了 Runnable 接口 (CUP执行程序的随机性)
构造方法
Thread Thread() : 创建Thead对象
Thread Thread(Runnable r) : 通过Runnable对象创建Thread对象
Thread Thread(Runnable r, String threadName) : 通过Runnable对象创建Thread对象并指定线程名
成员方法
void start() : 启动线程, 即让线程开始执行 run() 方法中的代码
String getName() : 获取线程的名称
void setName(String name) : 设置线程名称
静态方法
static Thread currentThread() : 返回对当前正在执行的线程对象的引用
static void sleep(long millis) : 让所在线程睡眠指定的毫秒
多线程中的常见问题
共享资源定义位置: 共享资源要定义在多个线程能够共同使用的地方,
多个Thread共用同一个Runnable实现类对象, 则定义为Runnable实现类的非静态成员变量
如果只用Thread子类, 则可以定义为Thread子类的静态成员变量
操作共享数据的线程安全问题:使用同步解决
同步代码块:synchronized (锁对象) {}
同步代码块锁对象:必须是多个线程共享的对象(一个类的Class对象 如果是实现Runnable, 则可以是this)
同步方法:public (static) synchronized void method() {}
同步方法锁对象:
静态同步方法, 锁对象是: 方法所在类的Class对象
非静态同步方法, 锁对象是: this
<<<网络编程>>>
Socket(套接字):用于描述IP地址和端口,是一个
网络编程的三大要素:
IP地址:InetAddress(网络中设备的标识,不易记忆,可用主机名)
现在的IP地址使用的是32位来表示,也就是4个字节,是2进制.
实例:IP地址:192.168.1.1(中间用"."分开,这叫做点分十进制表示法,通过这样的方式让我们更方便的记忆IP地址,去修改IP地址)
InetAddress:此类表示互联网协议(IP)地址
端口号:
物理端口 网卡口
常见服务占用的端口:
80: HTTP服务
443: HTTPS服务, 安全加密的HTTP
21: FTP服务, 文件传输
22: SSH服务, 安全加密的远程登录
23: Telnet服务, 远程登录
传输协议:(其实就是一种规则和规范)
UDP协议:将数据源和目的封装成数据包中,不需要建立连接:
每个数据包的大小限制64k;
因无连接,是不可靠协议,不需要建立连接,速度快
TCP协议:建立连接,形成传输数据的通道;在连接中进行大数据传输;
通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍微低
UDP和TCP区别
UDP:用户数据报协议.
特点: (无连接,可能丢失数据,传输快)
无连接的不可靠协议
数据传输大小限制为64K(一个包)
不需要建立连接即可传输 数据发送速度快, 发送方只发送数据, 不检查接收方是否真正接收到数据, 所以数据可能有丢包 的情况
适用场景:适合实时性要求强的场合, 比如网络电话等环境, 这种协议延迟很小
TCP:传输控制协议
特点: (需连接,保证数据准确,传输慢)
需要建立连接的可靠协议
没有数据传输大小的限制
在传输前需要先建立连接(三次握手) 它的重发机制保证了数据传输的准确性, 但因为需要接收方发回验证信息, 所以数据发送时间长, 数据流量大
适用场景:这种方式适合准确性要求强的场合, 比如金融系统, 视频点播, 用户可以等待数据传输但是不能 忍受错误
InetAddress概述和测试
java.net.InetAddress 类: 用于表示IP地址对象 (InetAddress的实例包含 IP 地址,还可能包含相应的主机名)
静态方法
static InetAddress getLocalHost() : 获取本机的InetAddress对象
static InetAddress getByName(String host) : 根据主机名或IP的字符串获取主机的InetAddress 对象
static InetAddress getLoopbackAddress() : 获取回环地址的InetAddress对象.
static InetAddress getByAddress(byte[] addr) : 根据IP获取InetAddress对象
成员方法
String getHostAddress() : 返回主机的IP地址
String getHostName() : 返回主机名
UDP协议发送数据
java.net.DatagramSocket 类: 基于UDP协议的Socket
构造方法
DatagramSocket() : 创建DatagramSocket对象, 随机分配端口号
DatagramSocket(int port) : 创建DatagramSocket对象, 指定端口号
成员方法
void send(DatagramPacket p) : 发送数据包
void receive(DatagramPacket p) : 接收数据, 数据保存在DatagramPacket对象中
void close() : 关闭通信, 释放资源
java.net.DatagramPacket 类: UDP数据包
构造方法
DatagramPacket(byte[] msg, int msgLength, InetAddress host, int port) : 创建数据包对象, 指定数据, 目标主机对象, 端口
DatagramPacket(byte[] buf, int length) : 创建数据包对象, 接收数据为length的数据, 存入byte 数组中 成员方法
InetAddress getAddress() : 获取数据包发送方的InetAddress对象
byte[] getData() : 获取包中的数据, 以byte数组形式
int getLength() : 获取数据包中数据的长度, 即byte数组的长度
int getPort() : 获取发送方端口号
UDP发送数据步骤:
// 1. 为发送端创建Socket对象(DatagramSocket)
DatagramSocket datagramSocket = new DatagramSocket();
// 2. 创建数据并打包
DatagramPacket datagramPacket = new DatagramPacket(byte数组, 数组长度, InetAddress对象, 端口号);
// 3. 发送数据
datagramSocket.send(datagramPacket);
// 4. 释放资源
datagramSocket.close();
UDP发送数据步骤:
// 1. 创建接收端Socket对象:
DatagramSocket datagramSocket = DatagramSocket(接收方端口号);
// 2. 接收数据
DatagramPacket datagramPacket = new DatagramPacket(byte数组, 数组长度); datagramSocket.receive(datagramPacket);
// 该方法会阻塞等待接收数据
// 3. 解析数据
InetAddress inetAddress = datagramPacket.getAddress(); // 获取发送方IP地址
byte[] bytes = datagramPacket.getData(); // 获取数据
int dataLength = datagramPacket.getLength(); // 获取数据长度
String s = new String(bytes, 0, dataLength);
// 4. 输出数据
System.out.println(s);
// 5. 释放资源:
datagramSocket.close()
UDP收发数据注意事:
端口绑定异常: java.net.BindException: Address already in use: Cannot bind : 端口已经被占用
解决办法:改一下端口或者关闭被占用的端口呗
TCP协议发送数据
java.net.Socket 类: 基于TCP协议的Socket, 作为客户端
构造方法
Socket(InetAddress add, int port) : 创建TCP客户端对象
成员方法
OutputStream getOutputStream() : 获取输出流对象, 用于发送数据
InputStream getInputStream() : 获取输入流, 用于接收数据
void close() : 释放资源
TCP发送数据步骤
// 1. 创建客户端Socket对象(建立连接)
Socket socket = new Socket(InetAddress地址, 端口号);
// 2. 获取输出流对象
OutputStream outputStream = socket.getOutputStream();
// 3. 发送数据
outputStream.write(byte数组);
// 4. 释放资源
socket.close();
TCP发送数据注意事项:
连接失败异常: ConnectException: Connection refused: connect : 连接被拒绝, 无法创建连接. 一般是因为网络不通, IP地址不存在等导致无法连接
解决办法: 确认必须有接收端, 且可以连接
TCP发接收数据步骤
java.net.ServerSocket : TCP服务端
构造方法
ServerSocket(int port) : 创建一个TCP服务端, 并监听指定端口
成员方法
Socket accept() : 监听数据, 会阻塞. 收到数据后返回Socket对象
void close() : 关闭Socket
// 1. 创建服务端ServerSocket对象:
ServerSocket serverSocket = new ServerSocket(端口号); // 指定要监听的端口号
//2. 监听数据
Socket socket = serverSocket.accept(); // 该方法会阻塞, 直到有客户端连接
// 3. 获取输入流对象
InputStream inputStream = socket.getInputStream();
// 4. 获取数据
int dataLength = inputStream.read(装数据的byte[]数组); String s = new String(byte[], 0, dataLength);
// 5. 输出数据
System.out.println(s);
// 6. 释放资源:
socket.close();
serverSocket.close();
<<<反射>>>
反射:在运行时,我们可以获取任意一个类的所有方法和属性;在运行时,让我们调用任意一个对象的所有方法和属性
反射的前提:
要获取类的对象(Class对象)
获取字节码对象:
1.类对象调用getClass()方法获取
Student s = new Student();
Class clazz = s.getClass();
2.类名调用class属性获取
Class clazz = Student.class;
3.Class类的forName()方法获取
Class clazz = Class.forName("Text01.Studnet");
获取类对象
1. T newInstance() 获取字节码对象所表示的类的对象(该方法是Class类下的方法)
获取Javabin的构造方法对象
1. Constructor<T> getConstructor(Class<?>... parameterTypes) 返回参构造方法对象(指定public修饰的构造)
2. Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回参构造方法对象(所有构造)
3. Constructor<?>[] getConstructors() 返回所有构造方法对象数组的对象(指定public修饰的构造)
4. Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象数组的对象(所有构造)
5 T newInstance(Object... initargs) 获取字节码对象所表示的类的对象(该方法是Constructor类下的方法)
获取类的成员变量对象
1. Field getField(String name) 返回指定字段的成员变量的对象(指定public修饰的成员变量)
2. Field getDeclaredField(String name) 返回指定字段的成员变量的对象(所有成员变量)
3. Field[] getFields() 返回一个包含所有成员变量的数组对象(指定public修饰的成员变量)
4. Field[] getDeclaredFields() 返回一个包含所有成员变量的数组对象(所有成员变量)
获取类的成员变量的值
1. Object get(Object obj) 获取指定成员变量对象的字段值
2. void set(Object obj, Object value) 通过指定成员变量对象,修改该成员变量的字段值为指定字段值(指定Public修饰的成员变量的字段值)
3. void setAccessible(boolean flag) 设置反射时取消Java的访问权限,暴力访问(设置为true时,取消Java访问权限)
注意:
(1)get方法只能获取Public修饰的成员变量的字段值如果想获取私有成员变量的字段值需要调用父类( AccessibleObject类)的void setAccessible(boolean flag)方法
(2)getDeclaredField(String name)等获取私有成员的方法,仅仅只是获取到私有成员,而不能访问,如果想访问必须设置取消访问权限,即使用void setAccessible(boolean flag)方法
获取类的成员方法对象
1. Method getMethod(String name, Class<?>... parameterTypes) 返回指定成员方法的对象(指定public修饰的成员方法)
2. Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回指定成员方法的对象(所有成员方法)
3. Method[] getMethods() 返回所有成员方法对象数组的对象(指定public修饰的成员方法)
4. Method[] getDeclaredMethods() 返回所有成员方法对象数组的对象(所有成员方法)
Method方法:
1. Object invoke(Object obj, Object... args) 执行方法
JavaBean概述和规范
JavaBean规范: 是一个类,用于封装数据,
使用public进行修饰
提供私有修饰的成员变量
为成员变量提供公共的get/set方法
提供公共无参的构造
实现序列化接口(Serializable)
BeanUtils概述
BeanUtils: Apache commons提供的一个组件,主要功能就是为了简化JavaBean的封装数据操作
作用: 利用反射技术给一个类的对象的成员属性赋值或获取值, 用于快速封装数据到JavaBean
Jar包:Java ARchive, 后缀名为 .jar , 是一个压缩文件, 里面包含编译后的class文件和说明信息
作用: jar包中是写好的代码编译出来的class文件, 有了这些类文件, 就可以调用其中的方法
导入jar包的步骤
项目根目录下创建名为 lib 的目录 --> 复制jar文件粘贴到项目根目录下的 lib 目录下 --> 选中项目中的jar包, 右键, 选择 Build Path , 点击 Add to Build Path .
此时项目中的 Referenced Libraries 中会出现jar包名称的奶瓶, 说明已经添加成功 导入的jar包整个项目都能使用
方法:
1. static void setProperty(Object bean, String name, Object value) 给JavaBean对象的成员变量进行赋值
2. static String getProperty(Object bean, String name)
3. static void populate(Object bean, Map properties)
注意:BeanUtils的setProperty和getProperty方法底层并不是直接操作成员变量,而是操作和成员变量名有关的set和get方法
|