文章目录
- Java对象序列化
- 什么是序列化
- 对象的序列化主要有两种用途:
- java对象序列化为什么要使用SerialversionUID
- 如何进行序列化
- 堆 -栈 -方法区 -常量池 -静态域
- java基础
- 自动装箱
- Integer对象范围
- java中“==”与“equase”的区别
- String、StringBuffer、StringBuolder三者区别
- 三种循环语句的区别
- 什么是循环嵌套
- 跳转控制语句 ( java中break和continue的区别 )
- java中循环的不同终止方式
- 循环的终止方式详解
- 面向对象的三大特征(封装-继承-多态)
- 封装
- 继承
- 继承的好处和弊端(理解)
- 继承中变量的访问特点(掌握)
Java对象序列化
什么是序列化
概念栗子:
其实也可以这样理解,相当于快递的打包和拆包,里面的东西要保持一致,不能人为的去改变他,不然就交易不成功。
序列化与反序列化也是一样,而版本号的存在就是要是里面内容要是不一致,不然就报错。像一个防伪码一样
什么是序列化和饭序列化
- 把对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1.序列化就是将度下个的字节序列永久的保存到硬盘上.通常存放在一个文件中.
2.在网络上传送对象的字节序列
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。
比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,
于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。
发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象
java对象序列化为什么要使用SerialversionUID
进入源码
*如果可序列化类未显式声明serialVersionUID,则
*序列化运行时将计算默认的serialVersionUID值
*基于类的各个方面的类,如
*Java(TM)对象序列化规范。然而,它是强的
*建议所有可序列化类显式声明
*serialVersionUID值,因为默认的serialVersionUID计算是
*对类细节高度敏感,这些细节可能因编译器而异
*实现,因此可能导致意外的
*在反序列化过程中<code>InvalidClassException</code>s。因此,为了
*保证不同java编译器的serialVersionUID值一致
*实现时,可序列化类必须声明显式
*serialVersionUID值。同时强烈建议
*serialVersionUID声明使用<code>private</code>修饰符,其中
*可能,因为这样的声明只适用于立即声明
*类——serialVersionUID字段作为继承成员不有用。阵列
*类不能声明显式的serialVersionUID,因此它们总是
*默认计算值,但需要匹配
*数组类放弃serialVersionUID值。
如果可序列化类未显式声明serialVersionUID,则序列化运行时将计算默认的serialVersionUID值.
但如果使用了默认的serialVersionUID值.则修改了实体类的时候,实体类对象的serialVersionUID值也会改变,当你反序列化的时候,比较serialVersionUID值不一致,就抛出InvalidClassException异常
如何进行序列化
- 需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer
- 底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。
- 在 Java 中使用对象流来完成序列化和反序列化
ObjectOutputStream:通过 writeObject()方法做序列化操作
ObjectInputStream:通过 readObject() 方法做反序列化操作
Person 类(get set省略)
@Data
public class Person implements Serializable {
private static final long serialVersionUID = -5809782578272943999L;
private int age;
private String name;
private String sex;
private String address;
TestPersonSerialize 测试类
public class TestPersonSerialize {
public static void main(String[] args) throws Exception {
serializePerson();
Person p = deserializePerson();
System.out.println(p.getName()+";"+p.getAge());
}
private static void serializePerson() throws FileNotFoundException,IOException {
Person person = new Person();
person.setName("测试实例");
person.setAge(25);
person.setSex("male");
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
new File("E:/person.txt")));
oo.writeObject(person);
System.out.println("序列化成功");
oo.close();
}
private static Person deserializePerson() throws IOException, Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/person.txt")));
Person person = (Person) ois.readObject();
System.out.println("反序列化成功");
return person;
}
}
堆 -栈 -方法区 -常量池 -静态域
java基础
自动装箱
Integer a = 1;
变量a为Integer类型,而1为int类型,且Integer和int之间并无继承关系.但因为自动装箱机制的存在,在为Integer类型的变量赋int类型值时,Java会自动将int类型转换为Integer类型,即
Integer a = Integer.valueOf(1);
valueOf()方法返回一个Integer类型值,并将其赋值给变量a。这就是int的自动装箱。
Integer对象范围
Integer x = 127;
Integer y = 127;
Integer i = 128;
Integer j = 128;
System.out.println( x == y ); // true
System.out.println( i == j ); // false
疑问点:
为什么会出现这样的情况呢?引用上面的自动装箱 机制,那应该是new的对象会在堆空间开辟一块新的空间来存储数据,那这样i == j
的好理解,那x == y
的为什么会是true呢?原因说明: 我们知道。自动装箱其实是调用Integer.valueOf()
方法。那我们来看看这个方法里做了什么。我们看到。这里的注释信息写的很明确了,-128到127之间的值都是直接从缓存中取出的。如果int型参数i在IntegerCache.low和IntegerCache.high范围内,则直接由IntegerCache返回;否则new一个新的对象返回
那接着查看源码。 IntegerCache ,里面的值确实是-128 到127 之间,
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
由此。我们得出结论。当数值是-128 到127之间的时候,java虚拟机不会重新在堆 开辟空间,而是通过缓存到常量池中去找,是否已经存储了该数值,如果存在,则直接将地址值赋值给该变量。
java中“==”与“equase”的区别
- ==
如果作用于
基本数据类型
的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型
的变量,则比较的是所指向的对象的地址
- equals方法,equals 是一个方法,而不是运算符。equals方法不适用于基本数据类型,只适于引用数据类型。
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date、File、包装类等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
String、StringBuffer、StringBuolder三者区别
- 运行速度的角度
从快到慢的运行顺序为 StringBuilder > StringBuffer > String
String为字符串常量
,而StringBuilder和StringBuffer均为字符串变量
,即String对象一旦创建之后该对象是不可更改
的,StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收
的操作,所以速度要比String快很多。
- 线程角度
StringBuilder是线程不安全的,而StringBuffer是线程安全的
总结:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
三种循环语句的区别
- 三种循环的区别
for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
do...while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
- for循环和while的区别
条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,
该变量还可以继续使用
- 死循环(无限循环)的三种格式
1. for(;:){}
2. while(true){}
3. do {} while(true);
什么是循环嵌套
循环嵌套概述:在循环中,继续定义循环,
- 整个内循环,就是外循环的一个循环体,内部循环体没有执行完毕,外循环是不会继续向下执行的
- 结论:
- 外循环执行一次,内循环执行一圈
跳转控制语句 ( java中break和continue的区别 )
- 跳转控制语句(break)
- 跳出循环,结束循环
- 跳转控制语句(continue)
- 跳过本次循环,继续下次循环
- 注意: continue只能在循环中进行使用!
java中循环的不同终止方式
- break 跳出循环,结束循环(特例.如果在循环嵌套的情况下,如果break是在内层循环,则 仅终止内层循环,外层循环不会终止)
- continue 跳过本次循环,继续下次循环.()即-当次循环不执行,下次循环不影响)
- return 程序返回到调用某方法的地方
- break+标签:跳出循环到标签处,结束标签内的循环,但是不影响标签外的循环继续执行,在多重循环(循环嵌套)的最外层设置一个标签,配合break即可终止整个循环。-这里的
多重循环指的是,两层或者两层以上的循环体
- continue+标签:跳出循环到标签处,结束此次循环,从此标签处开始下一次循环
循环的终止方式详解
面向对象的三大特征(封装-继承-多态)
封装
1.封装厩述是面向对象三大特征之一(封装。继承,多态)是面向对象编程语言对客观世界的模拟,客观世界
里成员变量都是隐藏在对象内部的,外界是无法直接操作的
2,封装原则将类的臬些信息隐藏在类内部,不允许外部程序直接访问,而是涌过该类提供的方法来实现对隐藏
信息的操作和访问成员变Mprjvate,提供对应的getxxx()/setxxx()方法
3.對装好处通过方法来控制成员变量的操作的提高了代码的安全性吧代码用方法进行封装,提高了代码的复用
性
继承
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
继承的好处和弊端(理解)
- 继承好处
- 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
- 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
- 继承弊端
- 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
- 继承的应用场景:
- 使用继承,需要考虑类与类之间是否存在is…a的关系,不能盲目使用继承
- is…a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类
继承中变量的访问特点(掌握)
在子类方法中访问一个变量,采用的是就近原则。
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲…)
总结:
封装是对细节的隐藏,
继承是对共性的抽取,
多态是对类型的拓展.