java的数组的长度在创建时候是固定的,所以有了arraylist。
arraylist 基于数组实现的,所以查询速度快,增删速度慢,
linklist是基于链表结构实现的,所以增删速度快,查询速度慢。
ArrayList与LinkedList
ArrayList和LinkedList顾名思义,ArrayList是Array(动态数组)的数据结构,相当于动态数组;LinkedList是Link(链表)的双向数据结构,也可当作堆栈、队列、双端队列。
对于随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据(可以在上述ArrayList代码中体现)。
ArrayList和LinkedList线程不安全,在多线程中不建议使用。hashMap也为现线程不安全,hashTable线程安全。
哈希表的本质是数组加上链表;
排序二叉树的特点为,左子树的值小于子树的根节点的值,右子树的值大于根节点的值。
排序二叉树如果插入的节点本身就是有序的,如 从小到大排列,或者从大到小排列,那么二叉树就变成了一个 链表。
所有实现了 collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator 对象的方法,
类加载阶段
加载-连接(验证、准备、解析)-初始化;
连接阶段分为 验证准备解析。准备阶段为类变量分配内存并设置类变量(static修饰的变量)的初始化(根据数据类型赋值)。对于final修饰的类变量 会根据初始值赋值。
字符串常量池,
jdk1.7之前存在于方法区中,1.7及之后存在于堆中,JDK1.7字符串常量池和静态变量被从方法区拿到了堆中。(大概是因为方法区太小了);
字符串常量值中的字符串只存在一份,且被所有线程共享。
字符串常量池中的内容是在类加载完成后,准备阶段后,在堆中生成字符串实例,然后在字符串常量池中,保存该实例的引用,记住:string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的。
class常量池简介:
我们写的每一个Java类被编译后,就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table). 从上面的反编译字节码中可以看到,Class的常量池其实就是一张记录着该类的一些常量、方法描述、类描述、变量描述信息的表。主要用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References);
每个class文件都有一个class常量池。
什么是字面量和符号引用:
字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。
字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等。 符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可(它与直接引用区分一下,直接引用一般是指向方法区的本地指针,相对偏移量或是一个能间接定位到目标的句柄)。
运行时常量池(Runtime Constant Pool):
运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,不同之处是:它的字面量可以动态的添加(String#intern()),符号引用可以被解析为直接引用
JVM在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在解析阶段,会把符号引用替换为直接引用,解析的过程会去查询字符串常量池,也就是我们上面所说的StringTable,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。
运行时常量池是一个统称, 也包括字符串常量池, 但是字符串常量池放的只是字符串, 而运行时常量池放中, 还包括类信息, 属性信息, 方法信息, 以及其他基础类型的常量池比如int, long等;
jdk1.7之前, 运行时常量池(包含着字符串常量池)都在方法区, 具体的hotspot虚拟机实现为永久代;
jdk1.7阶段, 字符串常量池从方法区移到堆中, 运行池常量剩下的部分依旧在方法区中(剩下类信息, 属性信息, 方法信息等), 同样是hotspot中的永久代
jdk1.8, 方法区的实现从永久代变成了元空间, 字符串常量池依旧在堆中, 运行时常量池在方法区中, 这个时候方法区是通过元空间实现的;
实现“继承“ 的方法:
1.继承Thread类(Override它的run方法)
2.实现Runnable接口(实现run方法)
3.使用ExecutorService、Callable、Future实现有返回结果的多线程
== 和 equals():
(1) == 用于比较基本数据类型时比较的是值,用于比较引用类型时比较的是引用指向的地址。
(2)Object 中的equals() 与 == 的作用相同,但String类重写了equals()方法,比较的是对象中的内容。
String s1= “hello world” String s2= new String(“hello world”)
s1直接指向常量池中的“HelloWorld”,s2指向堆中的对象,堆中的对象存储的是常量池中的相同字符串地址,即"HelloWorld"在常量池中的地址 == 比较的s1和s2中存储的地址,一个是常量池中的HelloWorld地址,一个是堆中的对象的地址,== 就是false(地址不同) equals比较的是最终在常量池中的内容,所以是true
方法不可以被继承?
子类继承父类 会自然的继承父类的属性和方法,当你更改子类中对应方法时才叫重写。在java中,子类构造器会默认调用super()(无论构造其中是否写有super()),用于初始化父类成员,同时当父类中存在有参构造器时,必须提供无参构造器,子类构造器中并不会自动继承有参构造器,仍然默认调用super(),使用无参构造器。因此,一个类想要被继承必须提供无参构造器。
抽象方法可以在接口和抽象类里面声明,抽象类可以没有抽象方法
1、abstract类不能用来创建abstract类的对象;2、final类不能用来派生子类,因为用final修饰的类不能被继承;3、如2所述,final不能与abstract同时修饰一个类,abstract类就是被用来继承的;4、类中有abstract方法必须用abstract修饰,但abstract类中可以没有抽象方法,接口中也可以有abstract方法。
1.强引用 , 例如 Object a= new Object();只要存在强引用 ,则不能回收。
2.弱引用 , 在内存不够时回收。
3.虚引用,只能存活到一下次垃圾回收。
4.影子引用 , 只是在回收时触发一个事件
关于final的重要知识点
1、final关键字可以用于成员变量、本地变量、方法以及类。
2、 final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
3、 你不能够对final变量再次赋值。
4、 本地变量必须在声明时赋值。
5、 在匿名类中所有变量都必须是final变量。
6、 final方法不能被重写。
7、 final类不能被继承。
8、 没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或者调用this()初始化。不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”。
数据类型转换
当使用 +、-、*、/、%、运算操作是,遵循如下规则:
只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型,如果两个操作数中有一个是float类型的,另一个将会被转换为float类型,并且结果也是float类型,如果两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型,否则(操作数为:byte、short、int 、char),两个数都会被转换成int类型,并且结果也是int类型。
语句 1 :(b1 + b2) 被转换为int类型 但是 b3仍为 byte ,所以出错 要么将b3转化为int 要么将(b1 + b2) 强制转换为byte类型。所以语句1错误。
语句 2:b4 、b5被声明final 所以类型是不会转换, 计算结果任然是byte ,所以 语句2正确。
语句 3:(b1 + b4) 结果仍然转换成int 所以语句 3 错误。
语句 4 : (b2 + b5) 结果仍然转换为int , 所以语句4错误。
①无论如何,Integer与new Integer不会相等。不会经历拆箱过程,
②两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
java在编译Integer i2 =
128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存
③两个都是new出来的,都为false
④int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比
finally中return语句会覆盖try-catch中的return语句
继承 只有两种情况:类继承类(单继承)、接口继承接口(多继承) 实现 只有一种情况:类实现接口(多实现) A 正确 B 接口可以定义成员常量 C 正确 D 类不能有子接口,只能有子类
1.java支持单继承,却可以实现多个接口。a对d错
2.接口没有构造方法,所以不能实例化,抽象类有构造方法,但是不是用来实例化的,是用来初始化的。c对
3.抽象类可以定义普通成员变量而接口不可以,但是抽象类和接口都可以定义静态成员变量,只是接口的静态成员变量要用static final public 来修饰。b错
基类就是父类。。而不是子类。
先来看一段代码:
public abstract class Test {public static void main(String[] args) {System.out.println(beforeFinally());}public static int beforeFinally(){int a = 0;try{a = 1;return a;}finally{a = 2;}}
}
/**output:
1
*/
从结果上看,貌似finally
里的语句是在return
之后执行的,其实不然,实际上finally
里的语句是在在return
之前执行的。那么问题来了,既然是在之前执行,那为什么a
的值没有被覆盖了?
实际过程是这样的:当程序执行到try{}语句中的return方法时,它会干这么一件事,将要返回的结果存储到一个临时栈中,然后程序不会立即返回,而是去执行finally{}中的程序,在执行a = 2
时,程序仅仅是覆盖了a的值,但不会去更新临时栈中的那个要返回的值。执行完之后,就会通知主程序“finally的程序执行完毕,可以请求返回了”,这时,就会将临时栈中的值取出来返回。这下应该清楚了,要返回的值是保存至临时栈中的。
再来看一个例子,稍微改下上面的程序:
public abstract class Test {public static void main(String[] args) {System.out.println(beforeFinally());}public static int beforeFinally(){int a = 0;try{a = 1;return a;}finally{a = 2;return a;}}
}
/**output:
2
*/
在这里,finally{}里也有一个return,那么在执行这个return时,就会更新临时栈中的值。同样,在执行完finally之后,就会通知主程序请求返回了,即将临时栈中的值取出来返回。故返回值是2。
finally语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句不能影响try或catch中
return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回。
switch支持10种类型 基本类型
以java8为准,switch支持10种类型 基本类型:byte char short int 对于包装类 :Byte,Short,Character,Integer String enum 2、实际只支持int类型 Java实际只能支持int类型的switch语句,那其他的类型时如何支持的 a、基本类型byte char short 原因:这些基本数字类型可自动向上转为int, 实际还是用的int。 b、基本类型包装类Byte,Short,Character,Integer 原因:java的自动拆箱机制 可看这些对象自动转为基本类型 c、String 类型 原因:实际switch比较的string.hashCode值,它是一个int类型 如何实现的,网上例子很多。此处不表。 d、enum类型 原因 :实际比较的是enum的ordinal值(表示枚举值的顺序),它也是一个int类型 所以也可以说 switch语句只支持int类型
重载与重写:
重载就是一句话:同名不同参,返回值无关。
覆盖/重写:同名同参
参数列表:个数丶类型丶参数类型顺序等