1 简述Static 和Final的用法
1.1 Static
1.static关键字可以修饰方法和变量
2.静态资源优先于创建对象加载数据
3.只会加载一次就会一直存在,不会再开辟新的空间
4.静态资源全局唯一,共享,可以被多个对象共享
5.静态资源可以直接被类名调用
6.静态只能调用静态,非静态可以随意调用
1.2 Final
1.被final修饰的方法是一个最总的方法,不可以被重写
2.被final修饰的类是一个最终类,不能被继承
3.被final修饰的变量是一个常量,不能被修改
2 类,抽象类,接口
2.1 类和类的关系
类和类的关系:继承 extends / 单继承 / 单根继承
继承的意义:为了提高代码的复用性,减少了代码的编写提高开发效率。
方法重写的意义:在不修改父类源码的前提下,在子类中重写业务,从此使用的就是重写后的功能。
要求子类的方法声明和父类一样,只要改方法体。
有了继承有了重写就产生了多态,多态的意义:为了统一程序的调用标准,标准就是父类。
多态 也就是向上转型/向上造型。
向下造型的意义:很少用,相当于想要使用子类的特殊功能,还不如直接创建子类对象简单。
class A extends B
其中,A和B都是类,A是子类,B是父类,A就拥有了B的所有功能(除了私有的和构造方法)
其他知识点:this 和super ,构造方法,各种代码块...
2.2 类和接口关系:实现implements / 单实现 / 多实现
-- class A implements B,C
其中,A是实现类,B和C是接口
要求A 可以把 B 和C 接口里的所有 抽象方法 都重写掉,否则 A 就是抽象类
接口不能创建对象
接口里没有构造方法,接口里都是常量,接口里都是抽象方法
2.3 接口和接口关系:继承extends / 单继承 / 多继承
接口的多继承的关系,打破了java单继承的局限性
interface A extends B,C
其中,A B C 都是接口,A是子接口,同时拥有B和C接口里的所有功能
class AImpl implements A
要求AImpl需要重写A接口里的所有方法(是包含B和C接口的所有方法),否则就是抽象类
2.4 接口和抽象类的区别!!!
-- 相同点:都是抽象层,都不能实例化
-- 不同点:
-- 1、抽象类用abstract关键字描述,接口用interface
-- 2、子类和抽象类之间是extends关系,实现类和接口之间是implements关系
-- 3、抽象类中 可以 有构造方法 ,接口里 不能 出现 构造方法
-- 4、抽象类里可以有 变量,接口里没有变量全都是静态的常量
-- 5、接口里定义常量的语法:public static final String NAME="jack",会为变量自动拼接public static final
-- 6、抽象类里 可以有普通方法 也可以有 抽象方法,接口都是抽象方法
-- 7、抽象类和子类之间是继承关系,而且java中,只支持单继承
-- 8、接口突破了java单继承的局限性,因为接口可以多继承也可以多实现,甚至可以继承的同时多实现
-- 9、接口的复杂用法
-- 多继承: interface A extends B,C 其中A是子接口,同时拥有自己的和BC的功能
-- 多实现: class AImpl implements M,N,O,P 其中AImpl是实现类,需要同时重写MNOP的所有抽象方法,否则就是一个抽象类
-- 继承的同时多实现: class AImpl extends Object implements M,N 一定是先继承后实现
3 访问控制符
1.public 所有类可见
2.private 只有本类可见
3.protected 本类,本包,所有子类可见
4.default 本类,本包可见(不写默认是default,而且我们还不能写default,一写就报错)
4 Error 和 Exception 有什么区别? 列出你见过的 Exception并简要说明
error 表示系统级的错误,程序不必处理的异常,比如内存溢出,不可能指望程序能处理这样的情况;
exception 表示需要捕捉或者抛出,需要程序进行处理的异常。也就是说,如果程序运行正常,不会发生情况。
常见异常有:
NullPointerException:当操作一个空引用时会出现此错误。
NumberFormatException:数据格式转换出现问题时出现此异常。
ClassCastException:强制类型转换类型不匹配时出现此异常。
ArrayIndexOutOfBoundsException:数组下标越界,当使用一个不存在的数组下标时出现此异常。
ClassNotFoundException 类找不到异常
ArithmeticException 算术异常
4.1 Java中的异常处理关键字是什么?
throw:有时我们明确要创建异常对象然后抛出它来停止程序的正常处理。throw关键字用于向运行时抛出异常来处理它。
throws:当我们在方法中抛出任何已检查的异常而不处理它时,我们需要在方法签名中使用throws关键字让调用者程序知道该方法可能抛出的异常。调用方法可以处理这些异常或使用throws关键字将其传播给它的调用方法。我们可以在throws子句中提供多个异常,也可以与main()方法一起使用。
try-catch:我们在代码中使用try-catch块进行异常处理。try是块的开始,catch是在try块的末尾处理异常。我们可以使用try有多个catch块,try-catch块也可以嵌套。catch块需要一个应该是Exception类型的参数。
finally:finally块是可选的,只能用于try-catch块。由于异常会暂停执行过程,因此我们可能会打开一些不会关闭的资源,因此我们可以使用finally块。finally块总是被执行,无论是否发生异常。
4.2 Java中的检查型异常和非检查型异常有什么区别?
检查型异常和非检查型异常的主要区别在于其处理方式。检查型异常都需要使用try,catch 和finally 关键字在编译器进行处理,否则会出现编译器报错。对于非检查型异常则不需要这样做。Java中所有继承 Exception 的类的异常都是检查型异常,所有继承RuntimeException 的异常都被称为 非检查型异常。
5 final(已解释)、finally、finalize的区别
5.1 finally
finally是在异常处理时提供finally块来执行任何清除操作。不管有没有异常被抛出、捕获,finally块都会被执行。try块中的内容是在没有异常时就会执行到结束。catch块中的内容,是在try代码块中发生了catch代码块中所声明的异常时,就会跳转catch代码块中执行。finally块则是无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。
5.2 finalize
finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。 使用finalize还需要注意一个事,调用super.finalize();
一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。
6 sleep()和 wait()有什么区别?
1、sleep是Thread类中的方法,但是wait是Object中的方法。
2、sleep方法不会释放锁,但是wait会释放锁,而且会加入到等待队列中。
3、sleep方法不依赖于同步关键字synchronized,但是wait需要依赖synchronized关键字。
4、sleep不需要被唤醒(休眠之后退出阻塞),但是wait需要被唤醒(不指定时间需要被别人中断)。
5、sleep必须捕获异常,而wait,notify,notifyAll不需要捕获异常
补充1:在用法上sleep(millseconds,毫秒单位)可以用指定时间来使他自动醒过来,如果时间不到你只能使用interrupt()方法来强行打断,wait可以使用notify()方法直接唤醒。
补充2:sleep()方法是Thread类的静态方法,sleep的作用是让线程休眠指定的时间,在时间到达时恢复。wait是Object方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者将调用者的线程挂起,直到其他线程调用同一个对象的notify()方法才会重新激活调用者。
7 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
多线程有三种方法:继承 Thread 类或者实现 Runnable 接口 或者实现Callable接口。
Runnable规定(重写)的方法是run()——业务重写在run方法
Callable规定(重写)的方法是call()——业务重写在call方法
实现同步也有两种方法:一种是同步方法,另一种是同步代码块。
同步方法是在方法返回类型前面加上 synchronized 关键字
同步代码块是 synchronized (这里写需要同步的对象){…}
7.1 讲一下线程的几种启动方式?
第一种方法是自定义一个类去继承 Thread类 。该子类应重写 Thread 类的 run 方法,然后在 run 方法里填写相应的逻辑代码。创建子类对象,调用start方法来启动线程
第二种方法是实现 Runnable 接口,并编写 run 方法,相比继承 Thread 类创建线程的好处是
以实现接口的方式创建线程可以对类进行更好的扩展,该类可以继承其他类来扩展自身需
求,相比第一种方式更加灵活,扩展性强
7.2 线程五种状态
1.新建状态
2.可运行状态
3.运行状态
4.阻塞状态
5.死亡状态
7.3 进程和线程的区别
一个软件的运行最少需要一个进程支撑,一个进程又可以启动多个线程来执行
如果一个进程,只包含一个线程 — 单线程程序
如果一个进程,包含多个线程 — 多线程程序
7.4 并发和并行的区别
并发:如果只有一个CPU在干活,大家都去抢占了CPU资源,发生了资源被抢占的现象(例子:京东商品秒杀情况)
并行:假设有多个CPU在干活,每个CPU干一个任务,只不过是多个CPU一起各干各的
7.5 多线程的卖票案例
7.6 何为死锁?死锁产生的条件?
死锁:就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。
死锁产生的四个必要条件
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
7.7 如何解决死锁??
1.最简单、最常用的方法就是进行系统的重新启动。不过这种方法代价很大,它意味着在这之前所有的进程已经完成的计算工作都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程;
2.**撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。**这时又分两种情况:一次性撤消参与死锁的全部进程,剥夺全部资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。一般来说,选择逐步撤消的进程时要按照一定的原则进行,目的是撤消那些代价最小的进程,比如按进程的优先级确定进程的代价;考虑进程运行时的代价和与此进程相关的外部作业的代价等因素;
3.**进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时不再发生死锁。**虽然这是个较理想的办法,但是操作起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便今后的回退,有时这是无法做到的。
8 简单讲一下 java 的跨平台原理
所谓的平台就是操作系统,有windows,linux,unix,苹果等系统
java 源程序(.java 文件)通过编译器编译成为 Class 文件(字节码文件),而字节码文件是描述程序要运行的指令,这些指令与任何的平台无关,但是Java 虚拟机认识它。
所以只需要安装不同操作系统版本的 JVM(java虚拟机)!就可以了
9 有了基本数据类型,为什么还需要包装类型?
Java 是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型。它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
另外,当需要往集合中存放时,像 int,double 这种基本类型是放不进去的,因为容器都是装 object 的,这是就需要这些基本类型的包装器类了。
10 "=="和 equals 方法究竟有什么区别?
==是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的。
equals 方法是用于比较两个独立对象的内容是否相同。
其实是因为 Integer 在常量池中的存储范围为[-128,127],127在这范围内,因此是直接存储于常量池的,而128不在这范围内,所以会在堆内存中创建一个新的对象来保存这个值,所以m,n分别指向了两个不同的对象地址,故而导致了不相等。
11 讲一下 java 中的集合
Collection是根接口。既然是接口就不能创建对象,我们只能学习他的共性方法。
11.1 List(接口) 有索引(有下标)、有序、允许重复
List接口下有两个实现类
ArrayList
-
存在于java.util包中。
-
内部用数组存放数据,封装了数组的操作,每个对象都有下标。
-
内部数组默认初始容量是10。如果不够会以1.5倍容量增长。
-
底层维护的是一个数组,适合查询,增删数据效率较低。
LinkedList
特点:底层维护的是一个链表,适合增删,不适合查询
11.2 Set(接口) 无索引、无序、不允许重复
Set接口下有两个实现类
Hashset
特点:HashSet:底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复,此类允许使用 null 元素。
TreeSet(几乎不用)
特点:底层就是TreeMap,也是红黑树的形式,便于查找数据。
11.3 Map集合的特点 :(常用于存 键值对 结构的数据)
1.可以根据键提取对应的值
2.键不允许重复,如果重复值会被覆盖
3.存放的都是无序数据
4.初始容量是16,默认的加载因子是0.75
HashMap特点:HashMap底层是一个Entry数组,当存放数据时会根据hash算法计算数据的存放位置。当计算的位置没有数据时,就直接存放,当计算的位置有数据时也就是发生hash冲突的时候/hash碰撞时,采用链表的方式来解决的,在对应的Entry数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。
TreeSet特点:(几乎不用)
11.4 Map集合的遍历方法
注意:Map集合不可以直接遍历,如果需要遍历需要转成Set集合,转成Set集合的两个方法是keySet()和entrySet()
12 Collection 和 Collections 的区别?
Collection 是 java.util 下的接口,它是各种集合的父接口,继承于它的接口主要有 Set 和 List;Collections 是个 java.util 下的类,是针对集合的帮助类。
13 String、StringBuffer 和 StringBuilder 的区别?
首先说运行速度:在这方面运行速度快慢为:StringBuilder > StringBuffer > String
线程安全:在线程安全上,StringBuilder 是线程不安全的,而 StringBuffer 是线程安全的
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况(初始容量是16,不够2倍+2增容)
14 BigDecimal和BigInteger的使用场景
BigDecimal:常用来解决浮点数运算不精确的问题
BigInteger:常用来解决超大的整数运算。
15 GC 是什么? 为什么要有 GC?
GC 是垃圾收集的意思,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。
16讲一下java的反射
Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
16.1 如何通过反射创建对象?
分为两个主要步骤:
1.获取需要反射对象的字节码对象(三种方法)
一. Class.forName(“类的全路径”);
Class<?> clazz = Class.forName(“类的全路径”) 包名加类名
二. 类名.class
Class<?> clazz = Student.class;
三. 对象.getClass();
Class<?> clazz = Student.getClass();
2.获取字节码对象后使用newInstance()方法或者getConstructor方法创建对象
16.2反射知识补充
反射本质可以分为两套api,一套是普通反射,只可以反射public修饰公开类,另外一套是暴力反射,可以反射被private修饰的私有类。
17 谈谈 JVM 的内存结构和内存分配?
Java 虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、栈内存和堆内存。
方法区:String 常量和static修饰的方法和变量都保存在方法区,还有类的字节码文件都是保存在方法区里
栈内存:局部变量时存在栈内存中的,并且先进栈的数据后出栈。
堆内存:成员变量和new出来的对象都是存放在堆内存中的
18 内部类的使用
如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。就是把类定义在类的内部的情况就可以形成内部类的形式。
A类中又定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。
特点
1、 内部类可以直接访问外部类中的成员,包括私有成员
2、 外部类要访问内部类的成员,必须要建立内部类的对象
3、 在成员位置的内部类是成员内部类
4、 在局部位置的内部类是局部内部类
18.1 匿名内部类 – 经常用!!
匿名内部类属于局部内部类,并且是没有名字的内部类。
18.2 匿名内部类总结
问:接口可以创建对象吗??
答:一般情况下接口是不可以创建对象的,但是如果我们结合了接口的匿名对象和匿名内部类就可以创建对象,但是我们需要记住创建的是实现类的对象吗,而不是接口本身的对象,因为接口本身是绝对不可以创建对象的。
问:这么创建对象的作用是什么??
答:一般情况下,我们创建接口的实现类对象,我们需要再创建接口的的实现类,有要新建一个类,然后去实现抽象方法,相当麻烦,所以为了方便创建接口的实现类,所以我们回采用这种简单的方法创建接口的实现类对象。
19 java中常用的设计模式有哪些??
1.单例设计模式(懒汉式,饿汉式)
--饿汉式
package cn.tedu.thread;
//这个类用来测试 单例设计模式:保证整个工程中,只有唯一的实例
public class Test4_Singleton {
public static void main(String[] args) {
//4、调用了MySingleton内部创建好的对象
MySingleton m1 = MySingleton.getSingle();
//5、全局真的只要一个对象吗?
MySingleton m2 = MySingleton.getSingle();
//==比较引用类型比较的是地址值
System.out.println(m1 == m2);
}
}
//自定义单例类
class MySingleton {
//1、私有化构造方法,目的是不让外界随意new
private MySingleton() {}
//2、在类的内部 ,提供创建好的对象
//static--因为静态只能调静态,所以想要被getSingle()调用,必须也是静态资源
static private MySingleton single = new MySingleton();
//3、提供公共的 ,访问方式,把single返回给外界调用位置
static public MySingleton getSingle(){
return single ;
}
}
懒汉式
//懒汉式:
//延迟访问(是指没有第一时间创建对象,而是什么时候调用get()什么时候才创建)
//线程安全隐患(有多条语句 对 共享资源 进行操作)--需要把get()变成同步方法
class MySingleton2 {
// 1、私有化构造方法,目的是不让外界随意new
private MySingleton2() {
}
// 2、在类的内部 ,提供创建好的对象
// static--因为静态只能调静态,所以想要被getSingle()调用,必须也是静态资源
static private MySingleton2 single; // 懒汉式
// 3、提供公共的 ,访问方式,把single返回给外界调用位置
synchronized static public MySingleton2 getSingle() {// 直接把方法同步了,默认使用的锁对象是this
// synchronized (MySingleton2.class){//如果你要锁的共享资源是静态的,此时,锁对象必须是MySingleton2的字节码对象
if (single == null) {
single = new MySingleton2();
}
return single;
// }
}
}
2.工厂模式
3.门面模式
4.策略模式