IT`huhui前言录
这是自己对JAVA基础的一个小总结,会不断完善。因为时间仓促的原因。
每学习一段时间,停下来,静心总结一下,甚好。停停走,走走停,一往无前,不摔倒。
一些链接里面是我看到一些人理解后写出来很好的文章然后我转载过来的。
原创博文,大家转载的意欲,请附带上以下信息:
来自:IT`huhui的个人博客
作者:胡伟汇
链接: 原文链接
Java程序的运行方式
源程序(.java文件)→Java编译器进行编译→字节码(.class文件)→JVM解释执行
JAVA内存分配机制
stack (栈) 存放局部变量和方法调用
heap (堆) 存放new出来的对象,实例对象的存在于对象所属的heap空间上
data segment(变量区) 静态变量和字符串变量
code segment (代码区) 存放代码
注意区分好局部变量,实例变量,静态变量存放的不同区域。
变量 | 生命周期 |
静态变量 | 在类被加载时进行初始化,生命周期与类的生命周期相关 |
实例变量 | 存放在对象所属的heap空间上,生命周期和实例的对象相关 |
局部变量 | 局部变量和方法的参数都被生命在方法当中, 生命周期与方法被放在stack上的时间相关, 就是方法调用执行完毕,则生命周期结束 |
例子:
public class Sample
{
private static c = 3;//静态变量
private int a=1; //实例变量
public void b()
{
int a=2; //局部变量
System.out.println("局部变量:a="+a);
System.out.println("实例变量:a="+this.a);//局部变量的作用域内引用实例变量:this.变量名
}
public static void main(String[] args)
{
new Sample().b();
}
}
局部变量:2
实例变量:1
静态变量:3
附图:
标识符和命名规范
标识符只能由字母、数字、下划线、$所组成,其中不能以数字开头,
不能是java中的关键字(保留字),驼峰式命名,大小写敏感,无长度限制。
命名规范:
Package的命名
由一个小写单词组成
Class的命名
必须由大写字母开头而其他字母都小写的单词组成
Class变量的命名
必须用一个小写字母开头,后面的单词用大写字母开头。
Static Final变量的命名
Static Final 变量的名字应该都大写,并且指出完整含义,单词直接用下划线分隔。
面向对象- 封装
封装:又叫隐藏实现,就是通过类把数据和行为封装起来,隐藏算法或业务逻辑的实现过程,只公布必要的接口(方法)给使用者调用。
封装是面向对象的基础,目的是提高软件的可复用性和可维护性
面向对象 -继承
- 继承:在现有类的基础上构建新的类,当继承一个现有类时,就重用(继承)了那个类的方法和字段,同时还可以向新类中增添新的方法和字段。
继承的过程是一个从一般多特殊的过程,表示的是is-a关系。 - 只支持单继承,不允许多继承。
- 继承中的构造方法:
- 子类的构造过程中 必须 调用到父类的构造方法。
- 子类可以在自己的构造方法中使用super来调用父类的构造方法。
- 如果使用 this(参数)方法 会调用本类的另外的构造方法。
- 如果调用 super方法 必须在子类构造方法的第一行。
JAVA 多态(动态绑定)
多态:在执行期间 (而非编译期间)判断所引用对象的实际类型,根据其实际的类型调用相对应的方法
多态存在的必要条件
1. 有继承(或接口实现)
2. 要有重写
3. 父类引用指向子类对象
静态多态:方法重载,编译期绑定。
动态多态:方法重写,即父类类型子类形态,是在执行期间判断所引用对象的实际类型,根据实际类型调用其相应的方法,而不是根据引用的类型来调用方法。
动态多态是面向对象的核心,可以让现有的程序调用未来的代码,提高程序的可扩展性。
Object 类的 equals
必须是同一个对象才返回true 否则返回 false
String,Date 类等某些类对equals进行了重写,举例,在String中equals对比的是值,但是”==”比较的是内存地址。
子类没有明确些调用父类的构造方法。则系统默认调用父类的无参数构造函数
如果父类没有无参构造函数,子类又没明确调用父类构造方法,编译出错
JAVA 权限控制
对于class的权限修饰符只可以用public和default
public类可以在任意地方被访问
default类只可以被同一个包内的类访问
JAVA方法的重写和重载
方法重写
- 对父类继承来的方法进行重写。
- 重写的方法要与被重写的方法具有相同方法名称,参数列表和返回类型
- 重写方法不能比被重写方法更严格的访问权限
方法重载
方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数
值传递原则
基本类型传递的是该数值本身。引用类型传递的是对对象的引用,不是对象本身
异常分类
throwable
- error 系统本身错误 由虚拟机生成并且抛出
- exception 可以处理的异常 一般需要用户捕获
+ runtimeException 用户可以不处理
RuntimeException:运行期异常,可以通过优化代码避免,可以不用try,catch处理
Other Exception:必须在程序中捕获。
try{
有可能出现异常的代码块
}catch(Exception e){
处理捕获到的异常
}finally{
无论异常情况出现与否,都需要执行的一些操作
}
finally块的作用:try结束后,无论是否捕获到Exception,finally总被执行,因此实际应用中,通常可以用finally块来执行一些必须的资源回收工作。
程序执行流程进入try,但不执行finally的特殊情况
1、System.exit()
2、多线程工作时,由于死锁无法执行到finally
throw抛出异常对象
throws声明方法有抛出异常的可能
定义自己的异常类:继承自Exception
Collection 容器
集合主要有Collection和Map接口。
List特点:元素有放入顺序,元素可重复
Map特点:元素按键值对存储,无放入顺序
Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的)
集合与数组的区别
A、数组是同构的,集合可以是异构的
B、数组是定长的,集合可以动态增长
Map
HashMap是基于哈希表,底层采用“数组+链表”实现。
LinkedHashMap它继承自HashMap,保留插入的顺序,底层使用哈希表与双向链表来保存所有元素。
TreeMap实现了Map的子接口SortedMap,
采用红黑树作为底层存储结构,提供了按照键排序的Map存储。
使用TreeMap按照Key排序(String已经实现了Comparable接口)
1、让集合中的对象实现java.lang.Comparable接口
2、定义一个自己的比较器类实现implements java.util.Comparator接口,传入到集合。
遍历
map.entrySet().iterator();
map.keySet().iterator()
负载因子
负载因子 * 容量 > map大小 —–>调整Map大小。
例如:如果负载因子大小为0.75(HashMap的默认值),
默认容量为11,则 11 * 0.75 = 8.25 = 8,
所以当我们容器中插入第八个元素的时候,Map就会调整大小。
HashMap非线程安全,轻量级容器,支持null
Hashtable线程安全,重量级容器,不支持null
Properties继承自Hashtable。
Set
HashSet底层由HashMap实现
HashSet有以下特点
1、不能保证元素的排列顺序,顺序有可能发生变化
2、不是同步的
3、集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,
然后根据 hashCode值来决定该对象在HashSet中存储位置。
LinkedHashSet继承自HashSet,底层使用LinkedHashMap实现
SortedSet接口有一个实现类:TreeSet(底层由平衡二叉树实现)
HashSet去重
1、重写hashCode,不要返回相同的hashCode,选择31这个素数相乘结果避免hash地址冲突。
2、重写equals
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
result = 31 * result + age;
result = 31 * result + passport.hashCode();
return result;
}
TreeSet的去重和排序都是通过调用compareTo来判断(并不会调用hashCode和equals方法),即排序和去重都是要用相同的属性。
遍历
迭代器或for循环
List
ArrayLis底层实现:数组,非线程安全,查询性能好,容量增长为原来0.5倍
Vector底层实现:数组,线程安全,容量增长为原来的1倍
LinkedList底层实现:双向链表,非线程安全,修改效率高
测试数据:
ArrayList 添加到尾部 快,实测13毫秒
LinkedList 添加到尾部 慢,实测22毫秒
ArrayList 添加到头部 慢,实测976毫秒
LinkedList 添加到头部 快,实测25毫秒
结论:
1、频繁在头部或靠前的地方添加删除数据的情况,使用LinkedList
2、频繁在尾部或靠后的地方添加删除数据的情况,使用ArrayList
3、大部分情况应该优先使用ArrayList,除非经过数据测试ArrayList确实比LinkedList慢。
迭代器或for循环
Collections.synchronizedList
Collections.sort
- 在这里记录下Set和List 用迭代器遍历方法
//LIST
for(Iterator iter =list.iterator(); iter.hasNext();){
String str=(String )iter.next();
System.out.println(str);
}
//Set
Set keyset = mapmysql.keySet();
for (Iterator iterator = keyset.iterator();iterator.hasNext();){
int key = (int) iterator.next();
int values = (int) mapmysql.get(key);
}
比较器——Comparable
- 实现Comparable,编写compareTo()方法
public Song implements Comparable<Song>{
String title;
String artist;
String rating;
String bpm;
public int compareTo(Song s) {
return title.compareTo(s.getTitle());
}
}
- 另一种sort()方法,取用Comparator参数
- 创建并实现Comparator的内部类。用compare()方法替代了compareTo()方法。
- 调用重载的sort(),传入list和CompareTo的实例。
//这里举个在《Head First Java》里面看到的例子。
public class Jukebox5{
ArrayList<Song> songList = new ArrayList<Song>();
public static void main(String [] args){
new Jukebox5().go();
}
class ArtisCompare implements Comparator<Song>{
public int compare(Song one ,Song two ){
return one.getArtist().compareTo(two.getArtist());
}
}
public void go(){
System.out.println(songList);//排序前
ArtistCompare artistCompare = new ArtistCompare ();
Collection.sort(songList , artistCompare);
System.out.println(songList);//排序后
}
}
集合与数组的区别
A、数组是同构的,集合可以是异构的
B、数组是定长的,集合可以动态增长
数组
区分:
- 数组对象的内存图:
- 数组元素为引用数据类型的内存图
1、声明数组
1) 一组相同类型(可以是类)数据的集合;
2) 一个数组是一个对象;
3) 声明一个数组没有创建一个对象;
4) 数组能以下列形式声明:
int[] i 或 int i[]
Car[] c 或 Car c[]
2、创建数组
1) 创建原始数组 int[] i = new int[2];
2) 创建类类型数组 Car[] c = new Car[100];
3) 数组创建后有初始值。
3、初始化数组
1) 初始化、创建、和声明分开
int[] i;
i = new int[2];
i[0] = 0;
i[1] = 1;
2) 初始化、创建、和声明在同一时间
int[] i = {0,1};
Car[] c = {new Car(),new Car()};
4、多维数组
5、数组长度和迭代