什么是面向对象
- 面向过程更加注重每一个步骤和顺序。而面向对象更加注重做这个事情有哪些对象参与、各自需要做些什么。面向对象更易于复用、扩展和维护。
- 封装
- javabean的属性私有,getset方法
- orm框架
- 继承
- 子类继承父类,并做出自己的改变或者扩展,就是把共性的抽取为父类,子类只需要实现自己特有的方法
- 多态
父类类型 变量名 = new 子类对象
变量名.方法名()
// 无法调用子类特有的方法
JDK、 JRE、 JVM
JDK: Java开发环境
JRE:Java运行时环境
JVM:Java虚拟机
==和equals
== : 比较的是栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地址
equals:object默认也是==比较
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = str2;
System.out.println(str1==str2); //false
System.out.println(str1==str3); //false
System.out.println(str2==str3); //true
System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str3)); //true
System.out.println(str2.equals(str3)); //true
}
}
final
最终的
- 修饰类:类不可被继承
- 修饰方法:方法不可被子类覆盖,但是可以重载
- 修饰变量:变量一旦被赋值就不可以修改它的值
- 修饰成员变量
- 修饰类变量:只能在静态初始化块中指定初始值或者生命该类变量时指定初始值。
- 修饰成员变量:可以在非静态初始化块、声明该变量或者构造器中执行初始值
- 修饰局部变量
- 系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化。
- 修饰基本类型数据和引用类型数据
- 基本类型:数值一旦在初始化之后就不能改变
- 引用类型:在对其初始化之后便不能再让其指向另一个对象,但是引用的值是可改变的
- 修饰成员变量
String、 StringBuffer、 StringBuilder
- String是final修饰的,不可变,每次操作都会产生新的String对象
- StringBuffer和StringBuilder都是在原对象上操作
- StringBuffer是线程安全的,StringBuilder是线程不安全的
- StringBuffer方法都是synchronize修饰的
- 性能:StringBuilder > StringBuffer > String
- 经常改变字符串内容时使用StringBuffer、 StringBuilder
- 优先使用StringBuilder,多线程使用共享变量时使用StringBuffer
重载和重写的区别
- 重载:发生在同一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
- 重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类方法的访问修饰符为private则子类就不能重写该方法。
public int add(int a,String b)
public String add(int a, String b)
//编译报错
接口和抽象类的区别
- 接口:接口是抽象方法的集合,它只是一种形式,接口本身不能做任何事情。接口是完全抽象的,它不存在方法的实现,子类使用implements关键字实现接口,他需要提供接口中所有声明方法的实现。接口不能有构造器,是完全不同的类型,接口的默认修饰符是public,不可以使用其他修饰符。
- 抽象类:抽象类是用来捕捉子类的通用特性的,他不能被实例化,只能被用作子类的超类,抽象类可以有默认的方法实现,子类使用extends关键字来继承抽象类,如果子类不是抽象类的话,他需要提供抽象类中所有声明方法的实现。抽象类可以有构造器,除了不能实例化抽象类之外,他和普通的Java类没有任何区别,抽象方法可以有public,protect,default这些修饰符。
- 当你关注一个事物本质的时候,使用抽象类;当你关注一个操作的时候,使用接口。
List和Set的区别
- List:有序,按对象将进入的顺序保存对象,可重复,允许多个Null元素对象可以使用Iterator取出所有元素,在逐一遍历,可以使用get(int index)获取指定下标的元素
- Set:无序,不可重复,最多允许有一个null元素对象,获取元素时只能使用Iterator接口获取所有元素,在逐一遍历各个元素。
hashCode和equals
- 1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。
- equals和hashCode需要同时覆盖。
- 若两个对象equals返回true,则hashCode有必要也返回相同的int数。
- 若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高哈希表的性能。
- 若两个对象hashCode返回相同int数,则equals不一定返回true。
- 若两个对象hashCode返回不同int数,则equals一定返回false。
- 同一对象在执行期间若已经存 储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。
ArrayList和LinkedList区别
- ArrayList:基于动态数组,连续内存存储,适合下标访问,扩充机制:因为数组长度固定,超出长度存数据时需要创建新数组,然后将老的数组的数据拷贝到新的数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能,甚至超过LinkedList(需要创建大量的node节点对象)
- LinkedList:基于链表,可以存储在分散的内存中,适合数据的插入和删除操作,不适合查询:需要逐一遍历LinkedList必须使用Iterator不能使用for循环,以为每次for循环体内通过get(i)获取某一个元素时都需要对list重新遍历,性能消耗极大。另外不要试图使用indexOf等返回元素的索引,并利用其遍历,使用indexOf对list进行遍历时,当结果为空时会遍历整个列表
HashMap和HashTable区别
- HashMap是线程不安全的,单线程和多线程执行的结果可能不一样。允许key和value为null
- HashTable是线程安全的,因为其都加有synchroniz,都加有锁,所以单线程和多线程执行结果是一样的。key和value不能为null
如何实现一个IOC容器
- 配置文件配置扫描路径
- 递归包扫描获取.class文件
- 反射、确定需要交给IOC的类
- 对需要注入的类进行依赖注入
- 配置文件中指定需要扫描的包路径
- 定义一些注解,分别表示访问控制层、业务逻辑层、数据持久层、依赖注入注解、获取配置文件注解
- 从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹信息,我们将当前路径下的所有.class结尾的文件添加到一个set集合中进行存储
- 遍历这个set集合,获取在类上有指定注解的类,并将其交给IOC容器,定义一个安全的map用来存储这些对象
- 遍历这个IOC容器,获取到每一个类的实例,判断里面有其他依赖类的实例,然后进行递归注入
什么是字节码?采用字节码的好处是什么?
- 在Java中,这种供虚拟机理解的代码叫做 字节码 也就是扩展名为.class文件
- Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专一对一种特定的机器,因此,Java程序无需重新编译即可在多种计算机上运行。
Java类加载器有哪些?
- JDK自带的三个类加载器:bootstrapClassLoader、ExtClassLoader、APPClassLoader。
- bootstrapClassLoader是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%/lib下的jar包和class文件
- ExtClassLoader是APPClassLoader父类加载器,负责加载%JAVA_HOME%/lib/ext下的jar包和class类
- APPClassLoader是自定义加载类的父类,负责加载classpath下的类文件。
- 继承ClassLoader实现自定义加载类