当前位置: 移动技术网 > IT编程>开发语言>Java > JavaSE 第二次学习随笔(五)

JavaSE 第二次学习随笔(五)

2018年08月27日  | 移动技术网IT编程  | 我要评论

 

/*
* 中文乱码出现的情况研究
* 注意点:乱码解决的办法是再编码再解码
* 但是如果是编码出错了,无法解决.如果是解码出错了,可以利用再编码再解码
*
*
* 编码 解码 结果
* 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 来自于
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));

  

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网