JavaSE 第二次学习随笔(五)
/*
* 中文乱码出现的情况研究
* 注意点:乱码解决的办法是再编码再解码
* 但是如果是编码出错了,无法解决.如果是解码出错了,可以利用再编码再解码
*
*
* 编码 解码 结果
* GBK utf8 不可以(GBK2个字节,utf83个字节)
* GBK ISO8859-1 可以
* utf8 GBK 有时可以
* utf8 ISO8859-1 可以
* ISO8859-1 GBK 不可以(编码就出错了)
* ISO8859-1 utf8 不可以(编码就出错了)
*/
/*
* Properties:实质上是一个Map(HashTable)集合,存储的是属性,属性以键值对的形式存在.键值对内部的键值必须是字符串,不需要泛型
*
* 为什么要在这里将Properties?
* 因为使用与流结合
*
* 优点:
* 1.以键值对的形式存储数据
* 2.内部针对属性的存储封装了大量的专有方法:load,store,list
*/
public synchronized void load(Reader reader);
public synchronized void load(InputStream inStream); public void store(Writer writer, String comments);
public void store(OutputStream out, String comments);
以上方法都会调用load0()方法或者store0()方法,在调用时都会对其流进行包装, 包装成BufferedReader 或者 BufferedWriter;
虽然在store上没有直接的synchronized关键字保证方法同步, 但是在Writer类中对write()方法进行了锁同步(至于为什么, 应该是配置文件一般同时只有一个写流对其操作?)
在使用完流之后记得要关闭流~
/*
* 序列流:把多个输入流的内容一次性的打印(操作)---字节流 (两种方式)
*/
//创建三个输入流
FileInputStream fileInputStream1 = new FileInputStream("src\\com\\qianfeng\\test\\Demo2.java");
FileInputStream fileInputStream2 = new FileInputStream("src\\com\\qianfeng\\test\\Demo2.java");
FileInputStream fileInputStream3 = new FileInputStream("src\\com\\qianfeng\\test\\Demo1.java");
//将三个输入流放入序列流
------------------------------------------------------------------------
//方式一:先放入一个Vector
Vector<FileInputStream> vector = new Vector<>();
vector.add(fileInputStream1);
vector.add(fileInputStream2);
vector.add(fileInputStream3); //得到枚举器
Enumeration<FileInputStream> e = vector.elements();
------------------------------------------------------------------------- //方式二:先放入一个list
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(fileInputStream1);
list.add(fileInputStream2);
list.add(fileInputStream3); //将集合转换成枚举
Enumeration<FileInputStream> e = Collections.enumeration(list);
------------------------------------------------------------------------- SequenceInputStream sequenceInputStream = new SequenceInputStream(e);
FileOutputStream fileOutputStream = new FileOutputStream("filepath");
byte[] arr = new byte[1024];
int num;
while ((num = sequenceInputStream.read(arr)) != -1) {
fileOutputStream.write(arr, 0, num);
fileOutputStream.flush();
} sequenceInputStream.close();
fileOutputStream.close();
/*
* 数据流:字节流
* DataInputStream: 数据输入流
* DataOutputStream: 数据输出流
*
* 注意:数据流要与字节输入流,输出流配合使用, 如果数据类型不同, 那么写出和读入的顺序要有规则
*/
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("filepath"));
//写
dataOutputStream.writeInt(97);//4个字节
dataOutputStream.writeBoolean(true);//1个
dataOutputStream.write(33);//1个
dataOutputStream.writeDouble(34.56);//8个
//关闭流
dataOutputStream.close(); //读
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("filepath"));
dataInputStream.readBoolean();
dataInputStream.readInt();
dataInputStream.readByte();
dataInputStream.readDouble();
dataInputStream.close();
/*
* 内存流(byte数组流):
* ByteArrayInputStream:写入内存,在内部有一个数组,数据被放在这里面
* ByteArrayOutputStream:将数据取出,放在字节数组里面
*/
//创建输入流,关联一个byte型的数组,作为缓冲区数据
ByteArrayInputStream bais = new ByteArrayInputStream("hello world".getBytes()); //创建输出流-不需要指定参数
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] arr = new byte[1024];
int num;
while ((num = bais.read(arr)) != -1) {
baos.write(arr, 0, num);
} System.out.println(new String(arr)); bais.close();
baos.close(); //注意:将流关闭了之后,还可以调用方法,不会报错.
baos.write(45);
Java 序列化的高级认识 https://www.ibm.com/developerworks/cn/java/j-lo-serial/
以下是基本用法
/*
* 序列化流:是将短期存储的数据实现长期存储
* 数据的存储分成两类:
* 1.短期存储:存放在内存中,随着程序的关闭而释放---对象,集合,变量,数组
* 2.长期存储:存储在磁盘中,即使程序关闭了,数据仍然存在------文件
*
* 序列化:将数据从内存放入磁盘,可以实现数据的长久保存--数据持久化的手段
* 反序列化:将数据从磁盘放回内存
*
* 进行序列化的步骤:--通过对象的序列化讲解
* 1.创建一个类
* 2.使用对应的流将对象存入磁盘中----序列化----ObjectOutputStream
* 3.使用对应的流将对象从磁盘中取出放回内存--反序列化------ObjectInputStream
* 4.关闭流
*
* 注意点:序列化流在工作时也要关联对应的输入流和输出流
*/
//创建类用于序列化
//类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
//可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
/*
* 解释:
* 一个类如果没有实现Serializable,进行序列化会报异常:NotSerializableException
*
* 实现了Serializable接口的类可以达到的目的:
* 1.可以进行序列化
* 2.进行序列化的类的元素都必须支持序列化
* 3.接口本身没有方法或字段,只是用来表示可序列化的语义
*
* * 注意点:
* 1. ClassNotFoundException:当前的类没有找到
* 分析:将Person对象进行序列化之后,将Person类删除,再进行反序列化的时候出现了异常
* 原因:反序列化在执行的时候依赖字节码文件,当类没有了,字节码文件无法创建,反序列化失败
*
* 2.java.io.InvalidClassException 无效的类
* 出现的原因:没有声明自己的serialVersionUID,而使用系统的.在进行反序列化的时候,类被改动了,系统认为现在的类
* 已经不是原来的类了(在使用系统的id进行识别的时候,重写给Person设置了id),认为此类无效
*
* 3.使用系统的serialVersionUID与自定义的ID的区别?
* 使用系统的,序列化和反序列化,id不能手动设置,使用的是编译器默认生成的,一旦类发生了改动,id会重新赋值
* 使用自定义的,序列化和反序列化,id不会发生改变,所以当反序列化的时候,即使对Person类进行了一些改动,也能继续反序列化
* private static final long serialVersionUID = 1L;
*
* 4.总结序列化,反序列化工程的注意点:
* a.合理使用序列化流和反序列化流,要与输入流与输出流配合使用
* b.进行序列化的类一定要实现Serializable接口,只要实现了接口就可以序列化.包括集合,包装类等
* c.进行序列化的类要保证当前类与内部的类都要实现Serializable接口
*
*/
//写出--序列化
//创建序列化流并关联文件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("filepath"));
//调用方法实现序列化
//序列化后的内容不能直接查看,要想查看进行反序列化
objectOutputStream.writeObject(obj);
objectOutputStream.close(); ---------------------------------------------------------------------------------------------------- //读入--反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("filepath"));
//实现反序列化
Object object = objectInputStream.readObject(); //向下转型
/*
* ClassNotFoundException:当前的类没有找到
* 分析:将Person对象进行序列化之后,将Person类删除,再进行反序列化的时候出现了异常
* 原因:反序列化在执行的时候依赖字节码文件,当类没有了,字节码文件无法创建,反序列化失败
*/
System.out.println(object);
objectInputStream.close();
网络流部分
/*
* 网络通信:三大要素:IP,端口号,协议 1.IP:可以在网络中唯一的标记一台主机 127.0.0.1(本地地址/本机地址/保留地址)
* java中将IP面向对象了--InetAddress 2.端口:用来区分一台主机上的多个服务器(不可以重复) 取值范围:(0,65535)
* 注意点:在通信时两边的端口号要一致 3.网络协议:相当于指定的一个统一的标准
*
*
*
* 七层协议: 了解 应用层
*
* 与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的。 例如,一个没有通信功能的字处理程序就不能执行通信的代码,
* 从事字处理工作的程序员也不关心OSI的第7层。但是,如果添加了一个 传输文件的选项,那么字处理器的程序员就需要实现OSI的第7层。
* 示例:TELNET,HTTP,FTP,NFS,SMTP等。
*
* 表示层
*
* 这一层的主要功能是定义数据格式及加密。例如,FTP允许你选择以二进制 或ASCII格式传输。如果选择二进制,那么发送方和接收方不改变文件的内容。
* 如果选择ASCII格式,发送方将把文本从发送方的字符集转换成标准的ASCII后
* 发送数据。在接收方将标准的ASCII转换成接收方计算机的字符集。示例:加密,ASCII等。
*
* 会话层
*
* 它定义了如何开始、控制和结束一个会话,包括对多个双向消息的控制和管理, 以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,
* 在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。示例:RPC,SQL等。
*
* 传输层
*
* 这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同 应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。
* 示例:TCP,UDP,SPX。
*
* 网络层
*
* 这层对端到端的包传输进行定义,它定义了能够标识所有结点的逻辑地址,还定义了 路由实现的方式和学习的方式。为了适应最大传输单元长度小于包长度的传输介质,
* 网络层还定义了如何将一个包分解成更小的包的分段方法。示例:IP,IPX等。
*
* 数据链路层
*
* 它定义了在单个链路上如何传输数据。这些协议与被讨论的各种介质有关。示例:ATM,FDDI等。
*
* 物理层
*
* OSI的物理层规范是有关传输介质的特性标准,这些规范通常也参考了其他组织制定的标准。
* 连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。 物理层常用多个规范完成对所有细节的定义。示例:Rj45,802.3等。
*/
/*
* IP地址:
* java将IP地址面向对象了---InetAddress
*/
//获取自己的主机
InetAddress inetAddress = InetAddress.getLocalHost();
inetAddress.getHostName(); //HostName
inetAddress.getHostAddress(); //URI
//获取网络上任意一台主机
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");//根据域名 IP地址也可以
/*
* 网络通信
* Socket通信--TCP/UDP
*
* TCP与UDP的区别:
* TCP (建立在链接之上安全,丢包率低) UDP (类似于发快递,适合于消息的发送)
* 1.是建立在连接的基础上 建立在非连接的基础上
* 2.安全性更高 安全性低
* 3.传输速度低 速度高
* 4.适合传输数据量大的数据 数据量小的数据
* 5.必须建立连接,效率会稍低 每个数据包的大小限制在64K内
* 客户端:(app/浏览器)
* 服务器端:!=主机
*
* 端口号:同一台主机上的每一个服务器都拥有自己的端口号,取值范围(0,65535),常用的端口:80,8080
* 注意点:1.要保证客户端和服务器端的端口号一致 2.要保证同一台主机上的不同服务器端口号不同
*
* 先讲UDP:
* 注意点:在工作的时候,应该先将服务器端运行起来,处于一个监听的状态,再运行客户端
* 应用:
* UDP如QQ聊天,视频会议等
* TCP如下载等
*
* 客户端:
* 1.创建UDP通信的对象-socket对象:对应的类是DatagramSocket.(用于UDP数据的发送与接收)
* 2.数据的准备-封装包:DatagramPacket(数据包,包括相关的属性,数据)
* 3.发送数据,通过send方法
* 4.关闭socket对象
*/UDP
/*
//以下是基本概念 : Java UDP通信:DatagramSocket和DatagramPacket 来自于 https://blog.csdn.net/corozonut/article/details/71514509
UDP 是在IP网络上收发数据的传输层协议,其速度快但不可靠。为什么会使用这种不可靠的协议呢?许多应用保持最快的速度比保证每一位数据都正确更为重要,
例如实时音频或视频丢失数据只会作为干扰出现并且可以容忍;另外一些应用,利用UDP数据传输可靠性就需要在应用中进行控制。DNS、NFS、TFTP等都可以配置使用UDP协议。
我们都知道TCP是面向连接的,所谓连接就是在端点通信前建立起一条“虚电路”,利用逻辑标识来控制路由寻路,这个逻辑标识记录了目的IP、端口、虚电路标识等信息。
UDP是无需连接,每个传输单元就称为数据包,数据包上就记录了相应的路由信息,且前后传输的数据包可不相关,这就要求各数据包中记录路由信息。而TCP建立好虚电路后,
每个传输单元是不需要关心这些信息的。面向连接的TCP有诸多优点,如可靠性、拥塞可控等,但是其仅能用于端点间通信而不能用于广播或者组播通信,后两者还需要UDP发挥作用。
Java用两个类实现UDP:DatagramPacket和DatagramSocket,前者将数据字节填充到UDP包,后者收发UDP包。用法很简单,DatagramSocket收发DatagramPacket即可。
与TCP不同,UDP的socket并没有客户端和服务端的区别而统一应用此对象。
UDP向底层IP数据添加少部分内容:源端口、目的端口、IP数据部分长度和可选校验和,这些总共占用8字节。
端口、地址、数据长度和数据等信息都可以从DatagramPacket中提取或者向其设置,
以上UDPServer.java就是提取这些信息而获取客户端信息并作为回应地址的。UDP包中数据理论最大为65507(65535-20IP基本头-8UDP头),
但实际上几乎总是比这个少得多,在很多平台上往往限制在8KB,因此某些程序依赖于发送超过8KB数据的UDP包要多加小心,大多数情况下更大的包都会被简单地截取位8KB数据,
为保证最大的安全性,UDP数据部分尽量保持在512B以下。可以发现判断DatagramPacket是发数据还是收数据依据的是其构造差异。发数据在构造函数中需要指定目的Socket地址,而收数据并不需要(在生产环境中必须要考虑这边的安全策略)。
类似地,DatagramSocket在默认构造时常用于客户端——其并不关心某个本地端口,由系统指定即可;而指定端口的构造常用于服务端,意义不言而喻。
这边还有个UDP应用场景需要注意的问题,UDP服务器一般不会与客户端做太多的交互,通常可以在连接线程中直接响应客户端。不过如果需要做大量处理的话,可以创建处理线程来做此工作。
*/
//发送端
//* 1.创建UDP通信的对象-socket对象:对应的类是DatagramSocket.(用于UDP数据的发送与接收)
DatagramSocket datagramSocket = new DatagramSocket();
//* 2.数据的准备-封装包:DatagramPacket(数据包,包括相关的属性,数据, 数据包像快递一样, 需要地址自己发送...)
public DatagramPacket(byte buf[], int offset, int length, SocketAddress address);
public DatagramPacket(byte buf[], int length, InetAddress address, int port);
public DatagramPacket(byte buf[], int length, SocketAddress address);
//* 3.发送数据, 通过send方法
datagramSocket.send(datagramPacket);
//* 4.关闭socket对象
datagramSocket.close(); //侦听某个UDP端口
DatagramSocket datagramSocket = new DatagramSocket(port);
// (因为是收数据包, 不需要指定自己的地址, 只需要接收就完事了)
// 将数据读入到buf中, 使用getBytes()可以获取到buf数据
public DatagramPacket(byte buf[], int length);
public DatagramPacket(byte buf[], int offset, int length);
//调用receive(DatagramPacket)将数据从网络流接收到 packet 的 buf 数组中; receive是一个阻塞方法! 可以使用socket.setSoTimeout(ms);设置阻塞超时时间,超过时间未接收到视为数据丢失
datagramSocket.receive(packet);
packet.getData(); //byte[] 获取buf数组
TCP
IP,TCP 和 UDP, DatagramSocket 与 DatagramPacket, TCP传输 https://blog.csdn.net/mp624183768/article/details/70892015
/*
* TCP: 建立连接后,通过Socket中的IO流进行数据的传输
* 客户端
* 在客户端与服务器端通信的时候,对于客户端既要进行输入又要进行输出,所以在Socket对象的内部就内置了输入流和输出流,
* 当进行数据传输的时候,将数据放入socke对象的内部,将socket对象传到服务器端,相当于在客户端与服务器端建立了一个通道,
* 两端使用同一个socket对象.即通道仅需要建立一次就可以
*/
客户端
//1.创建Socket对象并绑定服务器的地址和端口
Socket socket = new Socket(InetAddress:InetAddress.getLocalHost(), port:22000);
//2.准备数据
String data = "BigData1712,你好";
//3.获取socket内部的输出流
OutputStream outputStream = socket.getOutputStream();
//4.将数据写入网络IO
outputStream.write(data.getBytes());
//接收从服务器传回的数据
InputStream inputStream = socket.getInputStream();
byte[] arr = new byte[1023];
int num = inputStream.read(arr);
//5.关闭资源
socket.close(); 服务端 //1.创建ServerSocket对象并绑定接口
ServerSocket serverSocket = new ServerSocket(port:22000);
//2.接收套接字的连接,保证客户端与服务器端使用同一个socket对象---对端口一直监听
Socket socket = serverSocket.accept();
//3.获取输入流
InputStream inputStream = socket.getInputStream();
//4.将内容写到控制台
byte[] arr = new byte[1023];
int num = inputStream.read(arr);
System.out.println(new String(arr,0,num));
//实现将服务器的数据写回客户端
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你好,BigData1712".getBytes());
//5.关闭资源
serverSocket.close();
反射 反射的高级运用 http://www.infoq.com/cn/articles/cf-java-reflection-dynamic-proxy
/**
* 反射
* 动态获取类的.class文件
* 并对其成员进行抽象
* 整体: 通过字节码文件直接创建对象
*/
//以下仅仅是对Java反射的基础概念,和基本方法的运用
Class cc = Class.forName("java.lang.Integer");
//获取全部的变量(无视权限)
Field[] fields = cc.getDeclaredFields();
//获取全部的方法(无视权限)
Method[] ms = cc.getDeclaredMethods();
//获取构造函数~ int.class是该方法的参数类型的class对象
Constructor constructor = cc.getConstructor(int.class);
//对Constructor 或Method 或 Field 的权限的修改改为setAccessible(true)
constructor.setAccessible(true);
//对获得的方法的调用
Object integer = constructor.newInstance(1010);
Method m = cc.getMethod("valueOf", int.class);
m = cc.getMethod("intValue");
System.out.println(m.invoke(integer));
//对获得的变量的调用
Field value = cc.getDeclaredField("value");
value.setAccessible(true);
System.out.println(value.get(integer));
JavaSE 第二次学习随笔(五)的更多相关文章
- JavaSE 第二次学习随笔(四)
---------------------------------------------------------------------------------------------------- ...
- JavaSE 第二次学习随笔(三)
* 常见异常 * 数组越界异常 * 空指针异常 * * * 特点: 当程序出现异常的时候, 程序会打印异常信息并中断程序 * 所以当同时出现多个异常的时候只能执行第一个, 后边的用不到 * * 单异常 ...
- JavaSE 第二次学习随笔(二)
循环结构中的多层嵌套跳出 targeta: for(int i = 0; i < 100; i++){ for (int j = 0; j < 100; j++) { if(i + j = ...
- JavaSE 第二次学习随笔(String的坑 + ==)
String 类是一个final类, 其内部是使用的 private final char value[]; 来存储内容, 其既可以当作一个基本类型来使用也可以当作一个类来使用;final 类(Str ...
- JavaSE 第二次学习随笔(关于内存的小题)
class HelloA { public HelloA() { System.out.println("HelloA"); } { System.out.println(&quo ...
- JavaSE 第二次学习随笔(作业一)
package homework2; import java.io.ObjectInputStream.GetField; import java.util.Arrays; public class ...
- JavaSE 第二次学习随笔(一)
Java是一种区分大小写的强类型准动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化,类型的检查是在运行时做的,优点为方便阅读,清晰明了,缺点 ...
- android 学习随笔五(界面)
把数据库内容显示到界面 清单文件设置为线性布局(5大布局属于ViewGroup) 在清单文件中可以增加View显示 LinearLayout ll = (LinearLayout) findViewB ...
- android 项目学习随笔五(JSON解析)
1.利用Xutils获取网络数据 /** * 从服务器获取数据 需要权限: <uses-permission * android:name="android.permission.IN ...
随机推荐
- matlab练习程序(多线段交点)
很简单的算法,这里是把每对线段都进行比较了. 还有一种似乎先通过x和y排序再进行交点判断的,不过那种方法我还没看太明白. 这里的方法如下: 1.根据线段的端点求两条直线的交点. 2.判断直线的交点是否 ...
- Python tqdm show progress bar
tqdm can help to show a smart progress bar, and it is very easy to use, just wrap any iterable with ...
- tr标签是什么
<tr> 标签定义 HTML 表格中的行. tr 元素包含一个或多个 th 或 td 元素.
- 【NLP_Stanford课堂】语言模型1
一.语言模型 旨在:给一个句子或一组词计算一个联合概率 作用: 机器翻译:用以区分翻译结果的好坏 拼写校正:某一个拼错的单词是这个单词的概率更大,所以校正 语音识别:语音识别出来是这个句子的概率更大 ...
- Linux(Ubuntu) 常用命令
玩儿转Linux:终端命令用法精选 最近再一次拾起了Ubuntu,为了更好的玩儿转Linux,专门到网上搜到的这些常用的终端命令,根据命令使用类别的不同分为了9个大类,都在下面一一列举了出来,个人觉得 ...
- JSP实现用户登录样例
业务描述 用户在login.jsp页面输入用户名密码登录: 如果用户名为xingoo,密码为123,则跳转到成功界面login_success.jsp,并显示用户登录的名字: 如果用户名密码错误,则跳 ...
- CSS z-index的用法
理清 position及z-index的用法: static : 无特殊定位,对象遵循HTML定位规则absolute : 将对象从文档流中拖出,使用left,right,top,bottom等属 ...
- February 24 2017 Week 8 Friday
If you fail, don't forget to learn your lesson. 如果你失败了,千万别忘了汲取教训. Frankly speaking, it is easy to ta ...
- git 解决冲突方法
转载:http://www.cnlvzi.com/index.php/Index/article/id/119 当共享一个项目后提交冲突时 git push -f 强制推送本地的替换服务端 git f ...
- 安装配置MySQL
安装yum install mysql-server设置开机启动chkconfig mysqld on启动mysql服务器service mysqld start 设置root的初试密码mysqlad ...