JavaSE-面向对象编程(oop)


面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据。

面向对象的三大特性:

  • 封装
  • 继承
  • 多态

类与实例化对象

实例化对象的方式

  • 调用new语句创建对象
// Student.java
public class Student{
	String studentName;
	public void study(){
		System.out.print(this.studentName+"正在努力学习!");
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		// 实例化对象
		Student student = new Student();
		student.studentName = "chen";
		student.study();
	}
}
  • 调用对象的clone()方法

  • 运用反射手段创建对象

  • 运用反序列化手段,见最后。

调用静态方法无需实例化对象,而调用非静态方法需要实例化对象

  1. 类是一种抽象数据类型,它对某一类事物整体描述、定义,但并不代表某一具体事物。

  2. 对象是抽象类的具体实例。

对象的创建过程:

  1. 分配内存空间,初始化属性默认值

  2. 实例化构造器,初始化实例、实例属性

  3. 返回地址给引用

在 JVM 中,对象在内存中的表现

表现为三个区域:

  1. 对象头:

    • 标记字段:默认存储对象的HashCode,GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等。见【JavaSE-多线程】

    • 类型指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

  2. 实例数据:这部分主要是存放类的数据信息,父类的信息。

  3. 对齐填充:由于虚拟机要求对象起始地址必须是8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐。Tip:一个空对象占多少个字节?就是8个字节,是因为对齐填充的关系哈,不到8个字节对其填充会帮我们自动补齐。

构造器

什么是构造器,特点:

骨架,特点:

  • 和类名相同

  • 没有返回值

作用:

  • new 本质就是调用构造方法

  • 初始化对象的值

注意点:

  • 定义有参构造器时,必须定义无参构造器。

  • 快捷键:alt + insert

实例:

// Student.java
public class Student{

	String name;
	public Student(){
		// ... 默认空构造器,一个类即使什么都不写,它会自动存在一个方法
	}

	public Student(String name){
		// 有参构造器:一旦定义了有参构造器,无参构造器就必须显示定义。
		this.name = name;
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		// 实例化对象
		Student student = new Student("chen");
		System.out.print(student.name);
	}
}

封装

简单来说就是:属性私有、get / set。alt + insert

// Student.java
public class Student{
	// 属性私有化,只能通过设置get、set方法进行调用与赋值
	private String studentName;
	// 公共属性提供调用以及赋值
	// public String studentName;
	public String getName(){
		return this.studentName;
	}
	public void setName(String name){
		this.studentName = name;
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		// 实例化对象
		Student student = new Student();
		student.setName("chen");
		student.getName();
	}
}

单继承

ctrl + h 可以查看继承关系。

  • 在java中所有的类都是直接或间接继承Object对象,子类继承父类时父类不能使用final 修饰。

  • 在java中类只有单继承,没有多继承。

  • 通过super.xxx 继承父类属性或调用父类方法

  • 父类中私有属性或者方法无法通过super字段进行继承调用。

  • super调用父类构造方法必须在构造方法的头一个位置,且根据父类构造器(有参 / 无参)进行传值。

  • super只能出现子在子类的方法或者构造方法中。

  • super和this不能同时调用构造方法。

    • this():本身调用者这个对象,没有继承关系也可以调用,调用的是本类的构造。
    • super():代表父类对象的应用,只能在继承条件下才可以使用,调用的是父类的构造器。
  • 判断继承关系 System.out.print(x instanceof y); //=> true / false

// Parent.java
public class Parent /*extends Object*/ {
	public int money = 10_0000_0000;
	public void inheritMoney(){
		System.out.print('继承财产'+this.money);
	}
}
// Son.java
public class Son extends Parent{
	//...
}
// Main.java
public class Main{
	public static void main(String[] args){
		Son son = new Son();
		son.inheritMoney();
	}
}

super 关键字:

// Parent.java
public class Parent /*extends Object*/ {
	public int money = 10_0000_0000;
	public Parent(){
		System.out.println("Parent无参数执行了");
	}
	public void inheritMoney(){
		System.out.println('继承财产'+this.money);
	}
	/*
	私有无法通过super进行继承调用
	private void inheritMoney(){
		System.out.print('继承财产'+this.money);
	}
	*/
}
// Son.java
public class Son extends Parent{
	public Son(){
		// super(); 被隐藏了!!这里调用了父类的无参构造,必须放在第一行
		System.out.println("Son无参数执行了");
	}
	public void test(){
                                        super.money = 11_0000_0000;
		super.inheritMoney();
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		Son son = new Son();
		son.test();
		/*
			Parent无参数执行了
			Son无参数执行了
			继承财产1000000000
		*/
	}
}

重写

必须存在继承关系或者实现关系,子类重写父类方法,方法名相同,参数类型相同,关键在于判别方法是否静态,且公有。重写是方法的重写而非成员属性的重写。

  • 静态方法:方法调用只和左边(定义数据类型)有关。

  • 非静态方法:子类重写父类方法,调用时只会执行子类方法。

  • 快捷键:alt + insert : override

// Parent.java
public class Parent {
	/*
	public staic void test(){
		System.out.println("Parent");
	}
	*/
	public void test(){
		System.out.println("Parent");
	}
}
// Son.java
public class Son extends Parent{
	/*
	public staic void test(){
		System.out.println("Son");
	}
	*/
	// 重写
	@Override
	public void test(){
		System.out.println("Son");
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		Son son = new Son();
		Parent parent = new Son();
		son.test();  //=> "Son"  then  //=> "Son"
		parent.test();  //=> "Parent"  then  //=> "Son"
	}
}

多态

  • 多态是方法的多态,属性没有多态的概念。

  • 注意类型转换异常ClassCastException。

  • 存在条件:必须存在关系,方法需要重写

    • 继承关系:父类的引用指向子类对象,会进行类型的转换。

    • 实现关系:方法形参是接口,具体传入的是接口的实现类的对象

// Parent.java
public class Parent {
	public void test(){
		System.out.println("Parent");
	}
}
// Son.java
public class Son extends Parent{
	// 重写
	@Override
	public void test(){
		System.out.println("Son");
	}
	public void test2(){
		System.out.println("Son独有方法");
	}
}
// Main.java
public class Main{
	public static void main(String[] args){
		Son son = new Son();
		Parent parent = new Son();
		Object obj = new Son();
		// String son2 = new Son();  //=> error, ClassCastException
		son.test();  //=> "Son"
		parent.test();   //=> "Son"
		obj.test();   //=> "Son"
		// parent.test2();  //=> error
		// 强制转换
		((Son) parent).test2();  //=> "Son独有方法"
	}
}
// Demo.java
public interface Demo{
	void pay();
}

//Demo2.java
public class Demo2 implements Demo{
	@Override
	public void pay(){
		System.out.println("Demo2 实现Demo 的pay方法");
	}
}

//Demo3.java
public class Demo3 implements Demo{
	@Override
	public void pay(){
		System.out.println("Demo3 实现Demo 的pay方法");
	}
}

// Main.java
public class Main{
	public static void main(String[] args){
		handlePay(new Demo2());
	}
	public static void handlePay(Demo demo){
		demo.pay();
	}
}

instanceof 语法

instanceof 关键字

instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

Boolean bool = obj instanceof Class

其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

obj 必须是引用类型(对象),不是基本类型

int i = 0;
System.out.println(i instanceof Integer);//编译不通过,编译报错
System.out.println(i instanceof Object);//编译不通过,编译报错

obj 为null

一般我们知道Java分为两种数据类型,一种是基本数据类型,有八个分别是 byte short int long float double char boolean,一种是引用类型,包括类,接口,数组等等。而Java中还有一种特殊的 null 类型,该类型没有名字,所以不可能声明为 null 类型的变量或者转换为 null 类型,null 引用是 null 类型表达式唯一可能的值,null 引用也可以转换为任意引用类型。我们不需要对 null 类型有多深刻的了解,我们只需要知道 null 是可以成为任意引用类型的特殊符号。在 JavaSE规范中对 instanceof 运算符的规定就是:如果 obj 为 null,那么将返回 false。

obj 为实例对象

Integer integer = new Integer(1);
System.out.println(integer instanceof  Integer);//true

obj 为 class 接口的实现类

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList arrayList = new ArrayList();
System.out.println(arrayList instanceof List);//true

List list = new ArrayList();
System.out.println(list instanceof ArrayList);//true

集合中有个上层接口 List,其有个典型实现类 ArrayList,所以我们可以用 instanceof 运算符判断某个对象是否是 List 接口的实现类,如果是返回 true,否则返回 false。

obj 为 class 类的直接或间接子类

新建一个父类 Person.class,然后在创建它的一个子类 Man.class

public class Person {
 
}

Man.class

public class Man extends Person{
     
}

测试:

Person p1 = new Person();
Person p2 = new Man();
Man m1 = new Man();
System.out.println(p1 instanceof Man);//false
System.out.println(p2 instanceof Man);//true
System.out.println(m1 instanceof Man);//true

注意第一种情况, p1 instanceof Man ,Man 是 Person 的子类,Person 不是 Man 的子类,所以返回结果为 false。

问题

编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

看下面的例子

Person p1 = new Person();
 
System.out.println(p1 instanceof String);//编译报错
System.out.println(p1 instanceof List);//false
System.out.println(p1 instanceof List<?>);//false
System.out.println(p1 instanceof List<Person>);//编译报错

按照我们上面的说法,这里就存在问题了,Person 的对象 p1 很明显不能转换为 String 对象,那么自然 Person 的对象 p1 instanceof String 不能通过编译,但为什么 p1 instanceof List 却能通过编译呢?而 instanceof List 又不能通过编译了?

解释

obj instanceof T

  1. obj 的数据类型必须是引用类型、空类型;否则会发生编译报错

  2. 如果obj 的数据类型强制转换为T 类型时发生编译错误则表达式instanceof 就会发生编译错误,否则判定为编译通过。

所以上述的问题中为什么 p1 instanceof String 会发生编译报错,而p1 instanceof List不会发生编译报错。

instanceof 实现策略(判定true 、 false)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zEvqfbbE-1653533739206)(imgclip.png "imgclip.png")]

  1. 如果obj 时null,返回false,否则设定S 为obj 的数据类型,剩余的问题就是判断S 数据类型与T 数据类型的关系。

  2. 如S == T 返回true

  3. 接下来要做的就是“子类型检查”,而Java语言的类型系统里数组类型、接口类型与普通类类型三者的子类型规定都不一样,必须分开来讨论。

  • S是数组类型:如果 T 是一个类类型,那么T必须是Object;如果 T 是接口类型,那么 T 必须是由数组实现的接口之一;

  • S是接口类型:对接口类型的 instanceof 就直接遍历S里记录的它所实现的接口,看有没有跟T一致的;

  • S是类类型:对类类型的 instanceof 则是遍历S的super链(继承链)一直到Object,看有没有跟T一致的。遍历类的super链意味着这个算法的性能会受类的继承深度的影响。

类型转换

目的:方便方法的调用,减少重复的代码。

// Father.java
public class Father{
	public void fatherSay(){
		System.out.println("father");
	}
}

// Son.java
public class Son extends Father{
	public void sonSay(){
		System.out.println("son");
	}
}

// Main.java
public class Main{
	public static void main(String[] args){
		// 高 <-------------- 低,可以任意转换,但是会丢失子类原本的方法!
		Father obj = new Son();
		// 调用子类的方法就必须进行类型转换;
		obj.fatherSay();  //=> "father"
		// obj.sonSay();  //=> error
		Son obj2 = (Son) obj;
		obj2.sonSay();  //=> "son"
		((Son) obj).sonSay();  //=> "son"
	}
}

抽象类

特点:约束

  1. 不能new这个抽象类,自能靠子类去实现它

  2. 抽象类中可以有普通方法

  3. 抽象方法必须在抽象类中,继承的子类必须重写父类抽象方法

  4. 关键字abstract

// Father.java
public abstract class Father{
	// 抽象类中的抽象方法
	public abstract void doSomething();
	public void methods(){
		System.out.print("这不是一个抽象方法");
	}
}

// Son.java
public class Son extends Father{
	// 重写父类的抽象方法
	@override
	public void doSomething(){
		// ...
	}
}

// Main.java
public class Main{
	public static void main(String[] args){
		Father father = new Father(); //=> error,抽象类不能被new
	}
}

存在意义

可以将这个类的对象抽象出来,子类只需继承这个类重写此类的构造方法就可以,提高开发效率!

抽象类存在构造器吗

抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super()或super(参数列表)调用抽象类中的构造方法。

abstract class Demo{
	publicDemo(){
		System.out.println("无参构造器")}
}
public class Demo2 extends Demo{
	public Demo2(){
		super();
	}
	public static void main(String[] args){
		Demo2 demo2 = new Demo2();	
	}
}

---> 输出结果
无参构造器

接口类(多继承)

特点:接口类声明关键字interface 而不是class

  1. 接口中的所有方法定义其实都是抽象的,默认是public abstract

  2. 使用关键字implements 继承接口。相比于extends单继承,可实现多继承。

  3. 实现类重写接口中的方法。

  4. 接口不能被实例化,没有构造方法。

  5. 可以实例化接口的实现类,调用重写方法。

  6. 在接口中定义的成员属性是一个静态常量,默认public static final。

// UserService.java 接口类
public interface UserService{
	// 定义抽象方法
	void add(String name);
	void delete(String name);
	void update(String name);
	void query(String name);
}

// TimerService.java
public interface TimerService{
	// 定义抽象方法
	void timer(String name);
}


// UserServiceImpl.java 接口实现类
/* 多继承 */
public class UserServiceImpl implements UserService,TimerService{
	// 方法重写
	@override
	public void add(String name){

	}
	@override
	public void delete(String name){

	}
	@override
	public void update(String name){

	}
	@override
	public void query(String name){

	}
	@override
	public void timer(String name){

	}
}

内部类

定义一个类(A)中又定义了类(B)。B就是A的内部类,A就是B的外部类。

成员内部类

  1. 成员内部类:非静态的内部类可调用外部类的方法,获取外部类的属性。
// Outer.java
public class Outer {
    private static int i = 10;
    public static void out(){
        System.out.println("out");
    }
    // 定义内部类
    public class Inner{
        public void in(){
            System.out.println("in");
        }
        public void getId(){
        	// 访问外部私有属性,调用外部方法
            System.out.println(i);
            out();
        }
    }
}
// Main.java
public class Main{
	public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.getId();
    }
}

静态内部类

  1. 静态内部类:静态内部类只能访问外部静态属性
public class Outer {
    // private int i = 10;  // 静态内部类只能访问外部静态属性
    private static int i = 10;
    public static void out(){
        System.out.println("out");
    }
    // 定义内部类
    public static class Inner{
        public void in(){
            System.out.println("in");
        }
        public void getId(){
            System.out.println(i);
            out();
        }
    }
}

局部内部类

形式一:

public class Outer {
    public void out(){
        // 局部内部类
        class inner{
			public void in(){
			
			}
		}
    }
}

形式二:

public class Outer {
    public static void main(String[] args){
        Inner inner = new Inner();
        inner.in();
        UserService userService = new UserService(){
			// 这样就可以new 接口
			@Override
			public void add(){
			
			}
		}
    }
}
class Inner{
	public void in(){
			
	}
}
interface UserService{
	void add();
}

匿名内部类

public class Outer {
    public static void main(String[] args){
   		// 没有名字初始化类,不用将实例保存到变量中。
        new UserService(){
			// 这样就可以new 接口
			@Override
			public void add(){
			
			}
		}
    }
}
interface UserService{
	void add();
}

Object 类

所有类默认继承Object 类

class Cat{
    public int age;
    public String type;

    public Cat(int age, String type){
        this.age = age;
        this.type = type;
    }

    @Override
    public boolean equals(Object data){
        if(data instanceof Cat){
            Cat otherCat = (Cat) data;
            if(otherCat.age == this.age && otherCat.type == this.type){
                return true;
            }
            return false;
        }
        return false;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                ", type='" + type + '\'' +
                '}';
    }
}
public class Demo5{
    public static void main(String[] args){
        Cat cat = new Cat(1,"布偶");
        Cat cat2 = new Cat(1,"蓝短");
        System.out.println(cat.equals(cat2));
    }
}

IDEA:

	// alt+ enter
	@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Cat)) return false;
        Cat cat = (Cat) o;
        return age == cat.age && type.equals(cat.type);
    }

序列化、反序列化

序列化与反序列化

序列化:Java 对象转换为字节序列的过程。

反序列化:字节序列转换为Java 对象的过程。

idea序列化配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8InTichZ-1653533962392)(imgclip.png "imgclip.png")]

类实现Serializable,alt+enter 就可以创建序列化uid

为什么需要序列化和反序列化

当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。基本原理和网络通信是一致的,通过特殊的编码方式:写入数据将对象以及其内部数据编码,存在在数组或者文件里面然后发送到目的地后,在进行解码,读出数据。OK到此显示出来为我们所用即可。

当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

对象序列化与反序列化注意点

序列化:java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。只有实现了Serializable和Externalizable接口的类的对象才能被序列化。

反序列化:java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

class Obj {
    private String name;
    private int age;
    private String sex;

    public Obj(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public Obj() {
    }
}

public class Demo {
    public static void main(String[] args) throws IOException {
        output();
    }

    private static void output() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        Obj obj = new Obj("chen", 18, "男");
        objectOutputStream.writeObject(obj);
        objectOutputStream.close();
    }

    private static void input() throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Obj o = (Obj)objectInputStream.readObject();
        System.out.println(o);
    }
}

报错
在这里插入图片描述
序列化

解决方法:序列化的类必须实现Serializable,此时还没加uid

class Obj implements Serializable{

    private String name;
    private int age;
    private String sex;

    public Obj(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public Obj() {
    }
}

public class Demo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        output();
    }

    private static void output() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        Obj obj = new Obj("chen", 18, "男");
        objectOutputStream.writeObject(obj);
        objectOutputStream.close();
    }
    
    private static void input() throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Obj o = (Obj)objectInputStream.readObject();
        System.out.println(o);
    }
}

查看输出文件

在这里插入图片描述
所以此处的输出内容不是直接输出的,是要经过程序将其读取进来这过程叫做反序列化

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        input();
    }

输出结果是:com.study.myFile.Obj@5b6f7412

对Obj 类重写toString()再执行,发现执行结果报错

Exception in thread "main" java.io.InvalidClassException: com.study.myFile.ObjectOutputStreamTestObject; local class incompatible: stream classdesc serialVersionUID = 6762953453798583304, local class serialVersionUID = 4471594530836362455
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1963)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1829)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2120)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1646)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
    at com.study.myFile.myObjectOutputStream.main(myObjectOutputStream.java:56)

原因:在写的时候传入的类对象中没有加入toString() 方法,但是在读的时候却执行了toString() 方法,没有定义uid所以程序就认为不是同一个类,因此处理方法:

类中加入序列版本号(点击类alt + enter【Add ‘serialVersionUID’】)

class Obj implements Serializable{
	private static final long serialVersionUID = 4990315073013474645L;
    private String name;
    private int age;
    private String sex;

    public Obj(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public Obj() {
    }
    // 写的时候加不加对读没关系,只要加上serialVersionUID 认为是同一个类就行
    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Demo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        output();
        input();
    }

    private static void output() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        Obj obj = new Obj("chen", 18, "男");
        objectOutputStream.writeObject(obj);
        objectOutputStream.close();
    }
    
    private static void input() throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Jming_er\\Desktop\\javaStudy\\src\\com\\study\\a.text");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Obj o = (Obj)objectInputStream.readObject();
        System.out.println(o);  // Obj{name='chen', age=18, sex='男'}
    }
}

特定修饰符无效反序列化

(1) 如果变量加上transient 修饰读取的结果为null,或者说就不可以反序列化。

(2) 如果变量加上static 修饰读取的结果为null,或者说就不可以反序列化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值