【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/129740905
出自【进步*于辰的博客】
之前这篇文章中包含了一些我总结的开发经验,由于考虑到将开发经验和java知识点放在同一篇文章会让大家阅读起来很麻烦,于是我把之前那些经验总结提取到了这篇文章【Java开发细节、经验锦集】。
java.lang.Class
类Java_API浅析;参考笔记二,P26.6、P29.4。
参数列表不同、或返回值类型不同、或都不同的同名方法称之为“重载”。与访问权限无关,其作用是增加代码可读性。注意:
main()
也可重载,默认情况下执行参数类型为String[]
的main()
;参考笔记二,P29.3。
与父类方法参数列表相同、返回值类型相同的同名方法称之为“重写”。注意:
参考笔记二,P39.7、P45.2。
1、new xx()
2、反射
3、xx.clone()
4、反序列化
clone()
属Object类方法,使用clone()
的类必须实现Cloneable
接口和重写clone()
。其中,克隆的对象是一个新对象,克隆分为浅克隆 和深克隆 两种,两者的区别是当克隆的类中引用其他类时,深克隆会同时克隆引用类,而浅克隆不会,仍是同一个。深克隆的实现原理是在相应clone()
内克隆引用类。
参考笔记一,P31.5、P32.2~5;笔记三,P15.2。
这张是反射的过程图,我曾在博文【关于对Java反射的理解与运用】中使用过。那篇文章中阐述:
图中的 B → D,通过类加载器 ClassLoader 将 class字节码文件 加载进JVM方法区、生成 class 信息、进而创建 Class 对象,这个过程就是 类加载 \color{red}{类加载} 类加载。(注:只有对类的主动使用才会触发类加载,例如:反射、实例化)
下述对此流程进行详述。
Person p1
中的p1
初始就是符号引用,经过解析转为内存地址,常说的“引用就是内存地址”就是这个意思。static int a = 10
(在静态代码块之外)。(前提:存在父类)
前2项在类初始化时执行,后4项在实例化时执行。
编译 → 类加载 → 实例初始化 → 实例化
;参考笔记一,P40.7。
参考笔记一,P34.3。
super()
必须在构造方法的第一行? \color{grey}{必须在构造方法的第一行?} 必须在构造方法的第一行?从第2点可知,子类初始化时会同时初始化父类,但并不能知道super()
在第一行的原因。因为父类的初始化数据存储于子类内存空间(具体指堆),即便后续调用(先初始化子类,后初始化父类)也可访问。因此,super()
在第一行的原因是:子类要为父类分配内存空间,自然要先知道父类占多少空间,即先初始化父类。参考笔记一,P33.7、P34.1、P35.2/3;笔记二,P26.5。
private
修饰部分;父类拥有子类所有,只是无法使用子类扩展部分。故经过上溯或下溯转型,都可使用相应资源;instanceOf
判断;super
并不代表父类引用,只是用于调用父类成员 \color{green}{并不代表父类引用,只是用于调用父类成员} 并不代表父类引用,只是用于调用父类成员。getClass()
是 Object 类的 final 方法(不可重写),故super.getClass()
等同于this.getClass()
,返回的是当前对象所属类的 Class 对象。参考笔记一,P1、P2.3。
序列化指将对象 转为字节序列、实现将对象持久化(永久保存)到磁盘、使对象能在网络 或进程间 传递的过程。
(注:实现序列化的类必须实现Serializable
接口;若此类引用了其他类,则相应类也必须实现此接口。)
持久性。
将对象转为字节序列存于磁盘,即使JVM死机,对象仍然存于磁盘。当JVM宕机时,可以通过反序列化还原对象,并且,序列化的对象占据更小的磁盘空间;
序列化的对象在网络上传输会更快捷、更安全;
可实现在进程间传递对象。
“进程间”是什么意思?因为无论程序复杂或简单,在启动时,JVM都只会创建一个进程,而进程间无法直接传输对象。
示例:
private static final long serialVersionUID = -5809782578272943999L;
这就是序列化ID,其在类加载时生成,用于作为类在JVM内存中的唯一标识。其作用是通过比较字节序列中的序列化ID和实体类中的序列化ID是否一致来判断是否为同一个类,即是否可反序列化,从而还原对象。
“序列化”与“反序列化*”是一种实现对象持久化的概念,具体实现方法任意。如下示例中使用
ObjectOutputStream
实现序列化,使用ObjectInputStream
实现反序列化是其中一种实现方法。
1、序列化:将对象 Person
序列化到 Person.txt
文件中。
看下述代码:
@AllArgsConstructor
class Person implements Serializable {
private static final long serialVersionUID = -5809782578272943999L;
private Integer id;
private String name;
}
class TestSerializable {
public static void main(String[] args) throws Exception {
Person person = new Person(1001, "yuchen");
System.out.println(person);// 打印:Person(id=1001, name=yuchen)
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\于辰\\Downloads\\新建文件夹\\Person.txt")));
oos.writeObject(person);
}
}
2、反序列化:将 Person.txt
文件中的字节序列 通过反序列化还原成 Person
对象。
看下述代码:
class TestSerializable {
public static void main(String[] args) throws Exception {
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\于辰\\Downloads\\新建文件夹\\Person.txt")));
Person person = (Person) ois.readObject();
System.out.println(person);// 打印:com.neusoft.boot.Person@69d0a921
}
}
rs.getTimestamp()
(rs是结果集ResultSet对象)获取Timestamp对象,再使用SimpleDateFormat类将其转为String。下述阐述需要计算不同位二进制的表示范围,引用博文【mysql知识点锦集】的第1项中的“求数据类型取值范围的计算通式”。虽然Java与Mysql属不同体系,但是数据类型的取值范围是相同的。因此,大家可以此博文作为参考。
参考笔记二,P65.1。
两个结论: \color{green}{两个结论:} 两个结论:
int
类型采用有符号二进制存储,char
类型采用无符号二进制存储。引用那篇博文中关于数据类型数值范围的计算通式:
int类型占4个字节,char类型占2个字节,先计算一下这两种类型的数值范围:
int
类型数值范围:-2{8*4-1} ~ 2{8*4-1} - 1 = -2.147483648E9 ~ 2.147483647E9
;(有符号二进制)char
类型取值范围:-2{8*2-1} ~ 2{8*2-1} - 1 = -32768 ~ 32767
;(有符号二进制)0 ~ 65535
。字节长度:int > char
,故int类型转为char类型属显式转换。但有一个 特例 \color{red}{特例} 特例:
当转为char类型的整型数据是常量,且数值在char类型的数值范围之内时,可隐式转换。
说明示例:
1、将数值在char类型取值–数值范围内的int常量转为char类型。
char c1 = -1;//----------A
char c2 = 65536//;-------B
char c3 = 0;//-----------C
char c4 = 65535;//-------D
char类型的数值范围是: 0 ~ 65535
。故A、B编译报错,而C、D转换成功。
2、将int
常量转为char
类型。
int a1 = 100;
final int a2 = 100;
char c5 = a1;// 编译报错
char c6 = a2;// 转换成功
尽管100
在char类型的取值范围内,但a1是变量,故编译报错;而a2以及举例1中的都是常量,故转换成功。
float类型与int类型都占4个字节,且都采用有符号二进制进行存储,但在float中,整数部分占8位,小数部分占23位。
因此,float类型的数值范围是:-2{8*1-1} ~ 2{8*1-1} - 1 = -128 ~ 127
。即-128.0 ~ 127.999999...
。
补充说明: \color{green}{补充说明:} 补充说明:
因为小数的二进制表示方法我暂未作研究,故此范围目前还不是很明确,仅供大家参考。
全称Object Relational Mapping(对象关系映射),指实体类与数据表一一对应,属性与字段一一对应,而实例/对象对应记录,即将对象“存入”数据表中。常用的ORM框架:mybatis、mybatis-plus、hibernate。
优点:
缺点:降低程序性能。
select
到程序中),再进行过滤和加工,这会降低程序性能;package
参考笔记二,P29.6。
package
是用来组织源文件的一种虚拟文件系统;import
的作用是引入,而不是拷贝,目的是告诉编译器编译时应去哪读取外部文件;import
而直接调用(不是指实例化时用全类名)。关于 IPv4,相关类 → Inet4Address类。
参考笔记一,P75.2。
概述:
ipv4 由4部分组成,包含网络地址 和主机地址,每部分解释为一个字节。故都是0 ~ 255
的整数。因此,ipv4 占4个字节(32位)。
分类:(注:a
指网络地址,b
指主机地址)
0
。因此,范围是:0.0.0.0 ~ 127.255.255.255
;10
。因此,范围是:128.0.0.0 ~ 191.255.255.255
;110
。因此,范围是:192.0.0.0 ~ 223.255.255.255
;1110
。因此,范围是:224.0.0.0 ~ .239.255.255.255
;1111
。因此,范围是:240.0.0.0 ~ 255.255.255.255
。static
static
。因为由static
声明或定义的变量为所有拥有它的对象共享,而内部类属于外部类,故内部类的static
变量为所有外部类的对象共享,这会导致内部类被提升为外部类、则内部类中的局部变量将无意义。除非是静态内部类;常量仅能在声明static int a = 10
或构造器(包括:代码块、构造方法)内赋初值。
static
的原因若没有static,则属于对象成员,则在每个对象实例化时都会创建一个副本,占据堆空间;而声明为static,则会在类加载时被加载进方法区的全局数据访问区中,即只有一个副本,节省空间。并且,声明为static,还可以在静态代码块中赋初值。
参考笔记二,P20。
什么是“编译”? \color{grey}{什么是“编译”?} 什么是“编译”?
“编译”是指将源代码一次性转换成目标程序的过程,编译只执行一次,故编译的着重点不是编译速度,而是目标程序的运行速度。因此,编译器一般都会尽可能多地集成优化技术,使生成的目标程序具有更高的执行速度。
特点: \color{red}{特点:} 特点:
什么是“解释”? \color{grey}{什么是“解释”?} 什么是“解释”?
“解释”是指将源代码逐条转换并同时运行的过程,不会生成目标程序,故解释的着重点是解释速度。因此,解释在每次程序运行时都需要解释器和源代码,也不能集成太多的优化技术,这样会降低程序的运行速度。
特点: \color{red}{特点:} 特点:
“编译”与“解释”的运用: \color{green}{“编译”与“解释”的运用:} “编译”与“解释”的运用:
高级语言按照执行方式分为 静态语言 \color{blue}{静态语言} 静态语言和 脚本语言 \color{purple}{脚本语言} 脚本语言。静态语言使用编译,如:C/C++、java;脚本语言使用解释,如:python、js、php。
在实际运用中,会将两者混合使用,以实现在保证程序逐条运行的同时保留目标程序,因为程序逐条运行能大大提升程序运行速度,保留目标程序便于程序纠错和维护。
本文持续更新中。。。