《java基础一》
1.面向对象的三大特征
封装、继承、多态,也可加上抽象
2.多态的作用
允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)
可替换性:多态对于已存在的代码具有可替换性;
可扩充性:增加新的子类不影响已经存在的类结构;
接口性:多态是超类通过方法签名,向子类提供一个公共接口,由子类完善或者重写它来实现。
3.代码中如何实现多态
实现多态主要有一下三种方式:
接口实现
继承父类重写方法
同一类中进行方法重载
4.虚拟机是如何实现多态的
动态绑定技术(dynamic binding),执行期间判断所引用对象的实际类型,根据实际类型调用对应方法。
5.接口的意义
接口的意义用三个词可以概括:规范、扩展、回调
6.抽象类的意义
抽象类可以概括为三点:
为其他子类提供一个公共类型
封装子类中重复定义的内容
定义抽象方法,子类虽然有不同的实现,但是定义是一致的
7.接口和抽象类的区别
8.父类的静态方法能否被子类重写
不能,重写只适用于实例方法,不能用于静态方法,而子类中有和父类中相同的静态方法,我们一般称为隐藏。
9.什么是不可变对象
不可变对象指对象一旦被创建,状态就不能被改变。任何改变都会创建一个新的对象,如String,Integer等其他包装类。
10.静态变量和实例变量的区别
静态变量存储在方法区,为类所有;实例变量存储在堆中,其引用存在当前线程栈。
11.java创建对象的几种方式
采用new
通过反射
采用clone
通过序列化机制
前两者都需要显示的调用构造方法。造成耦合性最高的是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用。
12.String s1="ab",String s2="a"+"b",String s3="a",String s4="b",s5=s3+s4,请问s5==s2返回什么
返回false,在编译的过程中,编译会将s2直接优化为“ab”,会将其放置在常量池当中,s5则是被创建在堆区,相当于s5=new String("ab");
13.object有哪些公共方法
equals()、clone()、getClass()、notify()、notifyAll()、wait()、toString()
14.java中==和equals()的区别,equals()和hashcode的区别
==是运算符,用于比较两个变量是否相等,而equals是object类的方法,用于比较两个对象是否相等。默认object类的equals方法是比较两个对象的地址,此时和==的结果一样。换句话说,基本类型比较用==,比较的是他们的值。默认下,对象==比较时,比较的是内存地址,如果需要比较对象内容,需要重写equals方法。
15.equals和hashcode的联系
hashcode是object的一个方法,返回一个哈希值。如果两个对象根据equals方法比较相等,那么调用这两个对象中任意一个对象的hashcode()方法,必须产生相同的hash值。
如果两个对象根据equals()方法比较不相等,那么产生的hash值不一定相等(碰撞的情况下还是会相等的)
16.a.hashcode()有什么用?与a.equals(b)有什么关系?
hashcode()方法是相应对象整型的hash值。它常用于基于hash的集合类,如Hashtable、HashMap、LinkedHashMap等等。它与equals()方法关系特别紧密。根据java规范,使用equals()方法判断两个相等的对象,必须具有相同的hashcode。
将对象放入集合中时,首先要判断放入对象的hashcode值是否已经存在集合中,不存在则直接放入集合。如果hashcode相等,然后通过equals()方法判断要放入对象与集合中的任意对象是否相等;如果equals判断不相等,则直接将该元素放入集合,否则不放入。
17.有没有可能不相等的对象具有相同的hashcode
有可能,两个不同的对象有可能具有相同的hashcode值,这就是为什么在HashMap中会有冲突。如果两个对象相等,必须有相同的hashcode值,反之不成立。
18. 3*0.1==0.3返回值是什么?
false,因为有些浮点数不能完全精确表示出来。
19. a=a+b和a+=b有什么区别吗?
+=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换。如:
byte a = 127;
byte b = 127;
b = a + b; // error : cannot convert from int to byte
b += a; // ok
(译者注:这个地方应该表述的有误,其实无论 a+b 的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)
20.short s1= 1; s1 = s1 + 1; 该段代码是否有错,有的话怎么改?
有错误,short类型在进行运算时会自动提升为int类型,也就是说s1+1的运算结果是int类型。
改为s1 += 1;(+=操作符会自动对右边的表达式结果强转匹配左边的数据类型)
21.final、finalize和finally的不同之处
final是一个修饰符,可以修饰变量、方法和类;如果final修饰变量,意味着该变量在初始化后不能被改变。finalize方法是对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用finalize没有保证。finally是一个关键字,与try和catch一起用于异常的处理,finally块一定会被执行,无论try块中是否发生异常。
java基础怎样算好
22.static都有哪些用法
几乎所有人都知道static关键字两个基本用法:静态变量和静态方法。也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享。
除了修饰变量和方法之外,static也用于静态块,多用于初始化操作:
public class TestStatic{
static {
//静态块,用于初始化
}
}
此外static也用于修饰内部类,此时称之为静态内部类。
最后一种用法就是静态导包,即import static是JDK1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用类名。可以直接使用资源名,比如
import static java.lang.Math.*;
public class TestStatic1{
public static void main (String [] args){
//system.out.println(Math.sin(20));传统做法
System.out.println(sin(20));
}
}
23.final有哪些用法
final也是很多面试官喜欢问的知识点,能回答以下三点基本就算过了:
被final修饰的类不可能被继承
被final修饰的方法不可以被重写
被final修饰的变量不可以被改变
被final修饰的方法,jvm会将其内联,以提高运行效率
被final修饰的常量,在编译阶段会存入常量池
回答出编译器对final域要遵守的两个重排序规则更好:
1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
2.初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
24.数据类型相关
java中int 、char、long各占多少字节
25.int和Integer的区别
Integer是int的包装类型,在拆箱和装箱中,二者自动转换。int是基本类型,直接存数值,而Integer是对象,用一个引用指向这个对象。
26.String、StringBuffer和StringBuilder区别
String是字符串常量,final修饰;StringBuffer字符串变量(线程安全);StringBuilder字符串变量(线程不安全)
27.String和StringBuffer
String和StringBuffer主要区别是性能:String是不可变对象,每次对String进行操作,就等同于产生一个新的String对象。所以尽量不对String进行大量的拼接操作,否则会产生很多零时对象,导致GC开始工作,影响系统性能。
StringBuffer是对对象本身操作,而不是产生新的对象,因此在有大量的拼接情况下,建议使用StringBuffer。
但是需要主要现在jvm会对String拼接做一定的优化:
String s="This is only"+"simple"+"test"会被虚拟机直接优化成String
s="This is only simple test",此时就不存在拼接过程。
28.StringBuffer和StringBuilder
StringBuffer是线程安全的可变字符串,其内部实现时可变数组。StringBuilder是JDK1.5新增的,其功能和StringBuffer类似,但是非线程安全。因此在没有多线程问题的前提下,使用StringBuilder会取得更好的性能。
《java基础二》
29.java中的4中引用
强引用、软引用、弱引用、虚引用,不同类型的引用体现在GC上。
强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,jvm也不会回收它,而是抛出OutOfMemoryError错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显示的将引用赋值为null,这样一来的话,jvm在合适的时间就会回收该对象。
软引用:在使用软引用时,如果内存空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
弱引用:具有弱引用的对象拥有的声明周期更短。因为当jvm进行垃圾回收,一旦发现弱引用对象,无论当前内存是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能发现弱引用对象。
虚引用:顾名思义就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。
30.深拷贝和浅拷贝的区别是什么
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
31.一个java文件内部是否可以有其他类(非内部类)
只能有一个public公共类,但是可以有多个default修饰的类。
32.如何正确退出多层嵌套循环
使用标号和break;
通过在外层循环中添加标识符;
33.内部类的作用
内部类可以有多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。内部类对象的时刻不依赖于外部类对象的创建。内部类并没有令人疑惑的“is-a”关系,它就是一个独立的实体。
内部类提供了更好的封装,除了该外围类,其他类都不能访问。
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
}
}
}
34.java中使用什么类型表示价格比较好
如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义类型的double类型。
35.如何将byte转为String
可以使用String接收byte[]参数的构造器来进行转换,需要注意的点是使用正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。
public static String byteArrayToStr(byte[] byteArray){
if(null == byteArray){
return null;
}
String str=new String(byteArray);
return str;
}
36.可以将int强转为byte类型吗,会产生什么问题
我们可以做强制转换,但是java中的byte是8位,而int是32位,所以如果强制转换为int类型,就会将高24位被丢弃。
37.你知道哪些垃圾回收算法
垃圾回收从理论上非常容易理解,具体的方法有以下几种:
标记-清除算法
标记-复制算法
标记-整理算法
分代回收
38.如何判断一个对象是否应该被回收
这就是所谓的对象存活性判断,常用的方法有两种:
引用计数法
对象可达性分析
由于引用计数法存在相互引用导致无法进行GC的问题,所以目前jvm虚拟机多使用可达性分析算法。
39.简单解释一下垃圾回收
java垃圾huishou机制最基本的做法是分代回收。内存中的区别被划分成不同的世代,对象根据其存活的时间被保存在不同的世代中。一般分为代,年轻、年老和永久代。内存分配是发生在年轻代中。当一个对象存活的时间足够长的时候,它就会被复制到年老代中。对于不同的世代可以使用不同的垃圾回收算法。进行世代划分的出发点是对应用中对象存活的时间进行研究之后得出的统计规律。一般来说,一个应用中大部分对象存活的时间都很短。比如局部变量存活的时间就只在方法的执行过程中。基于这一点,对于年轻代的垃圾回收算法就可以很有针对性。
40.调用System.gc()会发生什么
通知GC开始工作,但是GC真正开始的时间不确定。
41.进程和线程的区别
简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。
42.多线程上下文切换
多线程上下文切换是指CPU控制权由一个正在运行的线程切换到另一个就绪并等待获取CPU执行权的线程的过程。
43.创建线程的方式,它们之间的区别
通过实现Runnable接口,或者继承Thread类。相比扩展性,Runnable更优。
java不支持多继承,因此扩展Thread类就代表这个子类不能扩展其他类。而实现Runable接口的类还能扩展另一个类。
类可能只要求可执行即可,继承Thread类的开销过大。
44.Thread类中的start()和run()方法区别
start()方法被用来启动新创建的线程,而start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run方法的时候,只会在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
45.导致线程阻塞的原因有哪些
阻塞指的是暂停一个线程执行以等待某个条件发生(如某资源就绪)
46.sleep()和yield()区别
sleep()方法和yield()方法是Thread的静态方法,都会使当前运行的线程放弃CPU,把运行机会让给别的线程。
两者的区别在于:
sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给同优先级或者更高优先级线程一个运行的机会。
当线程执行了sleep(long millis)方法之后进入到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法之后就转到就绪状态;
sleep()方法声明抛出InterruptException异常,而yield()方法没有声明抛出任何异常;
sleep()方法比yield()方法具有更好的移植性。
47.产生死锁的条件
1)互斥条件:一个资源每次只能被一个进程使用;
2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不变;
3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强制剥夺;
4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
48.为什么wait()方法和notify()/notifyAll()方法要在同步块中被调用
这是JDK强制规定的,wait()方法和notify()/notifyAll()方法在调用前都必须获得对象的锁。
49.wait()方法和notify()/notifyAll()方法在放弃对象监视器时有什么区别
wait()方法和notify()/notifyAll()方法在放弃对象监视器的时候区别在于:wait()方法立即释放监视器,notify()/notifyAll()方法则会等待线程剩余代码执行完毕才会放弃对象监视器。
50.wait()和sleep()的区别
1)sleep()来自Thread类,和wait()来自object类。调用sleep()方法的过程中,线程不会释放对象锁,而调用wait()方法会释放锁。
2)sleep()睡眠后不出让系统资源,wait()让其他线程可以占用CPU
3)sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒,而wait()需要配合notify()/notifyAll()使用。
51.为什么wait、notify和notifyAll这些方法不在Thread类当中
一个很明显的原因是java提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁,那么调用对象的wait方法就有意义了。如果wait方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait、notify和notifyAll都是锁级别的操作,所以把它们定义在object类中,因为锁属于对象。
52.怎样唤醒一个阻塞的线程
如果线程是因为调用了sleep()、wait()、join()方法导致阻塞,可以中断线程,并且抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,java代码并没有办法直接接触到操作系统。
53.synchronized与Reentrantlock的区别
synchronized是和if、else、for、while一样的关键字,Reentrantlock是类,这是两者的本质区别。既然Reentrantlock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量。Reentrantlock比synchronized的扩展性体现在几点上:
1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
2)ReentrantLock可以获取各种锁的信息
3)ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word。
54.FutureTask是什么
这个其实前面有提到过,FutureTask表示一个异步运算的任务。FutureTask里面可以传入一个Callable的具体实现类,可以对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操作。当然,由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中。
55.一个线程如果出现了运行时异常怎么办
如果这个异常没有被捕获的话,这个线程就停止执行了。另外重要的一点是:如果这个线程持有某个对象的监视器,那么这个对象的监视器会被立即释放。
56.如何在两个线程间共享数据
通过在线程间共享对象就可以了,然后通过wait/notify/notifyAll,await/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue就是为线程之间共享数据而设计的。
57.为什么要使用线程池
避免频繁的创建和销毁线程,达到线程对象的重用。另外使用线程池,还可以根据项目灵活的控制并发的数目。
58.java中使用的线程调度算法是什么
抢占式,一个线程用完CPU之后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。
59.Thread.sleep(0)的作用是什么
由于java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程能获得CPU控制权,可以使用Thread.sleep(0) 手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。
60.什么是乐观锁和悲观锁
乐观锁:认为竞争不总是会发生,因此它不需要持有锁,将比较——替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么久应该有相应的重试逻辑。
悲观锁:悲观锁认为竞争总是会发生,因此每次对某资源进行操作是时,都会持有一个独占锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。
61.java中的++操作符线程安全吗
不是线程安全的操作,它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交叉。
62.poll()和remove()方法的区别
poll()和remove()都是从队列中取出一个元素,但是poll()在读取元素失败时会返回空,但是remove()失败时会抛出异常。
63.LinkedHashMap和PriorityQueue的区别
priorityQueue是一个优先级队列,保证最高或者最低优先级的元素总是在队列头部,但是LinkedHashMap维持的顺序是元素插入的顺序。当遍历一个PriorityQueue时,没有任何顺序保证,但是linkedHashMap输出顺序是元素插入的顺序。
64.ArrayList和LinkedList的区别
最明显的区别是ArrayList底层的数据结构是数组,支持随机访问,而LinkedList底层的数据结构是双向循环链表,不支持随机访问。使用下标访问一个元素,ArrayList的时间复杂度是O(1),而LinkedList是O(n).
65.comparator和comparable的区别
comparable接口用于定义对象的自然顺序,而comparator通常用于定义用户定制的顺序。comparable总是只有一个,但是可以有多个comparator来定义对象顺序。
66.如何实现集合排序
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/1678.html