Java基础面试题整理

第一题:
”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
A:static表示“静态”的意思,可用于修饰成员变量和成员方法,静态成员是随着类的加载而加载的,因此可以直接使用类访问。但是要注意,在静态成员方法中,不可以调用非静态成员变量或者非静态成员方法。
B:不可以重写,也没办法重写,因为private修饰的方法只能在本类被访问,连子类也无法访问,因此重写是无法实现的,但是可以继承,绝不可以调用。
C:对于静态方法,是编译时静态绑定,而重写是为了实现多态,是动态时绑定的,并不需要重写。
静态变量被分配内存中仅仅被加载一次,是指着个静态变量在此jvm进程中仅仅加载一次,也就是为什么无论创建多少个对象都只有一个相同的静态变量。
见下列例题:
public class A {
static{
System.out.print(“1”);
}
public A(){
System.out.print(“2”);
}
}
public class B extends A {
static{
System.out.print(“a”);
}
public B(){
System.out.print(“b”);
}
}
public class Hello {
public static void main(String[] args) {
A a = new B(); // 第一步
a = new B(); // 第二步
}
}
请问
第一步单独输出结果为多少?? 1a2b
第二步单独输出结果为多少?? 2b
整个输出结果为多少?? 1a2b2b
第一步静态变量被加载一次,初始化一次,得出结果
第二步静态变量不被加载(jvm进程仅仅执行一次静态变量),初始化一次,仅仅有个2b,
所以加上第一步的,整个输出结果为:1a2b2b

什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
因为首先 .java文件是要在jvm上面运行的,这是一个可以执行字节码文件的虚拟机进程,而Java虚拟机对应着各种平台有着不同的版本,因此可以被运行在任意平台,而字节码文件只需要运行在jvm上面,便可以执行程序。

Java虚拟机英文名是:Java Virtual Machine,简称JVM。是可以执行字节码文件的虚拟机进程。
Java源文件(.java)—-编译成(javac命令)—- Java字节码文件(.class),运行在jvm上(java命令)

JDK和JRE的区别是什么?
JRE的全名为:Java Runtime Environment; 是Java运行环境,它包含了jvm和Java基础类库,是使用Java语言编写的程序运行所需要的软件环境。
JDK的全名为:Java Development kit; 是Java开发工具包,它包含了JRE,以及下列等工具
Java.exe是java虚拟机
javadoc.exe用来制作java文档
jdb.exe是java的调试器
javaprof,exe是剖析工具

是否可以在static环境中访问非static变量?
(类加载机制)
不可以,因为静态成员是属于类的,它随着类的加载而加载到静态方法区内存,当类加载时,此时不一定有实例创建,没有实例就不可以访问非静态成员。
补充一点,静态成员变量只可以在类主体中定义,不能在方法中定义,即使是静态方法也不行。我是这样理解的,因为方法中定义的变量,生命周期便是方法执行完便销毁内存,但是静态变量很明显是属于类的,因此生命周期一定比局部变量的生命周期长,因此两者是相矛盾的,也就说明了,方法中不允许定义静态变量。

Java支持的数据类型有哪些?什么是自动拆装箱?
A:Java的数据类型分为两种,
第一种是基本数据类型(又名原生态或内置类型),分类为,四类八种
整数类型 byte 1,short 2,int 4,long 8
浮点型 float 4,double 8
逻辑型 boolean 1(允许分配的最小内存是8位)
字符型 char 2 (‘\u0000’)
String是属于引用类型。
第二种便是引用数据类型,包括类,接口和数组,引用数据类型就是指对一个对象的引用,也可以理解成,引用类型声明的变量,在内存中存储的实际上是地址,而实体在堆中。对象包括实例和数组两种。
B:自动装箱和拆箱是基本类型和引用类型之间的转换,可以new出对象,更好的操作数据,例如可以集合中想存放基本类型,泛型的限定类型只能是对应的包装类型。

Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?
A:覆盖是发生在父类和子类之间的状况,是子类重新定义了父类的方法。
要遵循“两同两小一大的规则”,即:
1,两同:方法名相同,形参列表相同
2,两小:子类方法返回值类型如果是引用,应是父类方法返回值类型的子类或者原类型,如果是基本类型,必须一样,子类方法声明抛出的异常应比父类方法声明跑出的异常更小或相等。
3,一大:子类方法的访问权限应比父类方法的访问权限更大或相等。
4,重写是发生在运行时期的,因为编译期编译器不知道并且没办法确定该去调用哪个方法,JVM会在代码运行的时候作出决定。
B:重载是发生一个类当中的状况
1,方法名必须相同
2,参数列表必须不同(个数不同,类型不同,排列顺序不同等)
3,和返回值类型无关
4,重载是发生在编译时期的,因为编译器是根据参数的类型来选择使用哪种方法。
以上都是为了实现多态。

Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?
A:构造函数是创建实例时将会被调用的一种特殊函数。(特殊在那一方面?没有返回值,不会被实例调用,而是创建实例)
B:构造函数重载和方法重载很相似,每个重载的构造函数都有着不同的形参列表,这也是在创建实例传入不同的参数来选择不同的构造器。
C:Java不支持像C++那样复制构造函数。

Java支持多继承吗?
Java不支持多继承,只支持单继承,即一个子类只能有一个直接父类。但是Java中的接口支持多继承,一个子接口可以有多个父接口,一个子接口继承了多个父接口,也就扩展了多个功能,当类实现接口时,类也就相应的扩展了多个功能,这也弥补了单继承的缺点。
为什么不支持多继承?我的理解是,可能是怕引起混淆,如果有多个直接父类,这多个直接父类中有相同的变量或方法名,但是行为不一样(都是吃饭,用勺子和用筷子),那么在运行时,JVM也无法判断使用哪个变量或方法了,因为相同的方法可能有不同的行为,但是接口不一样,即使这多个接口含有相同的方法名, 但是因为没有方法体(也就避免了相同的方法有不同的行为),子接口继承那个父类都不是问题,这个子接口只能有这么一个方法,实现时,根据需求,在方法中填入不同的行为,也就扩展了相应的功能。

接口和抽象类的区别是什么?
接口可以说是抽象类中的一种特例。
1,抽象类可以有构造方法,接口不能有构造方法。
2,抽象类可以有普通成员变量和静态成员变量,并且静态变量的访问类型可以任意,但是接口不能有普通成员变量,且成员变量默认只能为 public static final。
3,抽象类中的成员方法默认为public abstract,但是访问修饰符可以是public,protected,或者默认(不能是private,因为抽象类可以被继承),以及可以包含普通成员方法,但是接口中的抽象方法只能是public abstract。
4,抽象类中可以包含静态方法,接口类中不能包含静态方法,1.8之后可以有静态方法,不必加abstract(abstract和static不能放在一起)。
5,一个类可以实现多个接口,但只能继承一个抽象类。
6,如果子类可以没有实现抽象父类中的所有抽象方法,但是子类也必须定义为abstract类型,而接口是必须实现所有抽象方法的,否则定义为抽象类(我们平时所实现的接口其实已经实现了所有抽象方法,只是没写出来罢了)。
但是平时中,应该多用接口,少用抽象,因为软件设计讲究的是低耦合性,接口可以实现多个,但是抽象只能单继承。

什么是值传递和引用传递?
值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对 象本身 。 所以对该副本进行操作时,会同时改变原对象。

final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰符
因为abstract修饰的方法是必须在其子类中实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为调用的是父类的方法,而父类的方法又是抽象的方法,抽象方法不具备调用的意义,又不能够调用,所以上的修饰符不能放在一起。

下面这条语句一共创建了多少个对象:
String s=”a”+”b”+”c”+”d”;?
(直接形成abcd,而不是先生成四个字符)

一个对象,因为像这种在编译时期就可以被编译器识别的,可以直接拼接成 String s = “abcd”; ,他和变量不同,变量相加,编译器识别不出来,只有在运行时期才知道。是相当于 StringBuffer调用append(),在堆上产生新的对象。

Error和Exception的区别是什么?
Error类和Exception类的父类都是throwable类,他们的区别是:
Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误所导致的应用程序中断,仅靠程序本身无法恢复和预防。
而Exception类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception )
运行时异常;编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会直接终止。
而受检查的异常,都是可以被处理修复的异常,要么用try…catch…捕获并处理,要么抛出。

常见的异常;
- ArithmeticException(算术异常)
- ClassCastException (类转换异常)
- IllegalArgumentException (非法参数异常)
- IndexOutOfBoundsException (下标越界异常)
- NullPointerException (空指针异常)
- SecurityException (安全异常)


第异常问答题

异常处理完成以后,Exception对象会发生什么变化?
Exception对象会在下一个垃圾回收过程中被回收掉。

final,finally以及finalize有什么区别?
Final用于修饰属性,方法以及类,各表示属性不可改变,方法不可重写,
子类不可覆盖。
Finally是异常处理结构中的一部分,表示总是处理。
Finalize是Object类的一个方法。当垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法 但是在Java中,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行。

Java中实现多态的机制是什么?
静态多态:重载
动态多态:重写

JAVA 语言如何进行异常处理,关键字: throws,throw,try,catch,finally 分别代表什么意义?在 try 块中可以抛出异常吗?
Throws代表捕获并向外抛出异常。
Throw代表抛出异常,往往是throw new 自定义异常
此为有参构造
Class sextends Exception{
public 方法名(String msg)
Super(msg);
}
try…catch 内部捕获异常并作自定义处理
Finally 表示总是被执行,除非前面有System.exit(1);表示非正常退出程序。

两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?hashCode()和equals()方法的重要性体现在什么地方?
答:不对,Java对于eqauls方法和hashCode方法是这样规定的:
(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;
(2)如果两个对象的hashCode相同,它们并不一定相同。
其重要性体现在,hashCode用来确定位置,而equals用来比较对象是否相等,但是如果重写equals而没有重写hashCode则可能导致同一个对象没有机会equals,因为可能同一个对象有着不同的hashCode。所以hashCode和equals对hashMap的精确性比较重要。

是否可以继承String类?
String 类是final类,不可以被继承。

char 型变量中能不能存贮一个中文汉字,为什么?
char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode,每个Unicode码占用2个字节,而一个char类型也是占2个字节(16比特),所以放一个中文是没问题的。

String和StringBuilder、StringBuffer的区别?
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
String 类代表字符串,它是位于字符串常量区;因为它的底层是用final修饰的,所以它们的值在是不可改变的。任何试图改变它的行为都会产生新的对象。
而StringBuilder和StringBuffer类似,都是字符串缓冲区,初始容量一般是16 ,长度也可以改变,但StringBuffer是线程安全的,StringBuilder不是线程安全的,如果只是在单线程中使用字符串缓冲区,那么StringBuilder的效率会更高些。
值得注意的是StringBuilder是在JDK1.5版本中增加的。以前版本的JDK不能使用该类。

JVM加载class文件的原理机制
当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。
加载class文件需要三个阶段,分别是加载、连接(验证、准备和解析)和初始化。
类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件。
类的加载是由类加载器完成的,类加载过程采取了委托模型机制(PDM)。PDM更好的保证了Java平台的安全性。PDM是指类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。
这里写图片描述
当类被加载后就进入连接阶段,这一阶段包括验证(检查载入的class文件数据的正确性)、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:
1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;
2)如果类中存在初始化语句,就依次执行这些初始化语句。

抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。对于synchronized,我认为也是不能,因为即使可以,也是毫无意义,因为首先同步是一个高开销操作,只要有了synchronize,就会被放入监视器中,那么在abstract加上synchronize是不明智的,因为没有代码块需要去被监视。

阐述静态变量和实例变量的区别。
答:静态变量是被static修饰符修饰的变量,它是随着类的加载而加载的,是在类的初始化之前便被分配静态方法区,所以无论创建多少个对象,也只有一个该变量,前提是只有一个进程。
实例变量必须创建对象之后才会被分配内存,然后只能被对象调用。


堆和垃圾收集器问答

Java 中会存在内存泄漏吗,请简单描述。
理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题;然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。
无用可达的对象可以举个例子来说明一下,例如像往集合中填入对象,然后再使这个对象为null,那么此时,垃圾回收机制不会回收此对象,因为实际上集合对象还在无意识的保留着null对象,所以应该先从集合中删除再置为null。

对象什么时候会被垃圾回收?

当一个对象到不可达时,在下一个垃圾回收周期中尝试回收该对象,如果该对象重写了finalize()方法,并在这个方法中成功自救(将自身赋予某个引用),那么这个对象不会被回收。但如果这个对象没有重写finalize()方法或者已经执行过这个方法,也自救失败,该对象将会被回收

GC是什么?为什么要有GC?
GC是垃圾收集的意思,Garbage Collection。
因为内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,而Java提供的GC功能可以自动进行监测,这样的好处是可以有效的防止内存泄露,可以最大效率的利用内存空间。

简述一下垃圾回收器
垃圾回收器通常是作为一个单独的低优先级的线程运行,在不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,但程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。所以它的缺点是不可预知性。虽然可以调用:System.gc(),但不保证一定会执行。

简述一下垃圾回收机制
Java垃圾回收机制采用了“分代式垃圾收集”。
这种方法会根据Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
- 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
- 幸存者乐园(Survivor):这里存放着从伊甸园幸存下来的对象。
- 终身颐养园(Tenured):这里存放着足够老的幸存对象。

解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。
通常我们定义一个基本数据类型的变量(局部),一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间,栈空间操作起来最快但是栈很小,栈空间用光了会引发StackOverflowError;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代;程序中的字面量如直接书写的”hello”和常量都是放在常量池中,常量池是方法区的一部分。方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量等数据;堆和常量池空间不足则会引OutOfMemoryError。

Java中堆的结构是什么样子的?
虚拟机中的共划分为三个代:
年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent
Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系
不大。年轻代和年老代的划分是对垃 圾收集影响比较大的。

年轻代:
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老代:(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor区过来的对象。而且Survivor区总有一个是空的。同时,根据程序需要, Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

年老代:
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

持久代:
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应
用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持
久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。


接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?抽象类中是否可以有静态的 main 方法?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可以继承具体类。抽象类可以有静态的main方法。


*

集合类问答*

HashTable和HashMap的区别是什么?

继承不同。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map

Hashtable 中的方法是同步,安全的,是synchronized(上锁的),而HashMap中的方法在缺省情况(缺省就是默认)下是非同步的,不安全的,是非synchronized。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
可以通过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);

Hashtable中,key和value都不允许出现null值。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

ArryList,Vector,LinkList,之间的区别是什么?
首先,ArrayList和Vector的区别为:
1) Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。

其次,ArrayList和LinkList的区别为:
ArrayList底层是用数组实现的,是一块连续的空间
特点是:查询快,增删慢,因为需要移动内存
LinkedList底层是用链表实现的,是一系列不连续空间
特点是:查询慢(顺藤摸瓜),增删较快。
如何删除?
List.remove(index),返回被删数据
如何提高集合查询速度?
扩大内存,减小加载因子(原因和链表存放数据的原理有关,见笔记)

第三十六题
Collection和Collections的区别?
Collection是一个接口,它是Set、List等容器的父接口;Collections一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
比如:Collections.synchronizeMap();
Collections.sort(); 排序。
Collections.min(); 返回最小元素 Collections.max(); 返回最大元素。

第三十七题
List、Map、Set三个接口存取元素时,各有什么特点?
List存放的元素是可以重复且有序的,取元素可以根据索引。Set存放的元素不可重复且无序排列(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一,也是无序且不可重复。

HashMap的工作原理?
底层是数组加链表的结构,称为哈希表(hashing)。
其数组是table,table数组里可以存储的元素的位置称为“bucket”,而Entry对象存储的是key-value数据,所以Entry[]存储的Map中的内容。
当存放数值时:
HashMap是基于hashing的原理
int hash = hash(key.hashCode());
Int index = hash(key)%len 所返回的数值便是这个Entry所要放的索引处。
先对键调取hashCode()方法,返回的hashCode()用于找到bucket位置来储存键对象和值对象作为Map.Entry。
如果存在哈希冲突,那么会先用equals方法来比较key键返回为false的话,第二个Entry对象便会以链表形式保存数据。
当取数据时:
先根据key的hashCode找到bucket位置(就像当初放在bucket时),如果存在链表的结构,那么便会一个个比较,利用key建获取唯一的value值。

HashMap与ConcurrentHashMap的区别
ConcurrentHashMap的工作机制,通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

Enumeration接口和Iterator接口的区别有哪些?
Enumeration速度是Iterator的两倍,而且占用内存更小。
但是Iterator是线程安全的,他支持快速失败(fail-fast)
第二,它可以在迭代过程中删除数据。

快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
快速失败:当你在迭代一个集合的时候,如果有另一个线程正在修改你正在访问的那个集合时,就会抛出一个ConcurrentModification异常。
在java.util包下的都是快速失败,不能在多线程下使用。

安全失败:你在迭代的时候会去底层集合做一个拷贝,在拷贝的集合上进行遍历,所以你在修改上层集合的时候是不会受影响的,不会抛出ConcurrentModification异常。
在java.util.concurrent包下的全是安全失败的,可以在多线程下使用。

Iterator和ListIterator的区别是什么?
这里写图片描述
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向(next)也可以后向(previous)。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素(add),替换元素(set),获取前一个(previousIndex)和后一个元素(nextIndex)的索引。
hasNext(); –返回true或false
Next(); –返回集合中的数据


线程类问答

进程和线程的区别是什么?
进程和线程都是CPU工作时间段的描述
每个程序,CPU都会分配给他执行时间,所以统称为进程,它轮流执行顺序为:
先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文
即:
进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文;
对于线程来说:
程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。
这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,是更为细小的CPU时间段

比喻来说,当你开了一个QQ,就开了一个进程,开了一个迅雷,也开了一个进程。
在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程
一个进程管着多个线程。

创建线程有哪几种方式?你喜欢哪一种?为什呢?
就我目前所学来看,一共有两种
A:继承Thread类
B:实现Runnable接口
我比较喜欢实现Runnable接口,虽然他必须再次使用Thread类包装后才能调用start()方法,因为它是符合低耦合的要求的(但是如果一个类已经在继承其它父类的时候,因为Java不支持多继承,这时可以使用接口来完成线程的创建。)

概括的解释下线程的几种可用状态?
线程的生命周期:
1:(new) 新创建一个线程对象
2: (可运行runnable)线程对象创建之后,其他线程,例如main线程调取了该对象的start()方法。该状态的线程位于可运行的线程池中,等待被分配给cpu的时间片。
3: (正在运行running)运行状态,获取cpu的时间片,执行该程序代码。
4: (其他阻塞状态)阻塞状态是指线程因为某种原因而让出了CPU的时间片,进入到可运行状态。
阻塞的三种情况:
1:等待阻塞:运行(running)的线程执行O.wait()方法,jvm会把该线程放入到等待队列中。
2:同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则jvm会把该线程放入锁池中。
3:其他阻塞:运行(running)的线程执行Thread.sleep或者Thread.join()方法,或者发出I/O请求时,jvm会把该线程置为阻塞状态。
当sleep方法超时,或者join等待线程终止或者超时,或者I/O处理完毕 后,线程重新转入可运行的状态,等待分配CPU资源。
4: 死亡(dead):线程run(),main(),方法执行结束,或者因异常退出run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

同步方法和同步代码块的区别是什么?
同步方法即有synchronized关键字修饰的方法。
同步方法默认用this或者当前类class对象作为锁。
同步代码块:
synchronized(object){代码内容}
主要是修饰需要进行同步的代码块,比同步方法更颗粒度。
我们应该用同步代码块,因为要知道同步是一种高开销的操作,因此应该尽量减少同步的内容。

在监视器(Monitor)内部,是如何做到线程同步的?
监视器和锁在Java虚拟机中是一块使用的,一旦方法或者代码块被synchronized修饰,那么这个部分就放入了监视器的监视区域,确保一次只能有一个线程执行该部分的代码。线程在获取锁之前不允许执行该部分代码。

线程的sleep()方法和yield()方法有什么区别?

sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
阻塞状态–>就绪状态–>运行状态

sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;

sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

第四十题
Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。
wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

第四十一题
举例说明同步和异步。
同步:发送一个请求,等待返回,然后再发送下一个请求。(可以单线程和多线程)是属于阻塞式操作。
异步:发送一个请求,不需要等待返回,随时可以再发送下一个请求,是属于非阻塞式操作。在很多情况下采用异步途径往往更有效率。
例如正在写的数据以后可能被另一个线程读到,这是异步。
数据写完之后,另一个线程才可以读,这是同步操作。

启动一个线程是调用run()还是start()方法?
启动一个新线程是调用start()方法,start内部调用run()方法,让此线程处于就绪状态。
run()方法只是Runnable接口中定义的一个普通方法。

什么是死锁?
是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的状况。
产生死锁的四个条件
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
如何避免?
一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。

14.Java接口的修饰符可以为()

A private B protected C final D abstract

答案:CD

关于String类的一些方法
Str.CharAt(index); –返回索引处的字符
Str.codePointAt(index); –返回索引处字符的unicode值
s1.compareTo(s2); –按字典顺序比较两个字符串,小返负,大返正,往往是以括号内的作为参考点,来返回具体数字
s1.concat(s2) –链接两个字符串
Str.endWith(“.java”); –判断是否以指定的后缀结束,返回布尔值
s1.equalsIgnoreCase(s2); –忽略大小写来比较两个字符串的内容,返回布尔值
Str.indexOf(“java”); –返回指定字符串第一次出现的索引(索引都是依旧从0开始的),如果没有,返回-1
Str.isEmpty(); –判断字符串是否为空,只有length()方法为0时才会返回true,如果是含有空格,返回false
Str.replaceAll(“共产党”,”*”); –替换String为某些内容
Str.split(“;”) –把一个有规则的String按照特定标记切分为一个String[];里面的元素便是一个字符串
Str.substring(2,10); –截取字符串,从索引2开始,到索引(10-1)结束
Str.substring(2); –截取字符串,从索引2开始,一直到末端
Str.toUpperCase(); –将字符串转换为大
Str.toLowerCase(); –将字符串转换为小
Str.trim(); –去掉前边和后边的空格,但是中间的不行
Str.replaceAll(“ ”;“”); –这样可以去掉所有的空格
Str.toCharArray(“”); –将字符串转换为字符数组

Math.round(11.5);为多少?
Math.round(-11.5);为多少?

Math.round(x)相当于Math.floor(x+0.5);加上0.5再向下(最小数)取整就行了.
Math.floor();往最小数靠近
Math.ceil();往最大数靠近


有的图片是截取的,忘记源处,如果有发现的,请指出来,一定表明原作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值