/**
*接口
*/
interface A{
public void aaa();
public void bbb();
public void ccc();
}
/**
*抽象类
*/
abstract class B implements A{
public void aaa(){}
public void bbb(){}
}
/**
- 实现类
*/
public class C extends B{
public void aaa(){}
public void bbb(){}
public void ccc(){}
}
追问3:抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类。
课间休息,欣赏一下来自咱们SQL大腿群
美女同学的搬砖工地,坐标:西安。
========================================================================================
用于修饰类、方法和属性;
1、修饰类
当用final修饰类的时,表明该类不能被其他类所继承。需要注意的是:final类中所有的成员方法都会隐式的定义为final方法。
2、修饰方法
使用final方法的原因主要是把方法锁定,以防止继承类对其进行更改或重写。
若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。
class A{
private final void getName(){
System.out.println(“getName - A”);
}
}
public class B extends A{
public void getName(){
System.out.println(“getName - B”);
}
public void main(String[]args){
this.getName(); // 日志输出:getName - B
}
}
3、修饰变量
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
追问1:能分别说一下final、finally、finalize的区别么?
-
final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
-
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。当然,
还有多种情况走不了finally~
-
finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断。
课间休息,欣赏一下来自咱们SQL大腿群
同学的搬砖工地,坐标:北京。
北漂们猜猜具体位置是哪?
=================================================================================
序列化过程:
是指把一个Java对象变成二进制内容,实质上就是一个byte[]数组。
因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程(IO),这样,就相当于把Java对象存储到文件或者通过网络传输出去了。
反序列化过程:
把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。
以下是一些使用序列化的示例:
- 以面向对象的方式将数据存储到磁盘上的文件,例如,Redis存储Student对象的列表。
- 将程序的状态保存在磁盘上,例如,保存游戏状态。
- 通过网络以表单对象形式发送数据,例如,在聊天应用程序中以对象形式发送消息。
一个Java对象要能序列化,必须实现一个特殊的java.io.Serializable接口
,它的定义如下:
public interface Serializable {
}
Serializable接口没有定义任何方法,它是一个空接口。我们把这样的空接口称为“标记接口”(Marker Interface)
,实现了标记接口的类仅仅是给自身贴了个“标记”,并没有增加任何方法。
追问1:Java序列化是如何工作的?
当且仅当对象的类实现java.io.Serializable
接口时,该对象才有资格进行序列化。可序列化 是一个标记接口(不包含任何方法),该接口告诉Java虚拟机(JVM)该类的对象已准备好写入持久性存储或通过网络进行读取。
默认情况下,JVM负责编写和读取可序列化对象的过程。序列化/反序列化功能通过对象流类的以下两种方法公开:
-
ObjectOutputStream。writeObject(Object)
:将可序列化
的对象写入输出流。如果要序列化的某些对象未实现Serializable接口,则此方法将引发NotSerializableException
。 -
ObjectInputStream。readObject()
:从输入流读取,构造并返回一个对象。如果找不到序列化对象的类,则此方法将引发ClassNotFoundException
。
如果序列化使用的类有问题,则这两种方法都将引发InvalidClassException
,如果发生I / O错误,则将引发IOException
。无论NotSerializableException
和InvalidClassException
是子类IOException
异常。
让我们来看一个简单的例子。以下代码将String对象序列化为名为“ data.ser”的文件。字符串对象是可序列化的,因为String类实现了Serializable 接口:
String filePath = “data.ser”;
String message = “Java Serialization is Cool”;
try (
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream outputStream = new ObjectOutputStream(fos);
) {
outputStream.writeObject(message);
} catch (IOException ex) {
System.err.println(ex);
}
以下代码反序列化文件“ data.ser”中的String对象:
String filePath = “data.ser”;
try (
FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream inputStream = new ObjectInputStream(fis);
) {
String message = (String) inputStream.readObject();
System.out.println("Message: " + message);
} catch (ClassNotFoundException ex) {
System.err.println("Class not found: " + ex);
} catch (IOException ex) {
System.err.println("IO error: " + ex);
}
请注意,readObject()返回一个Object类型的对象,因此您需要将其强制转换为可序列化的类,在这种情况下为String类。
让我们看一个涉及使用自定义类的更复杂的示例。
给定以下学生班:
import java.io.*;
import java.util.*;
/**
-
Student.java
-
@author chenhh
*/
public class Student extends Person implements Serializable {
public static final long serialVersionUID = 1234L;
private long studentId;
private String name;
private transient int age;
public Student(long studentId, String name, int age) {
super();
this.studentId = studentId;
this.name = name;
this.age = age;
System.out.println(“Constructor”);
}
public String toString() {
return String.format(“%d - %s - %d”, studentId, name, age);
}
}
最后
ivate transient int age;
public Student(long studentId, String name, int age) {
super();
this.studentId = studentId;
this.name = name;
this.age = age;
System.out.println(“Constructor”);
}
public String toString() {
return String.format(“%d - %s - %d”, studentId, name, age);
}
}
最后
[外链图片转存中…(img-bDpOjBS3-1714362909548)]
[外链图片转存中…(img-FUKhdMSx-1714362909549)]
[外链图片转存中…(img-cswWGdIb-1714362909549)]