这里写目录标题
try代码块的执行顺序
执行顺序的详细讲解
总结:
try {
//执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
}catch {
//除非try里面执行代码发生了异常,否则这里的代码不会执行
}finally {
//不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
}
以下题输出什么呢
public static void main(String[] args) {
System.out.println(val());
}
public static int val() {
int num = 5;
try {
num = num / 0;
} catch (Exception e) {
num = 10;
} finally {
num = 15;
}
return num;
}
注: 在finally语句块中中没有return;
语句的话,会按顺序往下执行。
对象的克隆的使用和一些概念
序列化的概念与使用
文章摘自https://blog.youkuaiyun.com/u013870094/article/details/82765907
序列化和反序列化的概念
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
作用:
- 有些信息我们想让他持久的保存起来,那么就用序列化。就是把内存里面的这些对象给变成一连串的字节描述的过程。常见的就是变成文件。
- 序列化后的文件都是乱码,一个对象的数据是不可能直接看到的。
什么情况下需要序列化
当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
当你想在网络上传送对象的时候;
当你想通过RMI传输对象的时候;
如何实现序列化
实现Serializable接口即可
上面这些理论都比较简单,下面实际代码看看这个序列化到底能干啥,以及会产生的bug问题。
先上对象代码,飞猪.java
package com.lxk.model;
import java.io.Serializable;
/**
* @author lxk on 2017/11/1
*/
public class FlyPig implements Serializable {
//private static final long serialVersionUID = 1L;
private static String AGE = "269";
private String name;
private String color;
transient private String car;
//private String addTip;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
//public String getAddTip() {
// return addTip;
//}
//
//public void setAddTip(String addTip) {
// this.addTip = addTip;
//}
@Override
public String toString() {
return "FlyPig{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", car='" + car + '\'' +
", AGE='" + AGE + '\'' +
//", addTip='" + addTip + '\'' +
'}';
}
}
注意下,注释的代码,是一会儿要各种情况下使用的。
下面就是main方法啦
package com.lxk.test;
import com.lxk.model.FlyPig;
import java.io.*;
/**
* 序列化测试
*
* @author lxk on 2017/11/1
*/
public class SerializableTest {
public static void main(String[] args) throws Exception {
serializeFlyPig();
FlyPig flyPig = deserializeFlyPig();
System.out.println(flyPig.toString());
}
/**
* 序列化
*/
private static void serializeFlyPig() throws IOException {
FlyPig flyPig = new FlyPig();
flyPig.setColor("black");
flyPig.setName("naruto");
flyPig.setCar("0000");
// ObjectOutputStream 对象输出流,将 flyPig 对象存储到E盘的 flyPig.txt 文件中,完成对 flyPig 对象的序列化操作
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/flyPig.txt")));
oos.writeObject(flyPig);
System.out.println("FlyPig 对象序列化成功!");
oos.close();
}
/**
* 反序列化
*/
private static FlyPig deserializeFlyPig() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt")));
FlyPig person = (FlyPig) ois.readObject();
System.out.println("FlyPig 对象反序列化成功!");
return person;
}
}
对上面的2个操作文件流的类的简单说明
ObjectOutputStream代表对象输出流:
它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream代表对象输入流:
它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
实际运行结果,他会在 d:/flyPig.txt 生成个文件。
从运行结果上看:
1,他实现了对象的序列化和反序列化。
2,transient 修饰的属性,是不会被序列化的。我设置的奥迪四个圈的车不见啦,成了null。my god。
serialVersionUID 的作用和用法
serialVersionUID非必需但很有必要,如果自己不声明,在实现了Serializable接口后,JVM会动态的生成。原则上,序列化后的数据中的serialVersionUID与当前类当中的serialVersionUID一致时,对象才能够反序列化成功。在序列化过程种,系统将serialVersionUID写入到序列化的文件中,反序列化时,首先检测文件中的serialVersionUID和当前类的serialVersionUID是否一致,如果一致则反序列化成功,否则报错:java.io.InvalidClassException
。
反序列时怎么知道序列化对象是否一致呢
FlyPig person = (FlyPig) ois.readObject();
在读到这里时,会读取flyPig.txt
中的serialVersionUID,在与强转为(FlyPig)
或者与引用类型的类进行序列化比对,发现不一致,就会报错。
serialVersionUID 的一些概念。 取消属性 addTip 的注释,这之后,再次执行反序列化方法,看现象。
/**
* 反序列化
*/
private static FlyPig deserializeFlyPig() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt")));
FlyPig person = (FlyPig) ois.readObject();
System.out.println("FlyPig 对象反序列化成功!");
return person;
}
抛异常:InvalidClassException 详情如下。
InvalidClassException: com.lxk.model.FlyPig;
local class incompatible:
stream classdesc serialVersionUID = -3983502914954951240,
local class serialVersionUID = 7565838717623951575
**原因:**如果自己不声明,JVM会使用根据类的结构动态的生成serialVersionUID,类发生改变serialVersionUID会发生变化。我保存的时候,也就是我序列化的时候,那时候还没有这个addTip属性呢,所以,自动生成的serialVersionUID 这个值,在我反序列化的时候Java自动生成的这个serialVersionUID值是不同的,他就抛异常啦。
再来一次,就是先序列化,这个时候,把 private static final long serialVersionUID = 1L; 这行代码的注释打开。那个addTip属性先注释掉
序列化之后,再把这个属性打开,再反序列化。看看什么情况。
下面解释这个 serialVersionUID 的值到底怎么设置才OK。
首先,你可以不用自己去赋值,Java会给你赋值,但是,这个就会出现上面的bug,很不安全,所以,还得自己手动的来。
那么,我该怎么赋值,eclipse可能会自动给你赋值个一长串数字。这个是没必要的。
可以简单的赋值个 1L,这就可以啦。。这样可以确保代码一致时反序列化成功。
匿名内部类
文章摘自https://www.jianshu.com/p/0950c6787c7d
文章摘自https://www.cnblogs.com/wuhenzhidu/p/anonymous.html
什么是匿名内部类
如果在一个类里面定义一个类,那么这个类就是内部类,外面的那个类就是外部类,这个很好理解。内部类就相当于外部类的一个成员,你可以把内部类看成一个整体。内部类分为:静态内部类,非静态内部类。匿名内部类是非静态内部类的一种特殊情况,匿名内部类没有类名,因此就不可能有构造函数,不能创建对象。(构造器名与类名一样,匿名类没有没有类名)
为什么会有匿名内部类
说白了,就是因为想偷懒,不想写太多代码。如果可以,程序员完全可以通过实现接口或者继承抽象类的方式来实现而不用创建匿名内部类。但是使用匿名内部类的优点是显而易见的,可以少些代码,而且代码更加简洁。
匿名内部类的定义
先看匿名内部类的定义的语法格式:
new 实现接口()
{
//匿名内部类类体部分
}
new 父类构造器(实参列表)
{
//匿名内部类类体部分
}
为什么匿名内部类的定义有这两种方式呢?这是因此这两种方式的定义分别对应两种方式,一种是接口,另一种是抽象类(普通类也可以,但没有必要的使用场景)。
对于实现接口,由于接口是没有构造函数的,注意这里一定是空参数。
第二种是调用父类的构造器,注意此处可以是空参数,也可以传入参数。
使用匿名内部类
案例一,实现接口的匿名类:
public class HelloWorldAnonymousClasses {
2
3 /**
4 * 包含两个方法的HelloWorld接口
5 */
6 interface HelloWorld {
7 public void greet();
8 public void greetSomeone(String someone);
9 }
10
11 public void sayHello() {
12
13 // 1、局部类EnglishGreeting实现了HelloWorld接口
14 class EnglishGreeting implements HelloWorld {
15 String name = "world";
16 public void greet() {
17 greetSomeone("world");
18 }
19 public void greetSomeone(String someone) {
20 name = someone;
21 System.out.println("Hello " + name);
22 }
23 }
24
25 HelloWorld englishGreeting = new EnglishGreeting();
26
27 // 2、匿名类实现HelloWorld接口
28 HelloWorld frenchGreeting = new HelloWorld() {
29 String name = "tout le monde";
30 public void greet() {
31 greetSomeone("tout le monde");
32 }
33 public void greetSomeone(String someone) {
34 name = someone;
35 System.out.println("Salut " + name);
36 }
37 };
}
public class AnimalTest {
private final String ANIMAL = "动物";
public void accessTest() {
System.out.println("匿名内部类访问其外部类方法");
}
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void printAnimalName() {
System.out.println(bird.name);
}
}
// 鸟类,匿名子类,继承自Animal类,可以覆写父类方法
Animal bird = new Animal("布谷鸟") {
@Override
public void printAnimalName() {
accessTest(); // 访问外部类成员
System.out.println(ANIMAL); // 访问外部类final修饰的变量
super.printAnimalName();
}
};
public void print() {
bird.printAnimalName();
}
public static void main(String[] args) {
AnimalTest animalTest = new AnimalTest();
animalTest.print();
}
}