Java查缺补漏
变量
- 局部变量
方法或语句块内部定义的变量。
生命周期从声明位置开始到方法或语句块结束。
使用前必须先初始化。
- 成员变量(实例变量)
方法外部、类内部定义的变量(未被static修饰)。
生命周期伴随对象始终,从属于对象。
成员变量会自动初始化。
- 静态变量(类变量)
类内部通过static修饰符定义的变量。
生命周期伴随从类加载到卸载,从属于类。
在定义时就必须初始化它。
基本数据类型
首先,Java种数据类型分为 基本数据类型 和 引用数据类型 。
- java中共有3类8种基本数据类型
数值型:byte(1字节8位)、short(2字节16位)、int(4字节32位)、long(8字节64位)、float(4字节32位)、double(8字节64位)。
布尔型:boolean(true/false)1位,不是1字节,底层就是0或1.
字符型:char(unicode码)2位,因此可以用于表示中文字符。
- 引用数据类型
类(比如说String、enum)
接口
数组
byte | 1字节8位 | 2^8个数,范围在-128~127 | 拿出1位表示符号 |
short | 2字节16位 | 2^16个数,-32768~32767 | 大约可表示正负3万 |
int | 4字节32位 | 2^32个数,-2^31~2^31-1 | 大约可表示21亿 |
long | 8字节64位 | 2^64个数,-2^63~2^63-1 | Long赋值后要加L |
- Java整型常量的四种表示形式
十进制整数
八进制整数:以0开头,比如015(是十进制的13)
十六进制整数:以0x开头,比如0x15(是十进制的21)
二进制整数:以0b开头,比如0b00000001
- 浮点型变量/常量(浮点数是不精确的,一定不要用于比较)
float(单精度):4字节 float复制后要加F
double(双精度):8字节
- 字符型变量/常量
char:2字节
System.out.print('a'+'b'); 输出195,将a与b转换为对应的数字相加。
- boolean类型变量/常量
boolean只有两个值true或false,在内存中仅占1位,而不是1字节。
算术运算
- 整数运算
1.两个操作数中1个位long时,结果也为long;
2.没有long时,结果位int。即使操作数位byte、short,结果也为int。
- 浮点运算
1.两个操作数中一个为float时,结果也为float;
Java值传递
Java中方法调用传递时遵循值传递原则(传递的都是数值的副本)。
基本类型传递的也是值的副本。
引用类型传递的是该对象的地址值,指向同一个对象,也是值传递。
方法重载和方法重写
- 方法重载
发生在同一个类中
具体表现位同一个返回值类型、方法名,但是不同的参数类型、参数个数。
- 方法chon冲洗
发生在继承关系间
具体表现位子类继承父类的方法后,对父类中的方法进行重写,
要求返回值类型、方法名、参数列表完全相同,
重写方法的权限修饰大于等于父类,
返回值类型和声明异常类小于等于父类。
面向对象和面向过程
总结:
- 都是解决问题的思维方式,都是代码组织的方式。
- 解决简单问题可以使用面向过程
- 解决复杂问题宏观上使用面向对象,围观处理仍使用面向过程思想。
面向对象的内存分析
Java虚拟机(JVM)内存可以分为三个区域:栈stack、堆heap、方法区method area(本质上也是堆)。
- 栈的特点如下:
1.栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)。
2.JVM为每一个线程创建一个栈,用于存放线程执行方法的信息。
3.栈属于线程私有,不能进行线程间的共享。
4.栈的存储特征是“先进后处,后进先出”,类比弹匣子弹的压入和射出。
5.栈是由系统自动分配,速度快,是一个连续的存储空间。
- 堆的特点如下:
1.堆用于存储创建好的对象(就是new出来的)。
2.JVM只有一个堆,被所有线程所共享。
3.堆是一个不连续的空间,分配灵活,但是速度慢。
- 方法区
1.JVM只有一个方法区,被所有线程共享。
2.方法区实际也是堆,只是用于存储类、常量相关的信息(代码、静态变量、静态方法、字符串常量)。
3.用来存放程序中永远是不变或唯一的内容。
垃圾回收机制
相关算法:
- 引用计数器法
引用计数器法就是在创建的每一个对象,虚拟机都进行相应计数,该对象实例被变量引用则加1,超过生命周期或者被赋予新值则减1,最后变为0则成为回收的对象被回收。
缺点:无法识别循环引用对象。比如父类引用了子类对象,而子类对象又引用了父类对象。
- 引用可达法(跟搜索算法)
从一个节点开始找,如果发现有一个对象没有被关联,则认为它是无用的,就可以干掉。
通用的分代垃圾回收机制
JVM将堆内存划分为年轻带Eden、幸存代Survivor和年老代Old三个空间
- 当年老代满则diao调用FulGC,用于清理年轻带和年老代区域。成本较高,会带系统性能产生影响。
- 因此性能优化,垃圾回收优化很多时候就是针对Full GC。
创建对象
分如下四步:
1.创建对象空间,并将对象的成员变量初始化为0或null;
2.执行属性值显式初始化;
3.执行构造方法;
4.返回对象的地址给相关的变量。
参数传值机制
Java中,方法中所有参数都是“值传递“,也就是传递的是”值的副本“;
引用类型传递的是”对象的地址“,也就是传递的是”地址的副本“。
继承
继承成员变量:
1.子类只能继承父类的public、protected修饰的成员变量,不可以继承private修饰的成员变量,对于默认修饰(default或friendly表示同包)则与父类在同一包下的子类可以继承。
2.需要注意的是,当子类出现与父类中成员变量同名的子类成员变量,则会发生隐藏,即子类”替代“了父类的同名成员变量,若要在子类中访问父类的成员变量,需要使用super()关键字。
继承成员方法:
1.子类只能继承父类的public、protected修饰的成员变量,不可以继承private修饰的成员变量,对于默认修饰(default或friendly表示同包)则与父类在同一包下的子类可以继承。
2.那么子类与父类重名的成员方法就成为了重写,重写的规则再写一遍,以作复习。1.方法名、参数列表完全相同;2.返回值类型、异常类型小于等于父类;3.访问权限,子类大于父类。
==和equals
“==”比较符号两侧双方是否相同,基本类型则比对值是否相等,引用类型则比对地址是否相等。
equals继承于Object,如果不重写默认通过"=="判断地址是否相同。需要时进行重写。
Super
super关键字是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性。
构造方法写与不写都是super(...);
因此子类构造器默认先调用父类构造器。
数组
数组初始化初始化三种方式:
静态初始化:int[] a = {2,89,101};
默认初始化:int[] b = new int[3];
动态初始化:int[] c = new int[2];
c[0] = 1;
c[1] = 2;
多态的内存分析
创建对象并初始化时,子类构造器调用父类构造器,父类构造器一级一级向上回溯至Object类,最后再创建完成子类对象的初始化。
内部类
作用:1.提供了更好的封装。只能让外部类访问,不允许同一个包中的其他类直接访问。
2.内部类可以直接访问外部类的私有属性。但外部类不能直接访问内部类的内部属性。
普通内部类:访问时需要通过外部类访问。
静态内部类:不可以访问外部类非静态成员变量。
字符串(String、StringBuilder、Stringbuffer)
首先,String是不可变字符序列。
需要注意的是:
String str1 = new String("abcd");
String str2 = new String("abcd");
str1.equals(str2); //返回true
str1==str2; //返回false
String str3 = "def";
String str4 = "def";
str3.equals(str4); //返回true
str3==str4; //返回true
内存图:
String str = new String(''aa"); //堆区产生了两个对象
for(int i = 0;i < 1000;i++){
str += i;
}
最终产生了1002个对象
内存图:
StringBuilder
StringBuilder是可变字符串序列。相比于StringBuffer,两者中的方法完全一致,除了所有的方法都添加同步锁,因此对于字符串来说,StringBuffer是线程安全的,但是低效率的,StringBuilder则相反。
StringBuilder sb1 = new StringBuilder(); //默认字符数组长度为16
StringBuilder sb2 = new StringBuilder(32); //字符数组为32
- 数组扩容
StringBuilder通过append()方法进行拼接,实际上在内存中是新建一个字符数组,并且将长度扩大为原数组长度的两倍并加2.
也就是内存中原字符数组长度如果为16,拼接后不够,如何保证字符数组容量足够以保证字符串是可变的呢?那么就要新开辟一个数组,并且容量是16*2+2=34;然后把原数组内容复制进来。其中会调用确保容量函数和扩大容量函数,一个用于检测容量是否足够,不够的话调用扩容函数函数。
ArrayList
底层是Object数组
数组的拷贝
System的方法arraycopy(Object src, //原数组对象
int srcPos, //原数组开始拷贝的位置
Object dest, //目标数组
int destPos, //目标数组起始位置
int length) //要拷贝的长度
Arrays中的方法:
sort:整型则从小到大排序,存放对象则需要自己定义方法进行排序。
binarySearch:二分法查找。需要先通过sort排序,才可以进行二分法查找。
fill(a,2,4,100)表示对a数组对象进行从下表2开始到4(包头不包尾)的元素替换为100;
这次先到这里。。持续查缺补漏