1、static
1.1、作用
-
为特定类型或者对象分配单一的存储空间,而与创建对象的个数无关。
-
实现某个方法与类而不是与对象关联。
1.2、原理
-
静态资源是在类初始化的时候加载出来的,而非静态方法是在类new的 时候加载出来的。
-
静态资源,是实例间共享的,换言之,只要一处改变,那就全部都改变。
-
调用可以直接类名.方法名,或者就是类名.属性名
-
非静态可以调用静态,但是反过来就不行,因为静态是在类初始化的时候就初始化了
1.3、静态块
- 静态代码块里面的代码执行一次,且只在初始化类的时候执行
- 静态资源的加载顺序是严格按照静态资源的定义顺序来加载的
- 没有初始化的类变量,默认值就是0
- 父类静态块 → 子类静态块 → 父类块 → 父类构造器 → 子类块 → 子类构造器
2、final
2.1、作用
- 可以用来修饰引用,方法和类
2.2、引用
- 如果为基本类型,例如int 则应用为常量,无法修改
- 如果为数据类型,例如对象,数组,数组对象本身可以修改,但是指向该对象或者数组的地址不能修改
- 如果引用是类的成员变量,那必须当场赋值,否则报错
2.3、方法
- 当修饰是方法时,那么这个方法就是最终方法,无法被子类重写,但是,还是可以继承的。
2.4、类
- 当修饰是类的时候,那么这个类就是最终类,这个类无法被继承。比如说String就是最终类。
3、overload和override
3.1、重写
- 重写是子类对父类允许访问的方法实现过程重新进行编写,返回值和形参都不变,即外壳不变,核心重写
- 好处是子类可以根据自己的需要,定义自己的行为模式。
- 重写不会抛出新的异常检查,或比父类更加宽泛的异常
3.1.1、规则
- 参数列表与被重写方法的参数列表必须完全相同
- 返回类型与被重写方法的类型可以不一样,但是必须是父类返回值的派生类,这是在java7版本以后的新规则
- 访问权限不能比父类被重写的方法访问权限低
- 父类成员方法只能被子类重写
- 声明为final的方法不能被重写
3.2、重载
- 重载就是在一个类里面,方法名字相同,而参数不同,返回值类型可以相同,也可以不同
- 每个重载的方法(或者是构造器)都必须是独一无二的参数类型列表
- 常用:构造器的重载
3.2.1、规则
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
4、组合和继承的区别
4.1、定义
- 组合是指在新类中创建原有类的对象,重复利用原类的功能(has-a)
- 继承是使用现有类的功能,并且还可以在不修改原来类的情况下,对原来类进行拓展
4.2、比较
推荐使用组合,能用组合就尽量不使用继承。
5、前置++和后置++
- 前置++是在计算了值以后再使用
- 后置++是在使用了以后再计算值
- 这种规则在减减也是适用的
6、内部类
6.1、定义
将一个类定义在另一个给类里面或者方法里面,这样的类就被称为内部类。
内部类可以分为四种:成员内部类、局部内部类、匿名内部类、静态内部类
6.2、成员内部类
- 直接定义在外部类中,相当于外部类的一个属性
- 成员内部类可以无条件访问外部类的方法和属性,但是外部类想要访问内部类的方法和属性,就要创建一个内部类对象,然后通过该对象去访问内部类的属性和方法。
- 如果内部类和外部类出现重名,但是想调用外部类的属性或者方法,可以使用外部类的this关键字,也就是外部类.属性/方法
- 由于内部类寄生于外部类,所以创建对象时,必须先创建外部类才可以创建内部类
6.3、局部内部类
- 局部内部类位于方法中
- 与成员内部类的区别在于局部内部类的访问权限仅限于方法和作用域中
6.4、匿名内部类
- 所谓的匿名内部类就是一个没有显式的名字的内部类
- 匿名内部类会隐式的继承一个类或者实现一个接口,或者说,匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。
- 实际上我们的Inner是一个接口,本身接口是不能直接new的,但是呢却又发现我们在new的时候,Inner这个接口后面带了一对花括号,那么这个就表示实际上我现在new的是这个接口的实现类。但是发现,这个实现类是没有名字的。
6.5、静态内部类
- 静态内部类和成员内部类相比多了一个static修饰符。
- 不依赖外部类
- 不能使用外部的非静态方法和变量
7、二维数组的表示
三种表示形式
- int [] [] x
- int x [] []
- int [] y[]
8、接口和抽象类的对比
8.1、抽象类
- 只有声明,没有具体的实现
- 抽象方法必须用abstract关键字修饰
- 如果一个类中有抽象方法,那么这个类就是抽象类,抽象类前面必须要用abstract关键字修饰
- 因为抽象类没有具体实现的方法,所以不能用抽象类创建对象
- 抽象类中可以拥有成员变量和普通成员方法
- 抽象类是用来被继承的
8.1.1、与普通类区别
- 抽象方法必须是public或者是protected(因为如果是private,则不能被子类继承,子类无法实现),缺省情况下默认是public
- 抽象类不能创建对象
- 如果一个类继承了抽象类,则子类必须实现父类所有的抽象方法,否则子类必须也要定义为抽象类
8.2、接口
- 接口中可以含有变量和方法 ,变量会被隐式指定为public static final变量,方法会被隐式地指定为public abstract方法且只能是public abstract方法;
- 接口中所有方法不能有具体的实现,只能有定义。
- 一个类允许实现多个接口
- 一个类实现一个接口,那么就要实现接口中所有定义的方法
8.3、两者区别
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
9、反射机制
9.1、反射是什么
- 反射就是把Java类中的各个组成部分进行解剖,并映射成一个个的Java对象,拿到这些对象后可以做一些事情。
- 一个类有:构造方法,方法,成员变量(字段),等信息,利用反射技术咱们可以把这些组成部分映射成一个个对象
- 拿到映射后的构造方法,可以用它来生成对象;拿到映射后的方法,可以调用它来执行对应的方法;拿到映射后的字段,可以用它来获取或改变对应字段的值;
9.2、反射应用
- 反射是框架设计的灵魂
9.3、怎样使用反射
- 编译后的class文件就是一个class对象,存在堆中。
- 这些编译后的 class文件,这种事物也是一种对象,它也给抽象成了一种类,这个类就是Class
9.4、拓展
- Spring配置文件里会用到反射生成bean对象,其他常见的MVC框架,比如Struts2、SpringMVC等等一些框架里还有很多地方都会用到反射。
- 框架的代码里经常需要利用反射来操作对象的set、get方法,来把程序的数据封装到Java对象中去。
- 平常用到的框架,除了配置文件的形式,现在很多都使用了注解的形式。
- 反射是框架的灵魂,具备反射知识和思想,是看懂框架的基础
10、函数(方法)调用方式
- 通过对象名.方法名进行调用,这是最普通的也是最常见的一种调用方式。
- 通过new关键字调用构造方法,这种是在实例化对象时使用的方式
- 通过类名.方法名调用,当需要调用的那个方法为静态(有static的)方法时使用。
11、构造方法
11.1、构造函数是什么
-
一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象的属性和方
而一般函数是对象调用才执行,用 “.方法名” 的方式,给对象添加功能。
-
默认是有一个无参构造函数的,但是如果自定义了一个有参构造函数,那么就有必要再定义一个无参构造函数
11.2、构造函数特点
- 函数名与类名相同
- 不用定义返回值类型。(不同于void类型返回值,void是没有具体返回值类型;构造函数是连类型都没有)
- 不可以写return语句。(返回值类型都没有,故不需要return语句)
- 一般函数不能调用构造函数,只有构造函数才能调用构造函数。
12、stack和heap
12.1、stack是什么
- 每个应用程序运行时,都有属于自己的一段内存空间,用于存放临时变量、参数传递、函数调用时的PC值的保存。这叫stack。
- 内存申请 --由系统自动分配。例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
- 响应- 只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出
- 大小限制 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的
- 申请效率 由系统自动分配,速度较快。但程序员是无法控制的
12.2、heap
- 申请方式 需要程序员自己申请,并指明大小,
- 申请后系统响应 首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
- 大小限制 堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
- 申请效率 由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
13、继承和多态
区别
继承是子类使用父类的结构和行为,多态是指子类改变父类的结构和行为
大白话就是,继承就是可以在父类的基础上进行增加方法,而多态就是子类完全按照父类的方法,只是改变方法的具体实现。
13.1、多态是什么
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态就是同一个接口,使用不同的实例而执行不同操作
- 多态性是对象多种表现形式的体现。
14、值传递与引用传递
14.1、值传递
- 值传递就是说方法调用时,传递的参数是按值得拷贝,传递后就互不相关了
14.2、引用传递
- 引用传递就说,方法调用时,传递得参数是按引用进行传递,其实传递得是引用的地址,也就是变量对应内存的地址
14.3、总结
- 在Java中,只有基本类型是按照值传递,其他的都是按照引用传递
15、==和equal得区别
- ==是运算符,equal是方法
- 八大基本类型有(short,int,long,byte,char,float,double,boolean)
- 对于字符串来说,“==”比较两个变量本身的值,即两个对象在内存中的首地址,equals()”比较字符串中所包含的内容是否相同。
- 对于非字符串来说,"=="和"equals"方法的作用是相同的,都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。
16、创建空类,哪些成员变量是默认
- 布尔型(boolean)变量默认值为false
- byte、short、int、long为0
- 字符型为’\u0000’(空字符)
- 浮点型(float double)为0.0
- 引用类型(String)为null。
- 注意 没有初始化的局部变量是不能使用的,也可以理解为是局部变量没有默认值。
17、java入口函数
- public static void main(String[] args) 是程序的入口方法,JVM 在运行程序时会首先查找 main() 方法。
- public 是权限修饰词,表明任何类或对象都可以访问这个方法
- static 表明main() 是一个静态方法,即方法中的代码是存储在静态存储区的,只要类被加载就可以使用该方法而不需要通过实例化对象来访问
- 参数是String数组
- 返回值是void类型,也就是无返回值
18、内存泄漏和内存溢出
18.1、内存泄漏
- 内存泄漏是指那些本来应该回收的内存对象无法被内存回收的现象
- 一次内存泄漏影响不大,但是多次内存泄露的后果就是内存溢出
- 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。
18.2、内存溢出
- 指程序申请内存时,没有足够的内存供申请者使用
- 或者说,给你一块int类型的存储空间,但是你却用来存储long类型的数据
- 内存溢出就是说内存需求大于系统提供的
19、字符串默认存储方式
- 字符串常量存储在堆的常量池中
- 字符串对象存储在堆的非常量池中
- 字符串常量池在堆内存中,运行时常量池在方法区中
20、面向对象编程和面向过程编程
-
面向过程考虑数据变换; 面向过程的世界是以目标问题规定的I/O为中心的
-
面向对象考虑功能分工; 面向对象的世界是以内部实现的可理解性为中心的
-
作为面向对象来说,当你拿到一个问题,你分析这个问题不是第一步要做什么,第二步要做什么,你要做的是分析可以使用哪些工具来解决问题,这就是站在组织者的角度来解决问题。对于Java来说,面向对象就是你要分析可以使用哪些类和对象,然后再分析这些类和对象具有哪些属性和方法,最后再分析类和类之间的关系。而面向过程于面向对象相反,面向过程是站在执行者的角度,要解决一个问题,更多的是关注算法,第一步要怎么做,第二步要怎么做。
21、异常处理
21.1、异常是什么
- Java在编译或运行或者运行过程中出现的错误
- Java提供了更加优秀的解决办法:异常处理机制
- 异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰
- Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常
21.2、异常种类
异常的根接口Throwable,其下有2个子接口,Error和Exception。
- Error:指的是JVM错误,这时的程序并没有执行,无法处理;
- Exception:指的是程序运行中产生的异常,用户可以使用处理格式处理。
- 区别 Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。 Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
22、垃圾回收器
22.1、垃圾回收器是什么
- 垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
22.2、垃圾判断算法
-
引用计数法 给每个对象添加一个计数器,当有地方引用该对象时计数器加1,当引用失效时计数器减1。用对象计数器是否为0来判断对象是否可被回收。缺点:无法解决循环引用的问题。
-
可达性分析算法 通过对象作为搜索起始点,通过引用向下搜索,所走过的路径称为引用链。通过对象是否有到达引用链的路径来判断对象是否可被回收
22.3、垃圾回收算法
- 标记-清除算法 它分为2部分,先把内存区域中的这些对象进行标记,哪些属于可回收标记出来,然后把这些垃圾拎出来清理掉。清理掉的垃圾就变成未使用的内存区域,等待被再次使用。但它存在一个很大的问题,那就是内存碎片
- 复制算法 它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。保证了内存的连续可用,内存分配时也就不用考虑内存碎片等复杂情况。但是内存空间浪费一半
- 标记-整理算法 标记-整理算法标记过程仍然与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域。效率比复制算法稍低
- 分代收集算法 分代收集算法分代收集算法严格来说并不是一种思想或理论,而是融合上述3种基础的算法思想,而产生的针对不同情况所采用不同算法的一套组合拳,根据对象存活周期的不同将内存划分为几块。也就是具体问题具体分析,不同场景使用不同的算法相结合
23、多线程同步
23.1、什么是多线程同步
- 线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态
23.2、同步方式
- 互斥锁
- 读写锁
- 条件变量
- 信号量
24、数据库内连接和外连接
- 外连接分为外左连接(left outer join)和外右连接(right outer join)
- 左连接,取左边的表的全部,右边的表按条件,符合的显示,不符合则显示null
- 右连接:取右边的表的全部,左边的表按条件,符合的显示,不符合则显示null
- 内连接:也称为等值连接,返回两张表都满足条件的部分