java基础
JDK 和 JRE 有什么区别?
- JDK:java开发工具箱,有三个版本(java ee、java se、java me)
- JRE:java运行环境
- JVM:java虚拟机
- java类库
- java工具(编译器等)
- JRE:java运行环境
一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?
可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。
Java 有没有 goto?
java 中的保留字,现在没有在 java 中使用。
基础类型和运算符
说说&和&&的区别。
- &和&&都可以用作逻辑与的运算符,表示逻辑与(and)。当运算符两边的表达式的结果都 为 true 时,整个运算结果才为 true,否则,只要有一方为 false,则结果为 false。
- &&还具有短路的功能,即如果第一个表达式为 false,则不再计算第二个表达式。
- &还可以用作位运算符。
short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
对于 short s1 = 1; s1 = s1 + 1; 由于 s1+1 运算时会自动提升表达式的类型,所以结果是 int 型, 再赋值给 short 类型 s1 时,编译器将报告需要强制转换类型的错误。
对于 short s1 = 1; s1 += 1;由于 += 是 java 语言规定的运算符,java 编译器会对它进行特殊处 理,因此可以正确编译。
用最有效率的方法算出 2 乘以 8 等於几?
2 << 3,
因为将一个数左移 n 位,就相当于乘以了 2 的 n 次方,那么,一个数乘以 8 只要将其左移 3 位即可,而位运算 cpu 直接支持的,效率最高,所以,2 乘以 8 等於几的最效率的方法是 2 << 3。
== 和 equals 的区别是什么?
- 操作符==:
基础类型:比较值
引用类型:比较地址 - equals:
是一个方法,属于某一个具体的实例,从方法的功能上来说,这个方法是用来判定内容是否相等。如果一个类没有重写equals方法,则是Object里定义的实现,就是==。
hashCode相等,equals就一定为true吗?什么时候需要重写hashCode方法
- equals和hashCode都是Object的方法。从功能定义上讲,equals如果为true,那么hashCode一定也相等,即hashCode相等是equals为true的前提。
- Object里的hashCode值由对象的内存地址决定。
- 如果重写了equals,那么也必须重写hashCode,否则在HashMap各种地方,判断一个key是否相等,都会先判断key的hashCode值是否相等作为前提,这步会出错。
Integer 与 int 的区别
- int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 java 为 int 提供的封装类。
- int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋 值和值为 0 的区别,int 则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成 绩为 0 的区别,则只能使用 Integer。
- Integer还提供了很多操作数据的方法
Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor的英文意义是地板,该方法就表示向下取整,Math.ceil(11.6)的结果为11,Math.ceil(-11.6)的结果是-12;最难掌握的是round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
流程控制语句
switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?
在 switch(expr1)中,expr1 只能是一个整数表达式或者枚举常量(更大字体),整数表达式 可以是 int 基本类型或 Integer 包装类型,由于,byte,short,char 都可以隐含转换为 int,所以,这 些类型以及这些类型的包装类型也是可以的。显然,long 和 String 类型都不符合 switch 的语法 规定,并且不能被隐式转换成 int 类型,所以,它们不能作用于 swtich 语句中。
面向对象
请说出作用域 public,private,protected,以及不写时的区别
这四个作用域的可见范围如下表所示。
说明:如果在修饰的元素上面没有写任何访问修饰符,则表示 friendly。
作用域 | 当前类 | 同一package | 子孙类 | 其他package |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
friendly | √ | √ | × | × |
private | √ | × | × | × |
Overload(重载)和Override(覆盖)的区别。Overloaded的方法是否可以改变返回值的类型?
- 重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
- 重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
- 子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。
- 子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
- 至于Overloaded的方法是否可以改变返回值的类型这个问题,要看你倒底想问什么呢?这个题目很模糊。如果几个Overloaded的方法的参数列表不一样,它们的返回者类型当然也可以不一样。但我估计你想问的问题是:如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Overload。
- 在覆盖要注意以下的几点:
- 1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
- 2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
- 3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
- 4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
- 在使用重载要注意以下的几点:
- 1、在使用重载时只能通过不同的参数样式。
- 2、不能通过访问权限、返回类型、抛出的异常进行重载;
- 3、方法的异常类型和数目不会对重载造成影响;
- 4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
构造器 Constructor 是否可被 override?
构造器 Constructor 不能被继承,因此不能重写 Override,但可以被重载 Overload。
接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?抽象类中是否可以有静态的main方法?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承具体类。抽象类中可以有静态的main方法。
备注:只要明白了接口和抽象类的本质和作用,这些问题都很好回答,你想想,如果你是java语言的设计者,你是否会提供这样的支持,如果不提供的话,有什么理由吗?如果你没有道理不提供,那答案就是肯定的了。
只有记住抽象类与普通类的唯一区别就是不能创建实例对象和允许有abstract方法。
面向对象的特征有哪些方面
抽象类必须要有抽象方法吗?
- 抽象类:被abstract修饰的class就是抽象类,抽象不能被实例化。
- 抽象方法:被abstract修饰的方法就是抽象方法,抽象方法没有方法体(没有实现代码)。
- 包含抽象方法的类一定要声明为抽象类,但抽象类可以没有抽象方法。
- 构造方法和静态方法不能被声明为abstract
抽象类和接口
- 相同点:都不能实例化
- 不同点:
- 抽象类可以被继承(extends),接口可以被实现(implements)
- java只能单继承,但可以实现多个接口
- 抽象类可以有抽象方法,也可以有普通方法。接口里的所有方法都被public abstract修饰
- 抽象类里对变量没特殊限制。接口里变量都是常量(被public static final修饰)
- 抽象类中可以包含静态方法,接口中不能包含静态方法
- 抽象类有构造方法,接口中不能有构造方法。
抽象类能使用 final 修饰吗?
不能,抽象类是用来继承的,被final修饰的类不能被继承。
final 在 java 中有什么作用?
- 修饰类:
该类不允许被继承 - 修饰方法:
该方法不允许被重写 - 修饰变量:
使用 final 关键字修饰一个变量时,引用变量不能变(所以只能赋值一次,后面的赋值无效),引用变量所指向的对象中的内容是可以改变的。
静态变量和实例变量的区别?
- 在语法定义上的区别:
- 静态变量前要加 static 关键字,而实例变量前则不加。
- 在程序运行时的区别:
- 实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
- 静态变量不属于某个实例对象,而是属于类,所以 也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间, 静态变量就可以被使用了。
实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
是否可以从一个 static 方法内部发出对非 static 方法的调用?
不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static 方法调用时不需要创建对象,可以直接调用。也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法的 调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个 static 方法 内部发出对非 static 方法的调用。
String
String 属于基础的数据类型吗?
String不属于基础类型,基础类型一共有8种:
- 整形
- byte
- short
- int
- long
- 浮点型
- float
- double
- 布尔型
- boolean
- 字符型
- char
java 中操作字符串都有哪些类?它们之间有什么区别?
String、StringBuilder、StringBuffer
- String:在反复拼接过程中,性能低(需要大量反复复制),会生成大量新的中间String对象。
- String + 号的实现,例如“aaa” + “bbb”
- 先生成一个StringBuilder对象(生成新的对象)
- 调用该StringBuilder对象的append方法拼接“aaa”(复制 aaa)
- 调用该StringBuilder对象的append方法拼接“bbb”(复制 bbb)
- 调用该StringBuilder对象的toString方法返回一个新的String对象(复制 aaabbb,且生成新的对象)
- String + 号的实现,例如“aaa” + “bbb”
- StringBuilder:相对于String,性能高,不会产生中间String对象
- 实现:内部维护了一个char数组,每次操作字符串,实际就是操作这个char数组,最后拼接完成后通过toString方法生成一个新的String对象。
- StringBuffer:是StringBuilder的线程安全版本,方法上加了synchronized
String str="i"与 String str=new String(“i”)一样吗?
- String str=“i”:
- 如果字符串常量池中没有“i”,则新建一个“i”字符串对象放入常量池。
- 如果字符串常量池中有“i”,则str直接指向常量池中的“i”字符串对象
- String str=new String(“i”):
- 如果字符串常量池中没有“i”,则新建一个“i”字符串对象放入常量池,并基于该字符串对象在堆中创建一个字符串对象,并让str指向堆中的对象。
- 如果字符串常量池中有“i”,则直接基于该字符串对象在堆中创建一个字符串对象,并让str指向堆中的对象。
如何将字符串反转?
String 类的常用方法都有那些?
下面这条语句一共创建了多少个对象:String s=“a”+“b”+“c”+“d”;
被编译器在编译时优化后,“a”+“b”+“c”+"d"相当于直接定义了一个”abcd”的字符串,所以上面的代码应该只创建了一个 String 对象。
java容器
java 容器都有哪些?
- Collection(接口)
- List(接口)
- ArrayList
- LinkedList
- Set(接口)
- HashSet
- Queue(接口)
- LinkedList
- Stack(类)
- List(接口)
- Map(接口)
- HashMap
- TreeMap
- LinkedHashMap
- ConcurrentHashMap
Collection 和 Collections 有什么区别
- java.util.Collection:Collection是集合的顶层接口,提供了集合对象的通用方法。我们平时常接触的ArrayList、LinkedList、HashSet都是Collection接口的具体实现。
- java.util.Collections:Collections是一个工具类,提供了操作集合的静态方法(对集合的搜索、排序、线程安全化等)。此类构造方法被private修饰,不能实例化。
List、Set、Map 之间的区别是什么?
- List和Set都属于Collection,Map不属于Collection。
- List是列表,允许元素重复,可以通过下标进行操作。
- Set元素不重复。
- Map存储的是key-value键值对。
HashMap 和 Hashtable 有什么区别?
- 最大的区别:HashTable是HashMap的线程安全版本,方法上加了synchronized保证原子性。
- HashMap key value 都允许为null,HashTable key value 都不允许为null。
- HashMap默认大小为16,负载因子为0.75,扩容规律为2n。HashTable默认大小为11,负载因子为0.75,扩容规律为2n+1。
- HashMap中的迭代器是失败的,而Hashtable的枚举器不是。
如何决定使用 HashMap 还是 TreeMap?
- HashMap基于哈希表实现的,key是无序的,查找速率为O(1)。
- TreeMap是基于平衡二叉树(红黑树)实现的,key是有序的(默认升序),查找速率为O(logn)。
说一下 HashMap、HashTable的实现原理
ArrayList 和 LinkedList 的区别是什么?
ArrayList是基于数组实现的,LinkedList是基于双链表实现的。简单说ArrayList查找快,增删慢。LinkedList查找慢,增删快。
- 查找效率:ArrayList支持随机访问,访问任何位置的元素效率都是O(1)。LinkedList访问元素只能从头或从尾遍历,平均效率为O(n),如果访问的是头结点或尾节点则是O(1)。
- 增删效率:ArrayList增删元素需要挪动操作位置后的所有元素,效率为O(n)。LinkedList增删速率为O(1),但一般删除都需要先查找,所以整体效率也是O(n)。如果是头尾操作,查找效率就是O(1),增删效率也是O(1),所有适合只操作头尾节点的场景。
数组 和 ArrayList 有何区别?
- 数组大小固定。ArrayList是基于数组实现的动态数组,会自动扩容。
- Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
在 Queue 中 poll()和 remove()有什么区别?
哪些集合类是线程安全的?
Iterator 和快速失败
TODO
怎么确保一个集合不能被修改?
异常
error 和 exception 有什么区别?
-
相同点:
- Exception 和Error 都是继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出或者捕获,它是异常处理机制的基本类型。
-
不同点:Exception和Error体现了Java平台设计者对不同异常情况的分类。
- Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
- Exception又分为可检查(checked)异常和运行时异常。
- 可检查异常在源代码里必须显式的进行捕获处理,这是编译期检查的一部分。
- 运行时异常(RuntimeException),例如NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。
- Error是指正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序处于非正常的、不可恢复的状态。既然是非正常情况,不便于也不需要捕获。常见的比如OutOfMemoryError之类都是Error的子类。
运行时异常与一般异常有何异同?
参考上一题答案
throw 和 throws 的区别?
- throw: 用于在代码中手动抛出一个异常
- throws: 用于方法定义上,表明这个方法可能抛出一个异常,调用方需要显示捕捉该异常,如果没有显示捕捉该异常,则需要同样在方法定义上声明可能抛出该异常。
final、finally、finalize 有什么区别?
- final:用于修饰类、方法、变量
- finally:try-catch-finally,在finally代码块的代码不管是否有异常都会在最后执行,一般用于资源释放等。
- finalize:Object中的一个方法,在该实例被回收前被调用,不推荐覆盖该方法(两个风险:1、调用时间不确定,2、可能会导致垃圾回收异常)。
try-catch-finally 中哪个部分可以省略?
能省略catch或finally,但不能同时省略catch和finally。
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
会。
常见的异常类有哪些?
try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
retrun语句与finally代码块执行顺序如下:
1、先执行return关键字后的表达式,获取到返回结果,此时返回结果已确定,值会先缓存下来。
2、执行finally代码块
3、执行return把之前缓存的结果值返回
多线程
多线程有几种实现方法?
- 多线程有两种实现方法:
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
同步有几种实现方法?
- synchronized
- 同步方法
- 静态方法,锁对象就是该class
- 成员方法,锁对象就是该实例
- 同步代码块
- 锁对象由代码指定
- 同步方法
- Lock
- 例如 ReentrantLock(可重入锁)、ReentrantReadWriteLock(可重入读写锁)。
sleep() 和 wait() 有什么区别?
- 相同点:两个方法被调用后线程都会被阻塞一段时间
- 不同点:
- 这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
- sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。
- wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。
- sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常。
- sleep()必须填写等待时间;wait()可以不填写等待时间。