赞
踩
最近刷了1000道牛客网的面试题,大概是三个月左右吧,但是很多题目大同小异,考的都是同一个知识点,面试的时候也碰到不少原题。
我就把这些题目整理了一下,涵盖Java基础、Java集合、Java多线程、jvm,整理后挑出大概70道题高质量的题目,如果你没时间刷牛客网,可以参考一下,相信你在做笔试的时候会遇到的:
A ConcurrentHashMap使用synchronized关键字保证线程安全
B HashMap实现了Collction接口
C Array.asList方法返回java.util.ArrayList对象
D SimpleDateFormat是线程不安全的
D
ConcurrentHashMap 使用segment来分段和管理锁使用ReentrantLock来保证线程安全。
这个是HashMap的源码:
- public class HashMap<K,V>
- extends AbstractMap<K,V>
- implements Map<K,V>, Cloneable, Serializable
Arrays.asList() 返回 java.util.Arrays.ArrayList 对象,这里的 ArrayList 是 Arrays 私有的内部类;并不是java.util.ArrayList。
SimpleDateFormat没有加同步锁,故不安全。
- public static void main(String[] args){
- String s;
- System.out.println("s="+s);
- }
A 代码编程成功,并输出”s=”
B 代码编译成功,并输出”s=null”
C 由于String s没有初始化,代码不能编译通过。
D 代码编译成功,但捕获到NullPointException异常
C
局部变量没有默认值
A 接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。
B abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface,实现多重继承。接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。
C 在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是 static final的,不过在 interface中一般不定义数据成员),所有的成员方法默认都是 public abstract 类型的。
D abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"has-a"关系,interface表示的是"is-a"关系。
D
abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
接口中:
如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法
final变量在使用前必须先赋值
A 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器,每个线程都需要一个独立的程序计数器.
B Java虚拟机栈描述的是java方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表、类信息、动态链接等信息
C Java堆是java虚拟机所管理的内存中最大的一块,每个线程都拥有一块内存区域,所有的对象实例以及数组都在这里分配内存。
D 方法区是各个线程共享的内存区域,它用于存储已经被虚拟机加载的常量、即时编译器编译后的代码、静态变量等数据。
B C
java虚拟机栈:线程私有,没有类信息,类信息是在方法区中
java堆是被所有线程共享的一块内存区域,而不是每个线程都拥有一块内存区域。
A 访问修饰符的限制一定要大于被重写方法的访问修饰符
B 可以有不同的访问修饰符
C 参数列表必须完全与被重写的方法相同
D 必须具有不同的参数列表
B C
方法重写要注意的事项:
1.方法重写时, 方法名与形参列表必须一致。
2.方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。
3.方法重写时,子类的返回值类型必须要小于或者等于父类的返回值类型。
4.方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。
Exception(大)
RuntimeException(小)
A选项的一定要大于错误,而是子类重写方法的访问权限不能低于父类重写方法的访问权限
D 是重载要求
A 让该类不使用任何关键字
B 使用private关键字
C 使用protected关键字
D 使用void关键字
A
总结:default拒绝一切包外访问;protected接受包外的子类访问
public>protected>default>private
错误
在Java中,变量有两种类型,一种是原始类型,一种是引用类型。
原始类型一共有8种,它们分别是char,boolean,byte,short,int,long,float,double。
- A float f[][] = new float[6][6];
- B float []f[] = new float[6][6];
- C float f[][] = new float[][6];
- D float [][]f = new float[6][6];
- E float [][]f = new float[6][];
A B D E
一维长度必须定义,二维可以后续定义
A 抽象类可以有构造方法,接口中不能有构造方法
B 抽象类中可以包含非抽象的普通方法,接口中的方法必须是抽象的,不能有非抽象的普通方法
C 一个类可以实现多个接口,但只能继承一个抽象类
D 接口中可以有普通成员变量,抽象类中没有普通成员变量
B D
参考第3题答案
抽象类
1.抽象类中可以构造方法
2.抽象类中可以存在普通属性,方法,静态属性和方法。
3.抽象类中可以存在抽象方法。
4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。
5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。接口
1.在接口中只有方法的声明,没有方法体。
2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上
public static final
3.在接口中的方法,永远都被public来修饰。
4.接口中没有构造方法,也不能实例化接口的对象。
5.接口可以实现多继承
6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法
7.则实现类定义为抽象类。
java8中接口 可以有default、static方法,所以B是错的。
- public static void main(String[] args) {
- int num = 2;
- switch (num) {
- case 1:
- ++num;
- case 2:
- ++num;
- case 3:
- ++num;
- default:
- ++num;
- break;
- }
- System.out.println(num);
- }
- }
5
到break才跳出
- public class Tester{
- public static void main(String[] args){
- Integer var1=new Integer(1);
- Integer var2=var1;
- doSomething(var2);
- System.out.print(var1.intValue());
- System.out.print(var1==var2);
- }
- public static void doSomething(Integer integer){
- integer=new Integer(2);
- }
- }
1true
var1==var2
会进行拆箱,比较的是值。
- a = Integer.parseInt("1024");
-
- b = Integer.valueOf("1024").intValue();
下述说法正确的是()
A a是整数类型变量,b是整数类对象。
B a是整数类对象,b是整数类型变量。
C a和b都是整数类对象并且它们的值相等。
D a和b都是整数类型变量并且它们的值相等。
D
intValue()是把Integer对象类型变成int的基础数据类型;
parseInt()是把String 变成int的基础数据类型;
Valueof()是把String 转化成Integer对象类型;(现在JDK版本支持自动装箱拆箱了。)
本题:parseInt得到的是基础数据类型int,valueof得到的是装箱数据类型Integer,然后再通过valueInt转换成int,所以选择D
A Java反射主要涉及的类如Class, Method, Filed,等,他们都在java.lang.reflet包下
B 通过反射可以动态的实现一个接口,形成一个新的类,并可以用这个类创建对象,调用对象方法
C 通过反射,可以突破Java语言提供的对象成员、类成员的保护机制,访问一般方式不能访问的成员
D Java反射机制提供了字节码修改的技术,可以动态的修剪一个类
E Java的反射机制会给内存带来额外的开销。例如对永生堆的要求比不通过反射要求的更多
F Java反射机制一般会带来效率问题,效率问题主要发生在查找类的方法和字段对象,因此通过缓存需要反射类的字段和方法就能达到与之间调用类的方法和访问类的字段一样的效率
正确答案: A D F
A Class类在java.lang包
B 动态代理技术可以动态创建一个代理对象,反射不行
C 反射访问私有成员时,Field调用setAccessible可解除访问符限制
D CGLIB实现了字节码修改,反射不行
E 反射会动态创建额外的对象,比如每个成员方法只有一个Method对象作为root,他不直接暴露给用户。调用时会返回一个Method的包装类
F 反射带来的效率问题主要是动态解析类,JVM没法对反射代码优化。
- interface Action{
- void fly();
- }
- class Hero implements Action{
-
- //……
-
- }
A private void fly(){}
B void fly(){}
C protected void fly(){}
D public void fly(){}
D
接口方法默认是public abstract的,且实现该接口的类中对应的方法的可见性不能小于接口方法的可见性,因此也只能是public的。
A equals(Object obj) 指示某个其他对象是否与此对象“相等”
B copy() 创建并返回此对象的一个副本
C wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
D toString() 返回该对象的字符串表示
B
是clone方法 不是copy方法。
A final是java中的修饰符,可以修饰类、接口、抽象类、方法和属性
B final修饰的类肯定不能被继承
C final修饰的方法不能被重载
D final修饰的变量不允许被再次赋值
A C
final修饰类、方法、属性!不能修饰抽象类,因为抽象类一般都是需要被继承的,final修饰后就不能继承了。final修饰的方法不能被重写而不是重载!
final修饰属性,此属性就是一个常量,不能被再次赋值!
- public class OuterClass{
- private float f=1.0f;
- //插入代码到这里
- }
A
- class InnerClass{
- public static float func(){return f;}
- }
B
- abstract class InnerClass{
- public abstract float func(){}
- }
C
- static class InnerClass{
- protected static float func(){return f;}
- }
D
- public class InnerClass{
- static float func(){return f;}
- }
ABCD
1.静态内部类才可以声明静态方法 A、C错
2.静态方法不可以使用非静态变量 D错
3.抽象方法不可以有函数体 B错
A 抽象类可以有构造方法,接口中不能有构造方法
B 抽象类中可以有普通成员变量,接口中没有普通成员变量
C 抽象类中不可以包含静态方法,接口中可以包含静态方法
D 一个类可以实现多个接口,但只能继承一个抽象类。
A B D
- class Vehicle
- {
- private final void run()
- {
- System. out. println("Vehicle");
- }
- }
-
- class Car extends Vehicle
- {
- public static void main (String[] args)
- {
- new Car(). run();
- }
- private final void run()
- {
- System. out. println ("Car");
- }
- }
Car
父类方法有private修饰,所以对子类不可见,子类不能覆盖。所以子类方法和父类是两个方法。
如果父类方法将private改为public 会报错,因为父类final不允许继承。
A 所有的Java异常和错误的基类都是java.lang.Exception, 包括java.lang.RuntimeException
B 通过try … catch … finally语句,finally中的语句部分无论发生什么异常都会得到执行
C java中所有的数据都是对象
D Java通过垃圾回收回收不再引用的变量,垃圾回收时对象的finallize方法一定会得到执行
E Java是跨平台的语言,无论通过哪个版本的Java编写的程序都能在所有的Java运行平台中运行
F Java通过synchronized进行访问的同步,synchronized作用非静态成员方法和静态成员方法上同步的目标是不同的
B F
A:Java中所有错误和异常的父类是java.lang.Throwable
B:基本数据类型不是对象,不能用new的方法获取,但是每个基本数据类型都对应着封装类型,这些封装类型为了解决基本数据类型面向对象用的。
C:Java垃圾回收器负责回收无用对象占据的内存资源,但对象没有使用new获取了一块特殊区域,这块特殊区域的回收使用finallize()
D:Java跨平台是因为有JVM的存在,Java的三个版本的运行需要各自不同的环境。
A 类可以实现多个接口,接口可以继承(或扩展)多个接口
B 类可以实现多个接口,接口不能继承(或扩展)多个接口
C 类和接口都可以实现多个接口
D 类和接口都不可以实现多个接口
A
A native
B NULL
C false
D this
A D
这个关键字常见的坑:
true、false、null都不是关键字 ,而是常量,
goto、const、是保留的关键字
Java的所有关键字:
- abstract continue for new
- switch default if package
- synchronized do goto private
- this break double implements
- protected throw byte else
- import public throws case
- enum instanceof return transient
- catch extends int short
- try char final interface
- static void class finally
- long strictfp volatile const
- float native super while
- boolean assert
A 通过子类对父类方法的覆盖实现多态
B 利用重载来实现多态.即在同一个类中定义多个同名的不同方法来实现多态。
C 利用覆盖来实现多态.即在同一个类中定义多个同名的不同方法来实现多态。
D 通过子类对父类方法的重载实现多态
AB
Java通过方法重写和方法重载实现多态
方法重写是指子类重写了父类的同名方法
方法重载是指在同一个类中,方法的名字相同,但是参数列表不同
- try {
- FileOutputStream fos = new FileOutputStream("afile.txt");
- DataOutputStream dos = new DataOutputStream(fos);
- dos.writeInt(3);
- dos.writeChar(1);
- dos.close();
- fos.close();
- } catch (IOException e) {}
6
FileOutputStream是字节流。
java采用的uincode编码,两个字节表示一个字符,因此 char型在java中占两个字节,而int型占四个字节,故总共占四个字节。
- class HelloA {
- public HelloA() {
- System.out.println("A init");
- }
-
- {
- System.out.println("I’m A class");
- }
-
- static {
- System.out.println("static A");
- }
- }
-
- class HelloB extends HelloA {
- static {
- System.out.println("static B");
- }
-
- public HelloB() {
- System.out.println("B init");
- }
-
- {
- System.out.println("I’m B class");
- }
-
- public static void main(String[] args) {
- new HelloB();
- }
- }
static A
static B
I’m A class
A init
I’m B class
B init
执行顺序如下:
A 0
B 1
C 2
D 0.5
D
不同类型运算时以高精度的为准。
向上转型:byte-short-int-long-float-double
转化为:float(1.0)/float(2.0)=0.5
- StringBuffer s1=new StringBuffer(10);
- s1.append("1234");
- s1.capacity();
- System.out.println(s1.length());
- System.out.println(s1.capacity());
4 10
length 返回当前长度
如果字符串长度没有初始化长度大,capacity返回初始化的长度
如果append后的字符串长度超过初始化长度,capacity返回增长后的长度
假如 :
StringBuffer s1=new StringBuffer(1);
则输出:
44
StringBuffer 第一次扩容是2倍+2,如果扩充后的容量还是不够,则直接扩充到需要的容量大小。
- System.out.println((-3)%2);
- System.out.println(4%3);
- System.out.println((-3)%(-2));
- System.out.println(4%(-3));
- System.out.println((-12) % (-5));
输出:
- -1
- 1
- -1
- 1
- -2
(-3)%2 = -1 余 -1
(-12) % (-5) = 2余 -2
- class A {
- }
-
- class B extends A {
- }
-
- class C extends A {
- }
-
- class D extends B {
- }
-
-
- public class InstanceofTest {
-
- public static void main(String[] args) {
- A obj = new D();
-
- System.out.println(obj instanceof B);
-
- System.out.println(obj instanceof C);
-
- System.out.println(obj instanceof D);
-
- System.out.println(obj instanceof A);
-
- }
- }
输出:
- true
- false
- true
- true
instance是java的二元运算符,用来判断他左边的对象是否为右面类(接口,抽象类,父类)的实例。
A obj = new D(),obj的实际类型为D。
结构如下:
A
| |
B C
|
D
A 所有的Java异常和错误的基类都是java.lang.Exception, 包括java.lang.RuntimeException
B 通过try … catch … finally语句,finally中的语句部分无论发生什么异常都会得到执行
C java中所有的数据都是对象
D Java通过垃圾回收回收不再引用的变量,垃圾回收时对象的finallize方法一定会得到执行
E Java是跨平台的语言,无论通过哪个版本的Java编写的程序都能在所有的Java运行平台中运行
F Java通过synchronized进行访问的同步,synchronized作用非静态成员方法和静态成员方法上同步的目标是不同的
B F
A、java异常和错误的基类是Throwable,包括Exception和Error
B、try…catch…finally finally不管什么异常都会执行
C、java是面向对象的,但是不是所有的都是对象,基本数据类型就不是对象,所以才会有封装类的;
D、垃圾回收器并不总是工作,只有当内存资源告急时,垃圾回收器才会工作;即使垃圾回收器工作,finalize方法也不一定得到执行,这是由于程序中的其他线程的优先级远远高于执行finalize()函数线程的优先级。
E、JAVA跨平台性 实现在任意平台(不是任意版本)的java程序都可以在其他平台运行
F、synchronized实现方式有多种,修饰静态方法和非静态方法是不一样的。
A private
B protected
C final
D abstract
D
接口默认是 public abstract修饰
- public class methodover
- {
- public void setVar(int a, int b, float c) {
-
- }
- }
A private void setVar(int a, float c, int b){}
B protected void setVar(int e, int d, float f){}
C public int setVar(int a, float c, int b){return a;}
D public int setVar(int a, float c){return a;}
A C D
重载是在同一个类中,有多个方法名相同,参数列表不同(参数个数不同,参数类型不同),与方法的返回值无关,与权限修饰符无关。
- System.out.println("is "+ 100 + 5);
- System.out.println(100 + 5 +" is");
- System.out.println("is "+ (100 + 5));
-
- is 1005
- 105 is
- is 105
1."is"说明后面的内容都会被强制转换为string,is 100再和 5 拼接。
2.100+5先得到105,然后与is拼接
3.先算括号内的
int 和 String 用 “+” 拼接,自动强制转换为string。
A java中的集合类(如Vector)可以用来存储任何类型的对象,且大小可以自动调整。但需要事先知道所存储对象的类型,才能正常使用。
B 在java中,我们可以用违例(Exception)来抛出一些并非错误的消息,但这样比直接从函数返回一个结果要更大的系统开销。
C java接口包含函数声明和变量声明。
D java中,子类不可以访问父类的私有成员和受保护的成员。
B
vector默认就Object类型,不需要事先知道对象类型
接口的变量是final,准确的说叫常量,不是变量。
子类可以访问父类受保护(protected)的成员,不能访问的是privated。
- byte b = 127;
- int sum = 200;
- b += 1;
- sum += b;
- System.out.println(sum);
72
java中byte只有1个字节,8位,所以它的范围是 -128~127
会发生溢出, 对127加一发生溢出, 0111 1111 --> 1000 0000, 1000 0000为补码-128, 所以结果为200-128=72
- public void test() {
- int a = 10;
- System.out.println(a++ + a--);
- }
A 19
B 20
C 21
D 22
C
a++ 先把10赋值给a 再+1 所以左边是10 但此时a=11。
右边a -- 也是先赋值 此时右边赋值了,这里a=11,再 -1。10+11=2
最后a的值是10。
如果:
- int b = 1;
- System.out.println(b++ + b);
- System.out.println(b);
输出
3
2
b++ + b
左边值是 1 ,b赋值是2;右边 b是2,值也是2 ,所以是3。
- byte b1=1,b2=2,b3,b6;
- final byte b4=4,b5=6;
- b6=b4+b5;
- b3=(b1+b2);
- System.out.println(b3+b6);
A 输出结果:13
B 语句:b6=b4+b5编译出错
C 语句:b3=b1+b2编译出错
D 运行期抛出异常
C
所有的byte,short,char型的值将被提升为int型,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。
声明为final的变量会被JVM优化,第三行相当于b6=10,第6行相当于 b6 = 10
A 数组是一个对象,不同类型的数组具有不同的类
B 数组长度是可以动态调整的
C 数组是一个连续的存储结构
D 一个固定长度的数组可类似这样定义: int array[100]
E 两个数组用equals方法比较时,会逐个便利遍历其中的元素,对每个元素进行比较
F 可以二维数组,且可以有多维数组,都是在Java中合法的
A C F
数组的长度是固定的,不能动态调整。
一个固定长度的数组 初始化 int[] array =new int[100]
两个数组equals,比较的是是否同一个对象。
A short
B int
C double
D float
C
java中,你如果 没有在数字后面声明,浮点数默认为double。
要注意是(short)10/10.2*2,而不是(short) (10/10.2 *2),前者只是把10强转为short,又由于式子中存在浮点数,所以会对结果值进行一个自动类型的提升,浮点数默认为double,所以答案是double;后者是把计算完之后值强转short。
A 2japro
B &Class
C const
D _123
D
const是关键字
Java 标识符有如下命名规则:
$
组成 $
开头。- class Two{
- Byte x;
- }
- class PassO{
- public static void main(String[] args){
- PassO p=new PassO();
- p.start();
- }
- void start(){
- Two t=new Two();
- System.out.print(t.x+””);
- Two t2=fix(t);
- System.out.print(t.x+” ” +t2.x);
- }
- Two fix(Two tt){
- tt.x=42;
- return tt;
- }
- }
-
- null 42 42
1.注意第二行代码,Byte x;Byte是包装类,不是byte(基本数据类型),因此Byte的默认是null,不是0
2.t是一个引用地址类型,在调用fit(Two tt)函数是,是一个实参到形参的传值,也就是把t的地址赋值给了tt,但是都是指向堆内存中新建的对象,因此当对tt.x和t.x指向是相同的。因此t.x也是42
3.Two t2=fit(t);fit函数返回的还是一个引用地址,这句代码相当于把t(函数里面返回的是tt)的地址赋值给了t2,因此t2.x也是42
- switch(x)
- {
- default:
- System.out.println("Hello");
- }
A long
B char
C float
D byte
E double
F Object
B D
在Java7之前,switch只能支持 byte、short、char、int或者其对应的封装类以及Enum类型。
在Java7中,支持了String、Enum 类型
- String str = "12,3";
- String str2 = "123";
- System.out.print(str.split(",").length);
- System.out.print(str2.split(",").length);
2 1
split 这个方法默认返回一个数组,
如果 找到分隔符, 会把整个字符串当成字符串数组,即 { "12","3" }
如果没有找到分隔符, 会把整个字符串当成一个长度为1的字符串数组 , 即 { "123" }
- class testTryCatch {
- public static void main(String[] args) {
- System.out.println(test2());
- }
-
- public static int test2() {
- int b = 20;
- try {
- System.out.println("try block");
- return b;
- } catch (Exception e) {
- b = 50;
- System.out.println("catch block");
- } finally {
- b = 100;
- System.out.println("finally block");
- }
- return b;
- }
- }
try block
finally block
20
A JAVA程序的main方法必须写在类里面
B JAVA程序中可以有多个名字为main方法
C JAVA程序中类名必须与文件名一样
D JAVA程序的main方法中,如果只有一条语句,可以不用{}(大括号)括起来
A B
C: JAVA程序中public修饰的类名必须与文件名一样
D: JAVA程序的main方法中,不管有多少条语句都必须用{}(大括号)括起来
A 对
B 错
A
Java中一切都是对象,Object是所有类的根类,而且自动数据类型会自动装箱。
- class Base{
- public Base(String s){
- System.out.print("B");
- }
- }
- public class Derived extends Base{
- public Derived (String s) {
- System.out.print("D");
- }
- public static void main(String[] args){
- new Derived("C");
- }
- }
A BD
B DB
C C
D 编译错误
D
在调用子类构造器之前,会先调用父类构造器,当子类构造器中没有使用"super(参数或无参数)"指定调用父类构造器时,是默认调用父类的无参构造器,如果父类中包含有参构造器,却没有无参构造器,则在子类构造器中一定要使用“super(参数)”指定调用父类的有参构造器,不然就会报错。
- public class Test {
- private String name = "abc";
- public static void main(String[] args) {
- Test test = new Test();
- Test testB = new Test();
- String result = test.equals(testB) + ",";
- result += test.name.equals(testB.name) + ",";
- result += test.name == testB.name;
- System.out.println(result);
- }
- }
false,true,true
test.equals(testB)是比较内存地址,显然不一样。
test.name和testB.name指向的都是常量池的"abc"
- A dst=String.fromBytes(src,"GBK").getBytes("UTF-8")
- B dst=new String(src,"GBK").getBytes("UTF-8")
- C dst=new String("GBK",src).getBytes()
- D dst=String.encode(String.decode(src,"GBK")),"UTF-8" )
答案:B
操作步骤就是先解码再编码
用new String(src,"GBK")解码得到字符串
用getBytes("UTF-8")得到UTF8编码字节数组
A abstract不能与final并列修饰同一个类
B abstract 类中不建议有private的成员
C abstract 方法必须在abstract类或接口中
D static方法中能直接处理非static的属性
D
A、abstract修饰的类,不可实例化,所以需要子类去继承,然后重写其中的抽象方法。但是final修饰类是不可继承的。两者属性相冲。
B、看清楚,人家说的是不建议有,不是不能有。
C、抽象类中可以没有抽象方法,但是抽象方法必须在抽象类中或者接口中
D、static不可以修饰非static的属性,因为类加载的时候,static属性比非static先初始化,那么一个存在的总不能访问一个没有存在的吧。
A 类
B 函数
C 变量
D 数据
A
java的基本编程单元是类,基本存储单元是变量。
A abstract final class HI{}
B abstract private move(){}
C protected private number;
D public abstract class Car{}
D
A选项,final是最终类,不能被继承;abstrct类是抽象类,只能被继承,两者冲突。
B选项,private修饰符定义的属性及方法不能被子类实现,而抽象类的子类必须实现所有的抽象方法。两者冲突。 C选项,修饰符重复,而且没有定义数据类型。
A LinkedHashSet
B TreeSet
C HashSet
D AbstractSet
B
注意,不是有序是排序。
TreeSet 使用二叉树的原理对新 add()的对象按照指定的顺序排序(升序、降序),每增加一个对象都会进行排序,将对象插入的二叉树指定的位置。
A ArrayList和LinkedList均实现了List接口
B ArrayList访问速度比LinkedList快
C 随机添加和删除元素时,ArrayList的表现更加快速
D HashMap实现Map接口,它允许任何类型的键和值对象,并允许将NULL用作键或值
A B D
A LinkedeList和ArrayList都实现了List接口
B ArrayList是可改变大小的数组,而LinkedList是双向链接串列
C LinkedList不支持高效的随机元素访问
D 在LinkedList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在ArrayList的中间插入或删除一个元素的开销是固定的
D
D这个说法说反了。
- nums.add(6);
- nums.add(0,4);
- nums.remove(1);
A [5, 3, 1, 6]
B [4, 3, 1, 6]
C [4, 3, 6]
D [5, 3, 6]
B
list{5,3,1}
nums.add(6); //往后边加一个6,{5,3,1,6}
nums.add(0,4);//往下标为0的数加一个4,其他元素后移 {4,5,3,1,6}
nums.remove(1); // 移除下标为1 的元素,{4,3,1,6}
List、Set 是,Map 不是。
List、Set 是add操作,Map是put的k-v操作。
A HashSet 它是线程安全的,不允许存储相同的对象
B ConcurrentHashMap 它是线程安全的,其中存储的键对象可以重复,值对象不能重复
C Collection接口是List接口和Set接口的父接口,通常情况下不被直接使用
D ArrayList线程安全的,允许存放重复对象
A B D
线程安全(Thread-safe)的集合对象:
Vector 线程安全:
HashTable 线程安全:
StringBuffer 线程安全:
非线程安全的集合对象:
ArrayList :
LinkedList:
HashMap:
HashSet:
TreeMap:
TreeSet:
StringBulider
HashSet和ArrayList一样线程不安全,ConcurrentHashMap、HashMap 键不能重复,值可以重复
A java.util.ConcurrentHashMap
B java.util.Map
C java.util.TreeMap
D java.util.SortMap
E java.util.Hashtable
F java.util.HashMap
A E
A ArrayList和LinkedList均实现了List接口
B ArrayList的访问速度比LinkedList快
C 添加和删除元素时,ArrayList的表现更佳
D HashMap实现Map接口,它允许任何类型的键和值对象,并允许将null用作键或值
A B D
ArrayList插入和现有项的删除开销很大,除非在末端,但是随机访问速度快。LinkedList插入和删除开销很小。
- public class Test{
- public static void main(String [] args){
- List list=new ArrayList();
- list.add("a");
- list.add("b");
- list.add("a");
- Set set=new HashSet();
- set.add("a");
- set.add("b");
- set.add("a");
- System.out.println(list.size()+","+set.size());
- }
- }
3,2
list有序可重复,set无序不可重复
A ArrayList和LinkedList均实现了List接口
B ArrayList的访问速度比LinkedList快
C 添加和删除元素时,ArrayList的表现更佳
D HashMap实现Map接口,它允许任何类型的键和值对象,并允许将null用作键或值
A B D
ArrayList插入和现有项的删除开销很大,除非在末端,但是随机访问速度快。LinkedList插入和删除开销很小。
- public class Test {
- private synchronized void a() {
- }
- private void b() {
- synchronized (this) {
- }
- }
- private synchronized static void c() {
- }
- private void d() {
- synchronized (Test.class) {
- }
- }
- }
A 同一个对象,分别调用方法a和b,锁住的是同一个对象
B 同一个对象,分别调用方法a和c,锁住的是同一个对象
C 同一个对象,分别调用方法b和c,锁住的不是同一个对象
D 同一个对象,分别调用方法a、b、c,锁住的不是同一个对象
A C D
修饰非静态方法 锁的是this 对象
修饰静态方法 锁的是class对象
A volatile,synchronized 都可以修改变量,方法以及代码块
B volatile,synchronized 在多线程中都会存在阻塞问题
C volatile能保证数据的可见性,但不能完全保证数据的原子性,synchronized即保证了数据的可见性也保证了原子性
D volatile解决的是变量在多个线程之间的可见性、原子性,而sychroized解决的是多个线程之间访问资源的同步性
C
volatile只能修改变量,synchronized可以修饰方法,以及代码块
多线程访问volatile不会发生阻塞,而synchronized会出现阻塞
volatile能保证数据的可见性,但不能保证原子性
关键字volatile解决的下变量在多线程之间的可见性;而synchronized解决的是多线程之间资源同步问题
———<>
A 原子性
B 有序性
C 可见性
D 持久性
B C
synchronized 保证三大性,原子性,有序性,可见性,
volatile 保证有序性,可见性,不能保证原子性。
A 解决多线程中的对同一变量的访问冲突的一种技术
B TLS会为每一个线程维护一个和该线程绑定的变量的副本
C 每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了
D Java平台的java.lang.ThreadLocal是TLS技术的一种实现
A B D
ThreadLocal只是为每个线程处理自己的状态而引入的一个机制,不是用来解决每个线程共享变量的问题。
- public class Bground extends Thread{
- public static void main(String argv[]){
- Bground b = new Bground();
- b.run();
- }
- public void start(){
- for(int i=0;i<10;i++){
- System.out.println("Value of i = "+i);
- }
- }
- }
A 编译错误,指明run方法没有定义
B 运行错误,run方法没有定义
C 编译通过并输出0到9
D 编译通过,但无输出
D
对于线程而言,start是让线程从new变成runnable。run方法才是执行体的入口。
但是在Thread中,run方法是个空方法,没有具体实现。
Bground继承了Thread,但是没有重写run方法,那么调用run方法肯定是无输出。
A InterruptedException异常被捕获
B 线程调用了wait方法
C 当前线程创建了一个新的线程
D 高优先级线程进入就绪状态
A B
A选项正确,Java中一般通过interrupt方法中断线程
B选项正确,线程使用了wait方法,会强行打断当前操作,进入阻塞(暂停)状态,然后需要notify方法或notifyAll方法才能进入就绪状态
C选项错误,新创建的线程不会抢占时间片,只有等当前线程把时间片用完,其他线程才有资格拿到时间片去执行。
D选项错误,调度算法未必是剥夺式的,而准备就绪但是还没有获得CPU,它的权限更高只能说明它获得CPU被执行的几率更大而已
A ++x
B x=y
C x++
D x=1
D
前三个不是原子操作,最后一个直接赋值,为原子操作。
A sleep()
B wait()
C join()
D yield()
BC
1.sleep会使当前线程睡眠指定时间,不释放锁
2.yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁
3.wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态
4.当前线程调用 某线程.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait,释放锁
A 多进程里,子进程可获得父进程的所有堆和栈的数据;而线程会与同进程的其他线程共享数据,拥有自己的栈空间。
B 线程因为有自己的独立栈空间且共享数据,所有执行的开销相对较大,同时不利于资源管理和保护。
C 线程的通信速度更快,切换更快,因为他们在同一地址空间内。
D 一个线程可以属于多个进程。
A C
1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(通常说的主线程)。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。线程之间共享进程获得的数据资源,所以开销小,但不利于资源的管理和保护;而进程执行开销大,但是能够很好的进行资源管理和保护。
3、 子进程的所有资源都继承父进程,得到父进程资源的副本,子进程可获得父进程的所有堆和栈的数据,但二者并不共享地址空间。但线程拥有属于自己的一小部分资源,就是栈空间,保存其运行状态和局部自动变量的。
- public static void main(String[]args)throws Exception {
- final Object obj = new Object();
- Thread t1 = new Thread() {
- public void run() {
- synchronized (obj) {
- try {
- obj.wait();
- System.out.println("Thread 1 wake up.");
- } catch (InterruptedException e) {
- }
- }
- }
- };
- t1.start();
- Thread.sleep(1000);//确保线程1先运行
- Thread t2 = new Thread() {
- public void run() {
- synchronized (obj) {
- obj.notifyAll();
- System.out.println("Thread 2 sent notify.");
- }
- }
- };
- t2.start();
- }
A Thread 1 wake up
Thread 2 sent notify.
B Thread 2 sent notify.
Thread 1 wake up
C A、B皆有可能
D 程序无输出卡死
B
notify()、notifyAll() 调用后,并不是马上就释放对象锁的。所以t2先执行完了,然后释放了obj的锁,t1才能执行。
- static String str0="0123456789";
- static String str1="0123456789";
- String str2=str1.substring(5);
- String str3=new String(str2);
- String str4=new String(str3.toCharArray());
- str0=null;
15
str0和str1 在常量池。
str2,substring实际是new,5字符
str3和str4也都是new,每个5字符
以上三个分别都会创建新的对象,存放在堆。
常量池是PermGen的。(永久代:存储的是final常量,static变量,常量池。)
经过fullgc之后,年老区的内存回收,则年轻区的占了15个,不算PermGen,因此一共15字符
- package NowCoder;
- class Test {
- public static void hello() {
- System.out.println("hello");
- }
- }
- public class MyApplication {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Test test=null;
- test.hello();
- }
- }
A 能编译通过,并正确运行
B 因为使用了未初始化的变量,所以不能编译通过
C 以错误的方式访问了静态方法
D 能编译通过,但因变量为null,不能正常运行
A
静态方法属于静态绑定,编译器根据引用类型所属的静态类型为它绑定其对应的方法。此语句会翻译成invokestatic,该指令的调用中不会涉及this,所以不会依赖对象! 还有引用类型=null,其实就是指该引用在堆中没有对应的对象,但是编译的时候还是能根据声明找到其所属的静态类型。
A 程序计算器
B 方法区
C java虚拟机栈
D java堆
BD
私有:java虚拟机栈,程序计数器,本地方法栈
共享:java堆,方法区
A Stacks
B PC寄存器
C Heap
D Heap Frame
D
pc寄存器 就是 程序计数器
java只有栈帧 没有堆帧
- -Xms1G
- -Xmx2G
- -Xmn500M
- -XX:MaxPermSize=64M
- -XX:+UseConcMarkSweepGC
- -XX:SurvivorRatio=3
请问eden区最终分配的大小是多少?
A 64M
B 500M
C 300M
D 100M
C
java -Xmx2G -Xms1G -Xmn500M -Xss128k
-Xmx2G:设置JVM最大可用内存为2G。
-Xms1G:设置JVM促使内存为1G。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn500M:设置年轻代大小为2G。整个JVM内存大小= 年轻代大小 + 年老代大小 + 持久代大小。
-XX:SurvivorRatio=3:新生代中又会划分为 Eden 区,from Survivor、to Survivor 区。
其中 Eden 和 Survivor 区的比例默认是 8:1:1,当然也支持参数调整 -XX:SurvivorRatio=3的话就是3:1:1。
故该题为500*(3/5)=300M
A java.lang.OutOfMemoryError: PermGen space
增加-XX:MaxPermSize这个参数的值的话,这个问题通常会得到解决。
B java.lang.OutOfMemoryError: Requested array size exceeds VM limit
当你正准备创建一个超过虚拟机允许的大小的数组时,这条错误将会出现
C java.lang.OutOfMemoryError: Java heap space
一般情况下解决这个问题最快的方法就是通过-Xmx参数来增加堆的大小
D java.lang.OutOfMemoryError: nativeGetNewTLA
这个异常只有在jRockit虚拟机时才会碰到
A B C
A:运行时常量池导致的溢出
PermGen space 即永久代,Java8中移到了元数据区,XX:MaxPermSize 可以增大永久代空间。
B:属于堆空间不足导致的错误,属于数组过长导致堆内存溢出,加大堆内存或者减少数组长度。和C一样。
C:堆内存不足,直接增大堆内存。
D:java.lang.OutOfMemoryError: nativeGetNewTLA指当虚拟机不能分配新的线程本地空间(Thread Local Area)的时候错误信息,此错误是线程申请一个新的TLA时产生的,这个异常一般只会发生在jRockit虚拟机,但是只有过于绝对。
A 给对象赋予了空值null,以下再没有调用过
B 对象重新分配了内存空间
C 给对象赋予了空值null
D 给对象赋予了新值
A B D
在java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个:
1.给对象赋值为null,以下没有调用过。
2.给对象赋了新的值,重新分配了内存空间。
A 栈空间满
B 年轻代空间满
C 老年代满
D 持久代满
E System.gc()
C D E
Full GC触发机制:
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、survivor space1(From Space)区向survivor space2(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
- class A {
- private String a = "aa";
- public boolean methodB() {
- String b = "bb";
- final String c = "cc";
- }
- }
堆区、栈区、栈区
堆区:只存放类对象,线程共享;
方法区:又叫静态存储区,存储JVM加载的类信息、常量、静态变量,即使编译器编译后的代码等数据,线程共享;
栈区:存放方法局部变量,基本类型变量区、执行环境上下文、操作指令区,线程不共享;
a在堆区,但是aa在常量池。bb、cc 也在常量池。
A 默认情况下,Java应用启动过程涉及三个ClassLoader: Boostrap, Extension, System
B 一般的情况不同ClassLoader装载的类是不相同的,但接口类例外,对于同一接口所有类装载器装载所获得的类是相同的
C 类装载器需要保证类装载过程的线程安全
D ClassLoader的loadClass在装载一个类时,如果该类不存在它将返回null
E ClassLoader的父子结构中,默认装载采用了父优先
F 所有ClassLoader装载的类都来自CLASSPATH环境指定的路径
BDF
A、java中类的加载有5个过程,加载、验证、准备、解析、初始化;这便是类加载的5个过程,而类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机提供了3种类加载器,引导(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器)。A正确
B、一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例。所以B前面部分是正确的,后面接口的部分真的没有尝试过,等一个大佬的讲解吧;
C、类加载器是肯定要保证线程安全的;C正确
D、装载一个不存在的类的时候,因为采用的双亲加载模式,所以强制加载会直接报错,D错误
E、双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,所以默认是父装载,E正确
F、自定义类加载器实现 继承ClassLoader后重写了findClass方法加载指定路径上的class,F错误
- public class Base
- {
- private String baseName = "base";
- public Base()
- {
- callName();
- }
-
- public void callName()
- {
- System.out.println(baseName);
- }
-
- static class Sub extends Base
- {
- private String baseName = "sub";
- public void callName()
- {
- System.out.println (baseName) ;
- }
- }
- public static void main(String[] args)
- {
- Base b = new Sub();
- }
- }
A null
B sub
C base
A
这不是内部类的原因,这是类加载的顺序问题
类加载顺序:
父类的静态代码块>子类的静态代码块>父类的代码块>父类的构造方法>子类的代码块>子类的构造方法
因为 父类的构造方法 > 子类的代码块 ,所以子类还没有代码块 private String baseName = "sub";
baseName还没初始化,默认为null,如果是int则为0(baseName已经分配了空间,但是还没有值)
同样类型的题目:
有:
- class StaticStuff {
- static int x = 10;
-
- static {
- x += 5;
- }
-
- public static void main(String args[]) {
- System.out.println("x = " + StaticStuff.x);
- }
-
- static {
- x /= 3;
- }
- }
输出结果 x = 5
有:
- class X {
- Y y = new Y();
-
- public X() {
- System.out.print("X");
- }
- }
-
- class Y {
- public Y() {
- System.out.print("Y");
- }
- }
-
- class Z extends X {
- Y y = new Y();
-
- public Z() {
- System.out.print("Z");
- }
-
- public static void main(String[] args) {
- new Z();
- }
- }
输出结果:YXYZ
lz三个月刷完,整理不易,对你有帮助,希望点个赞噢~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。