static、final、transient、volatile关键字的作用,foreach循环的原理、java原生序列化及Xstream方式序列化
static
英文翻译静态的
1.修饰变量
2.修饰方法
3.静态代码块
4.静态内部类
5.静态导包 语法import static 1.import static ....ClassName.*;2.import static ...ClassName.具体方法;
package com.liuzhihong.test; import org.junit.Test; import static java.lang.Integer.*; import static java.lang.System.out; /** * @ClassName Test2 * @Description * @Author 刘志红 * @Date 2019/7/17 **/ public class Test2 { @Test public void test() { out.println(compare(1, 3)); } }
final
英文翻译最终的
1.修饰类不被继承
2.修饰方法不能被重写
3.修饰变量
包括成员变量和局部变量(包括行参)。修饰行参的时候只能调用时候赋一次值,后面这个变量就不能被修改了。
具体指引用不可变,内容可变;所以即使是赋相同的值也会报错,因为引用不能指向其他对象;对基本类型来说赋值右边的是常量;引用指向常量后不可变了;对引用数据类型来说,引用指向对象,对象本身可以改变内容;final修饰数组无意义,因为数组本身不可变。
transient
英文翻译短暂的
说到这个关键字首先就要提到序列化
平时我们在Java内存中的对象,是无法进行IO操作或者网络通信的,因为在进行IO操作或者网络通信的时候,人家根本不知道内存中的对象是个什么东西,因此必须将对象以某种方式表示出来,即存储对象中的状态。一个Java对象的表示有各种各样的方式,Java本身也提供给了用户一种表示对象的方式,那就是序列化,其他方式例如JSON化,XML化,当前也有比较好用的序列化工具,比如Google的protobuf。换句话说,序列化只是表示对象的一种方式而已。OK,有了序列化,那么必然有反序列化,我们先看一下序列化、反序列化是什么意思。
序列化:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。
反序列化:将字节数组重新构造成对象。
java 的transient关键字的作用是需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
transient使用小结
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
例:
//准备序列化的实体类
package com.liuzhihong.test; import java.io.Serializable; /** * @ClassName Person * @Description 序列化类 * @Author 刘志红 * @Date 2019/7/17 **/ public class Person implements Serializable { private String name; private transient Integer id; public Person() { } public Person(String name, Integer id) { this.name = name; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", id=" + id + '}'; } }
//进行序列化测试 package com.liuzhihong.test; import org.junit.Test; import java.io.*; /** * @ClassName Test2 * @Description * @Author 刘志红 * @Date 2019/7/17 **/ public class Test2 { @Test public void test() { Person person=new Person("xiaoqiang",22); //序列化前 System.out.println(person.toString()); //序列化 String filePath="D://Person.obj"; ObjectOutputStream os; ObjectInputStream oi; try { os=new ObjectOutputStream(new FileOutputStream(new File(filePath))); os.writeObject(person); //序列化person对象 oi=new ObjectInputStream(new FileInputStream(new File(filePath))); Person personNew = (Person) oi.readObject();//反序列化 System.out.println(personNew.toString()); } catch (Exception e) { e.printStackTrace(); }
finally{
os.close();
oi.close();
} } }
测试结果:
Person{name='xiaoqiang', id=22}
Person{name='xiaoqiang', id=null}
volatile
英文翻译不稳定的
volatile修饰的变量值发生变化时候,会强制将修改后的值写入主存中。
非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值
volatile和synchronized的比较
他们修饰变量,方法,代码块的时候
可见性 有序性 原子性 线程阻塞
volatile 有 有 无 无
synchronized 有 有 有 有
volatile不会让线程阻塞,响应速度比synchronized高
可见性:当多个线程访问同一个变量x时,线程1修改了变量x的值,线程1、线程2...线程n能够立即读取到线程1修改后的值
有序性:即程序执行时按照代码书写的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。
例:
package com.liuzhihong.test; /** * @ClassName Test3 * @Description * @Author 刘志红 * @Date 2019/7/17 **/ public class Test3 { private volatile int num = 0; public void inc() { num++; } public static void main(String[] args) throws InterruptedException { final Test3 t=new Test3(); for (int i = 0; i < 10; i++) { new Thread(() -> { for (int j = 0; j < 1000; j++) { t.inc(); } }).start(); } Thread.sleep(5000); System.out.println(Thread.activeCount()); //保证前面的线程都执行完 while (Thread.activeCount()>2) Thread.yield(); System.out.println(t.num); } }
运行结果我们发现 不能保证每次运行的结果都是10000 大多数情况是小于10000的。
foreach原理
对于集合来说foreach调用的是iterator()方法迭代,因为集合实现了Iterator接口
对于数组来说foreach是调用for循环
Xstream序列化
在transient我们说到IO或者网络传输的时候对象需要序列化后才能被识别,序列化的方式很多。上面有java原生的序列化。在纯java环境中使用,java自带的序列化反序列化可以很好的工作因为他是java自带的,不需要其他第三方jar包。但是在多语言环境下,用它序列化存储后很难用其他语言还原出来。而且序列化后占据的字节数比较大,序列化和反序列化效率比较低。
这里用Xstream进行序列化
1.通过XStream中的toXML()进行序列化成字符串str;可以用一个FileWriter把这个str存入磁盘,也可以用一个HttpClient传输这串str进行网络通信。
2.通过XStream中的fromXML()进行反序列化;
代码如下:
package com.liuzhihong.test; import com.liuzhihong.entity.Person; import com.thoughtworks.xstream.XStream; import org.junit.Test; /** * @ClassName Test * @Description * @Author 刘志红 * @Date 2019/7/18 **/ public class XStreamTest { //序列化 @Test public void test1(){ Person person=new Person("xiagou", 2, new int[]{1,2,3,4,5}); XStream xStream=new XStream(); String str = xStream.toXML(person); System.out.println(str); System.out.println("------------------------------------------"); //可以自定义序列化出来的格式 Person person1=new Person("小强", 3, new int[]{1,2,3,4}); xStream.alias("Person",Person.class); xStream.aliasField("Name", Person.class, "name"); xStream.aliasField("Id", Person.class, "id"); xStream.aliasField("Count", Person.class, "count"); String str1 = xStream.toXML(person1); System.out.println(str1); } //反序列化 @Test public void test2(){ String str="<Person>\n" + " <Name>小强</Name>\n" + " <Id>3</Id>\n" + " <Count>\n" + " <int>1</int>\n" + " <int>2</int>\n" + " <int>3</int>\n" + " <int>4</int>\n" + " </Count>\n" + "</Person>"; XStream xStream=new XStream(); //带别名的序列化结果反序列化的时候必须也要把别名对应关系写全了 xStream.alias("Person",Person.class); xStream.aliasField("Name", Person.class, "name"); xStream.aliasField("Id", Person.class, "id"); xStream.aliasField("Count", Person.class, "count"); Person person = (Person) xStream.fromXML(str); System.out.println(person); } }
XStream支持基本的数据类型,也支持数组集合等;
详情引用自:https://www.cnblogs.com/xrq730/p/4823684.html
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!