一、方法的重载和重写
- 方法的重载:在类中重名且拥有不同的参数列表的方法
- 方法的重写:子类继承父类后,可以对父类中同名同参数列表的方法进行覆盖操作
从编译个运行的角度来看:
- 重载,是指允许存在多个同名的方法,而这些方法的参数列表不同。编译器根据方法不同的参数表,对同名方法的名称做修饰(区分)。对于编译器而言,这些同名方法就成了不同的方法。
它们的调用地址在编译期就绑定了
。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法
所以对于重载而言,在方法调用之前,编译期就已经确定了所要调用的方法,这称为早绑定
或静态绑定
- 而对于多态(前提之一是方法的重写),只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为
晚绑定
或动态绑定
二、throws和throw
- throw:手动抛出生成的异常对象,在方法体内使用,是异常生成阶段
- throws:捕获被抛出的异常的异常对象,在方法名处声明,是异常的处理方式之一
三、String、StringBuffer和StringBuilder
- String、StringBuffer、StringBuilder的异同
- String:不可变的字符序列;底层使用 char[] 存储;
- StringBuffer:可变的字符序列;线程安全的,效率低;底层使用 char[] 存储;
- StringBuilder:可变的字符序列;JDK5.0新增的,线程不安全的,效率高;底层使用 char[] 存储;
- 可变的字符序列——源码解析
String str = new String(); //char[] value = new char[0];
String str2 = new String(“abc”); // char[] value = new char[]{‘a’,‘b’,‘c’};
StringBuffer sb1 = new StringBuffer();// char[] value = new char[16];底层创建了一个长度是16的char数组
sb1.append(‘a’);//value[0] = ‘a’;
sb1.append(‘b’);//value[1] = ‘b’;
StringBuffer sb2 = new StringBuffer(“abc”); // char[] value = new char[“abc”.length+16];
- 扩容问题:如果要添加的数据底层数组存放不下,那就需要扩容底层的数组。默认情况下,扩容为原来的2倍 + 2,同时将原有数组中的元素复制到新的数组中
- 指导意义:开发中建议大家使用:StringBuffer(int capacity)
三者的效率
StringBuilder > StringBuffer > String
四、Collection和Collections
- Collection是存储单列数据的接口,主要的子接口有List(ArrayList,LinkedList,Vector)和Set(HashSet,LinkedHashSet,TreeSet)
- Collection是操作集合(List,Set,Map)的一个工具类,主要提供一些静态方法,如reverse(),max(),min(),sort()
五、final、finally和finalize
- final:最终的
- final可以用来修饰的结构:类、方法、变量
- final用来修饰一个
类
:表明该类不能被其他类继承,即无子类(如String类、System类、StringBuffer类)- final用来修饰一个
方法
:表明此方法不能被重写(如:Object类中getClass()方法)- final用来修饰一个
变量
:此时的“变量”就称为一个常量
3.1 final用来修饰一个属性
:可以考虑的赋值位置有:显示初始化
、代码块中初始化
、构造器中初始化
3.2 final用来修饰局部变量
:①修饰方法体中的局部变量——常量 ②修饰形参——表明该形参是一个常量,不能对其进行修改static final用来修饰属性:称为全局常量
- finally:finally中声明的是一定会被执行的代码。即使catch中又出现异常,try中有return语句,catch中有return语句等情况
一般finally存放的代码是:像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,需要我们手动的进行释放。此时的资源释放就需要声明在finally中
- finalize:Object类的一个方法,对象在被垃圾回收机制回收前会调用一次该方法
六、ArrayList和LinkedList
七、Hashmap和LinkedHashMap
八、抽象类和接口
- 相同点:
都不可以实例化,都可以包含抽象方法,都可以被继承 - 不同点:
- 抽象类有属性、方法、构造器
- 接口没有构造器,JDK7及之前,接口中只能有抽象方法和全局静态变量,JDK8可以有默认方法和静态方法,JDK9可以有私有方法
- 抽象类解决的问题:“是不是什么” VS 接口解决的问题:“能不能干什么”
九、sleep()和wait()
- 相同点:
- 一旦执行此方法,都可以使得当前的线程进入阻塞状态
- 不同点:
- 声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
- 调用的条件不同:sleep()可以在任何需要的场景中被调用,wait()只能在同步代码块或同步方法中调用(由同步监视器调用)
- 是否会释放同步监视器:如果两个方法都是在同步代码块或同步监视器中被调用,sleep()不会释放锁,wait()会释放锁
十、==和equals()
1. == :运算符
- 适用于基本数据类型和引用数据类型
- 比较基本数据类型:比较两个变量的值是否相同(数据类型不一定要相同)
- 比较引用数据类型:比较两个对象的地址是否相同(即两个引用是否指向同一个对象,注意String比较不能使用 == )
补充:==符号使用时,必须保证符号左右两边的变量类型一致
2. equals():是一个方法
- 只适用于引用数据类型
- Object类中定义的equals()和==运算符的作用是相同的,即比较两个对象的地址是否相同
- 像String、Date、File、包装类等都重写了Object类中equals()方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同
- 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同,因此,我们就需要对Object类中 的equals()进行重写
十一、synchronized和Lock的异同
- 相同点:都是用来解决线程的安全问题
- 不同点:
- synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
- Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())
十二、ArrayList、LinkedList、Vector三者的异同
- 相同点:三个类都实现了List接口,存储数据的特点(有序的、可重复的数据)相同
- 不同点
- ArrayList:①作为List接口的主要实现类;②线程不安全,效率高;③底层使用Object[] elementData存储
- LinkedList:①对于频繁的插入、删除操作,使用LinkedList效率比ArrayList高;②底层使用双向链表存储
- Vector:①作为List接口的古老实现类;②线程安全的,效率低;③底层使用Object[] elementData存储
十三、HashMap和Hashtable的异同
- 相同点:都是Map接口的实现类,存放的都是key-value数据
- 不同点
- HashMap线程不安全,效率高
Hashtable线程安全,效率低 - HashMap可以存储null的key-value,健壮性较高
Hashtable不能存储null的key-value - HashMap是Map接口的主要实现类
Hashtable是古老的实现类,JDK1.0就有了
- HashMap线程不安全,效率高
十四、CurrentHashMap和Hashtable的异同
十五、反射与封装性的疑问
1. 直接通过new的方式或反射的方式都可以调用公共的结构,开发中到底用哪个
建议:直接new的方式
2. 什么时候会使用:反射的方式
根据反射的特征——动态性,来决定
3. 反射机制与面向对象的封装性是不是矛盾,如何看待两个技术
不矛盾,面向对象的封装性相当于是对我们的建议,然后反射机制是能与不能的问题