1.1 final、finally、finalize区别
final
修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。
finally
异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。一般异常处理块需要。
finalize
方法名。它是在 Object 类中定义的,因此所有的类都继承了它。
垃圾回收周期性地运行,检查对象不再被运行状态引用或间接地通过其他对象引用。就在对象被释放之前,Java 运行系统调用该对象的finalize( ) 方法。
finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
注意:
调用finalize方法后:
(1).对象不一定会被回收。只是给JVM一个回收的建议,不是回收命令
(2).垃圾回收不是析构函数。
(3).垃圾回收只与内存有关。
(4).垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。
Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。
1.2 垃圾收集器回收流程:
在 Java 中,当你创建一个对象时,Java 虚拟机(JVM)为该对象分配内存、调用构造函数并开始跟踪你使用的对象。当你停止使用一个对象(就是说,当没有对该对象有效的引用时),JVM 通过垃圾回收器将该对象标记为释放状态。
当垃圾回收器将要释放一个对象的内存时(完全可能到程序结束都不释放内存),它调用该对象的finalize() 方法(如果该对象定义了此方法,没定义就是Object中的finalize())。
垃圾回收器以独立的低优先级的方式运行,只有当其他线程挂起等待该内存释放的情况出现时,它才开始运行释放对象的内存。(事实上,你可以调用System.gc() 方法强制垃圾回收器来释放这些对象的内存。)
在以上的描述中,有一些重要的事情需要注意。首先,只有当垃圾回收器释放该对象的内存时,才会执行finalize()。如果在 Applet 或应用程序退出之前垃圾回收器没有释放内存,垃圾回收器将不会调用finalize()。
2.Java 8 的新特性
1.1 Lambda表达式
Lambda表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。(java原来只能使用匿名内部类代替Lambda表达式)
例子:
List names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成。
使用Lambda表达式后,
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
//更简单表示
Collections.sort(names, (String a, String b) -> b.compareTo(a));
Collections.sort(names, (a, b) -> b.compareTo(a));
1.2 接口的默认方法
Java 8 使我们能够使用default 关键字给接口增加非抽象的方法实现。这个特性也被叫做 扩展方法(Extension Methods)。如下例所示:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
除了抽象方法calculate ,接口 Formula 同样定义了默认的方法 sqrt。具体类只需要实现抽象方法calculate。默认的方法sqrt可以在其未实现时“开箱即用”。
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
3. java的优势
- 免费、跨平台,面向对象的特色,简单没有指针、还提供垃圾回收
- 它有大量的框架 – 各分其类,各有专长!
- 健壮性,早期的问题检测,后期动态(运行时)检测,把引用和实际值放在两块不同的内存中,消除重写内存和顺坏数据的可能性
- Java技术中使用了各种池技术,(连接池,线程池,缓冲池等),性能上不错
- 无线应用、网络应用,Java有一个扩展的例程库,用于处理像HTTP和FTP之类的TCP/IP协议。
4. Java有哪些特性(封装、继承、多态之类的)
三大特性:封装、继承、多态
4.1封装
封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装是一种信息隐藏技术,在java中通过关键字private,protected和public实现封装。
对外部只保留一些对外接口使之与外部发生联系。系统的其他部分之一通过这些接口与之进行交互。也就是说,用户不需要知道对象内部方法的实现细节,但可以根据对象提供的外部接口(对象名和参数)来访问参数。
4.2 继承
一个类继承另一个类,则继承的类为子类,被继承的类为父类。它的目的就是实现代码的复用。
子类继承父类后就自动拥有了父类的属性和方法,但是,父类的私有属性和构造方法并不能被继承。另外,继承后子类还可以写自己特有的属性和方法,目的是实现功能的扩展,子类也可以复写父类的方法,即方法的重写。
4.3 多态
多态的概念是以封装和继承为基础发展出来的。
概念:相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。
在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
5.new 实例化过程
Person p = new Person();
- 首先去JVM 的方法区中区寻找类的class对象,如果能找到,则按照定义生成对象,找不到则转2
- 加载类定义:类加载器(classLoader)寻找该类的 .class文件,找到后对文件进行分析转换为class对象存入方法区方便以后调用。
其中jdk 的class一般是在jvm启动时用启动类加载器完成加载,用户的class则是在用到的时候再加载。
- 当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。(在缓存中)
- 当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader.
- 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。
- 在jvm的堆中给对象开辟一个内存空间
- 对象初始化(赋值),顺序:
(1) 父类静态对象(静态变量),静态代码块
(2)子类静态对象(静态变量),静态代码块
(3)父类非静态对象(变量),非静态代码块
(4)父类构造函数
(5)子类非静态对象(变量),非静态代码块
(6)子类构造函数(子类的构造函数中第一行有一个默认的隐式语句。 super();)子类中所有的构造函数默认都会访问父类中的空参数构造函数。
注意:子类构造函数中如果使用this调用了本类构造函数时,则调用this的这个构造函数中super便没有了,
因为super和this都只能定义在第一行。
但是可以保证的是,子类中肯定会有其它的构造函数访问父类的构造函数。
6.反射的所有包,怎实现反射
7.java修饰符(public、private、default、protected)
修饰符 | 类内部 | 本包 | 子类 | 外部包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default(默认) | √ | √ | × | × |
private | √ | × | × | × |
8.单例模式和静态类的区别(Difference between static class and singleton pattern)
内存上:
单例模式执行的时候需要new 一个对象出来存储在堆栈里面,而静态方法不需要,它不依赖于对象(普通方法是Object.method而静态方法是class.method),但是他也是需要内存的,它是以代码块来存储
生命周期:
静态方法的类会在代码编译的时候就被加载,静态方法中产生的对象,会随着静态方法执行完毕而释放掉,而且执行类中的静态方法时,不会实例化静态方法所在的类。
如果用单例模式, 产生的那一个唯一的实例,会一直在内存中,不会被GC清除的(原因是静态的属性变量不会被GC清除),除非整个应用退出了JVM
执行效率:
静态方法与实例方法,在加载时机和占用内存上,静态方法和实例方法是一样的,在类型第一次被使用时加载。调用的速度基本上没有差别。
但是从日志打印来看,个人感觉还是静态方法在执行效率上快一点。
总结:
1. 单例可以继承类,实现接口,而静态类不能(可以集成类,但不能集成实例成员)
2. 单例可以被延迟初始化,静态类一般在第一次加载时初始化
3. 单例类可以被集成,他的方法可以被覆写
4. 静态方法是面向过程的,如果我们Java面向对象学得好的话应该是不会出现这种类的
9.接口和抽象类的区别
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的。它根本不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
Java 8 的新特性——
使用default 关键字给接口增加非抽象的方法实现
10. 继承的好处和坏处
好处:
- 继承是一种提高程序代码可重用性、可扩展性的有效手段
- 子类能自动继承父类接口
- 创建子类对象,无需创建父类对象
- 拓展功能简单直观
弊端:
- 打破封装,子类可以访问父类的属性和方法,两者是紧密耦合关系,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性。
- 可以把不允许子类覆盖的类定义为final类型,不允许父类的构造方法调用可被子类覆盖的方法等
- 不支持动态继承,运行时子类无法选择不同父类
- 子类不能改变父类接口
- 只能单继承
11.为什么this和super不能同时出现在一个构造函数里面?
构造函数必须出现在第一行上。
所以,注定了你只能调用一个构造函数。
默认的,父类的或者本类的其它构造,你自己选一个。