java基础面试题

1.  增强for循环原理是迭代器,而迭代器是专门用来遍历集合的,但数组不是集合,为什么增强for循环可以遍历数组?


     通过反编译可以知道: 使用增强for循环遍历数组,会解析成一般for循环,但遍历集合时,会解析为迭代器

2.   \\ 和 / 表示的路径有什么区别?

 兼容性问题
        \\ 是window独有的
        / 在任何操作系统下都识别  建议使用 /

3.对象的瘦身问题:

     transient:专门针对对象的瘦身,表不需要序列化的对象可以省略属性的序列化,减少字节序列的生成

4.通过反射修改String的值

@Test
public void homeWork() throws Exception{
    String str = "helloWorld";
    Class<String> cls = String.class;
    Field value = cls.getDeclaredField("value");
    value.setAccessible(true);
    value.set(str,new char[]{'1','2','3'});
    System.out.println(str);
}

4.在jdk1.5之后,下列 java 程序输出结果为__true true____。

1

2

3

4

int i=0;

Integer j = new Integer(0);

System.out.println(i==j);

System.out.println(j.equals(i));

这是个自动装箱和拆箱的问题 

当进行 i==j 比较时,这是基本数据类型与包装类数据类型的比较 ,使用'=='运算符时,包装类数据类会自动拆箱成基本数据类型 integer会拆箱成int进行比较,这时数值一样 则返回true

当使用equals方法时(只有包装类能调用equals方法,基本数据类型不行),基本数据类型会自动

装箱成包装类,i会装箱成integer与j比较,数值一样,则返回true

5.在Java中,对于不再使用的内存资源,如调用完成的方法,“垃圾回收器”会自动将其释放。

方法调用时,会创建栈帧在栈中,调用完是程序自动出栈释放,而不是(垃圾回收器)gc释放

JVM 内存可简单分为三个区:

1、堆区(heap):用于存放所有对象,是线程共享的(注:数组也属于对象)

2、栈区(stack):用于存放基本数据类型的数据和对象的引用,是线程私有的(分为:虚拟机栈和本地方法栈)

3、方法区(method):用于存放类信息、常量、静态变量、编译后的字节码等,是线程共享的(也被称为非堆,即 None-Heap)

Java 的垃圾回收器(GC)主要针对堆区

6.关于运行时常量池,下列哪个说法是正确的(B,C,D)

A.运行时常量池大小受栈区大小的影响
B.运行时常量池大小受方法区大小的影响
C.存放了编译时期生成的各种字面量
D.存放编译时期生成的符号引用
注:
运行时常量池:是每一个类或接口的常量池的运行时表示形式.

具体体现就是在Java编译后生成的.class文件中,会有class常量池,也就是静态的运行时常量池;

存储位置:运行时常量池一直是方法区的一部分,所以大小受方法区大小影响

运行时常量池存放内容:存放编译期生成的各种字面量和符号引用;

字面量:就是指这个量本身,比如字面量3,也就是指3.string类型的字面量"ABC", 这个"ABC" 通过字来描述, 所以就是字面量

符号引用;符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,包含在字节码文件的常量池中,它主要包括:在该类中,出现过的各类包,类,接口,字段,方法等元素的全限定名

7.以下有关构造方法的说法,正确的是:(A)

A 一个类的构造方法可以有多个

B 构造方法在类定义时被调用

C 构造方法只能由对象中的其他方法调用

D构造方法可以和类同名,也可以和类名不同

注:

A选项是函数重载的体现,一个类可以有多个参数列表不同的构造方法。A选项正确。

B选项,构造方法在对象被初始化时调用。B选项错误。

C选项,构造方法只能在对象被初始化时调用,不能由其他方法调用。

D选项,构造方法必须与类名相同。

8.类 ABC 定义如下:

 public  class  ABC{

 public  double  max( double  a, double  b) {   }

 }

将以下哪个方法插入行 3 是不合法的。(B)

A public  float  max(float  a, float  b, float  c){ return a }

B public  double  max (double  c,  double  d){ return c }

C public  float  max(float  a,  float  b){ return a }

D private  int  max(int a, int b, int c){return a  }

注:本体考查的是方法的重载,B中只改变了参数名,但没有改变参数类型或者参数数量,不是方法的重载所以错误

重载要求:在同一个类中,有两个或两个以上的方法,

1、方法名一致;

2、形参列表不一致,即:形参个数不一致 或 形参类型不一致 或 不同类型的形参的顺序不一致(其中有一项不一样即可),并且与形参变量名是否相同无关;

3、方法返回值类型可以一样,也可以不一样

9.以下哪项不属于java类加载过程?(B)

A 生成java.lang.Class对象

B int类型对象成员变量赋予默认值

C 执行static块代码

D 类方法解析

注:

类的加载包括:加载,验证,准备,解析,初始化。

选项A:生成java.lang.Class对象是在加载时进行的。生成Class对象作为方法区这个类的各种数据的访问入口。

选项B:既然是对象成员,那么肯定在实例化对象后才有。在类加载的时候会赋予初值的是类变量,而非对象成员。

选项C:这个会调用。可以用反射试验。

选项D:类方法解析发生在解析过程。

10.设int x=1,float y=2,则表达式x/y的值是:(D)

A 0

B 1

C 2

D 以上都不是

注:

不同类型运算时以高精度的为准。转化与运算关系byte-short-int-long-float-double,float=1转化为float=1.0,int/float相比先转化为同一类型即float(1.0)/float(2.0)=0.5

11.对于文件的描述正确的是( D)

A 文本文件是以“.txt”为后缀名的文件,其他后缀名的文件是二进制文件。

B File类是Java中对文件进行读写操作的基本类。

C 无论文本文件还是二进制文件,读到文件末尾都会抛出EOFException异常。

D Java中对于文本文件和二进制文件,都可以当作二进制文件进行操作。

注:

A.文件分为文本文件和二进制文件,计算机只认识二进制,所以实际上都是二进制的不同解释方式。文本文件是以不同编码格式显示的字符,例如Ascii、Unicode等,window中文本文件的后缀名有".txt",".log",各种编程语言的源码文件等;二进制文件就是用文本文档打开是看不懂乱码,只要能用文本打开的文件都可以算是文本文件,只是显示的结果不是你想要的,二进制文件只有用特殊的应用才能读懂的文件,例如".png",".bmp"等,计算机中大部分的文件还是二进制文件。

B.File类是对文件整体或者文件属性操作的类,例如创建文件、删除文件、查看文件是否存在等功能,不能操作文件内容;文件内容是用IO流操作的。

C.当输入过程中意外到达文件或流的末尾时,抛出EOFException异常,正常情况下读取到文件末尾时,返回一个特殊值表示文件读取完成,例如read()返回-1表示文件读取完成。

D.上面A选项已经说了,不论是文本文件还是二进制文件,在计算机中都是以二进制形式存储的,所以都当做二进制文件读取。

12.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

class Base

{

    public void method()

    {

        System.out.println("Base");

    

}

class Son extends Base

{

    public void method()

    {

        System.out.println("Son");

    }

     

    public void methodB()

    {

        System.out.println("SonB");

    }

}

public class Test01

{

    public static void main(String[] args)

    {

        Base base = new Son();

        base.method();

        base.methodB();

    }

}

问这个程序的输出结果。(D)

A Base SonB

B Son SonB

C Base Son SonB

D 编译不通过

注:

Base base=new Son(); 是多态的表示形式。父类对象调用了子类创建了Son对象。

base调用的method()方法就是调用了子类重写的method()方法。

而此时base还是属于Base对象,base调用methodB()时Base对象里没有这个方法,所以编译不通过。

要想调用的话需要先通过SON son=(SON)base;强制转换,然后用son.methodB()调用就可以了

13.jdk1.8中,下面有关java 抽象类和接口的区别,说法错误的是?(BD)

A 抽象类可以有构造方法,接口中不能有构造方法

B 抽象类中可以包含非抽象的普通方法,接口中的方法必须是抽象的,不能有非抽象的普通方法

C 一个类可以实现多个接口,但只能继承一个抽象类

D 接口中可以有普通成员变量,抽象类中没有普通成员变量

注:

抽象类

1.抽象类中可以构造方法

2.抽象类中可以存在普通属性,方法,静态属性和方法。

3.抽象类中可以存在抽象方法。

4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。

5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。

接口

1.在接口中只有方法的声明,没有方法体。

2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上

public static final 

3.在接口中的方法,永远都被public来修饰。

4.接口中没有构造方法,也不能实例化接口的对象。

5.接口可以实现多继承

6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法

7.则实现类定义为抽象类。

14.以下哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址( AB )

A String a = "hello"; String b = "hello";

B Integer a; Integer b = a;

C int a = 1; Integer b = new Integer(1);

D int a = 1; Integer b = 1;

注: 

内存引用地址是指栈中存放的地址,来指向堆中的某个位置

基本数据类型的数据直接存放在栈中,不存在引用地址

A中a和b同时指向常量池中的相同元素,内存引用地址相同

B声明相同类型的a直接赋值给b,两者相同

C和D中int是基本类型,没有引用地址

15.在Java中,HashMap中是用哪些方法来解决哈希冲突的?(C)

A 开放地址法

B 二次哈希法

C 链地址法

D 建立一个公共溢出区

16.在你面前有一个n阶的楼梯,你一步只能上1阶或2阶。请问,当N=11时,你可以采用多少种不同的方式爬完这个楼梯(144),当N=9时呢呢(55)

这是一个递归问题 f(n) = f(n-1) + f(n-2)   斐波那契公式

代码如下


public class TestFloor {
 
    public static void main(String[] args) {
        System.out.println("当N=11时:"+ladder(11) +" "+"当N=9时:"+ ladder(9));
    }
 
    private static int ladder(int n) {
        if(n==1) {
            return 1;
        }else if(n==2) {
            return 2;
        }else {
            return ladder(n-1) + ladder(n-2);
        }
    }
}

17.以下关于 abstract 关键字的说法,正确的是(D)

A abstract 可以与final 并列修饰同一个类。

B abstract 类中不可以有private的成员。

C abstract 类中必须全部是abstract方法。

D abstract 方法必须在abstract类或接口中。

注:

1abstract类不能与final,static使用。final修饰方法,子类可以调用,但不能覆盖。

2最好不要有private因为私有和抽象放在一起,子类如果想重写父类的私有方法根本继承不过来,也就无法重写

3抽象类中可以有非抽象方法

4抽象类中可以都是非抽象的,但是抽象方法一定要在类和接口中

18.下面代码运行结果是? ABCDBDCB

public class Test
{
	static boolean foo(char c)
	{
		System.out.print(c);
		return true;
	}
	public static void main( String[] argv )
	{
		int i = 0;
		for ( foo('A'); foo('B') && (i < 2); foo('C'))
		{
			i++ ;
			foo('D');
		}
	}
}

for(条件1;条件2;条件3) {

    //语句

}

执行顺序是条件1->条件2->语句->条件3->条件2->语句->条件3->条件2........

如果条件2为true,则一直执行。如果条件2位false,则for循环结束

19.java语言的下面几种数组复制方法中,哪个效率最高?B

A for 循环逐一复制

B System.arraycopy

C Array.copyOf

D 使用clone方法

注:

(1)从速度上看:System.arraycopy > clone > Arrays.copyOf > for 
(2)for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。 
(3)查看Arrays.copyOf的源码可以发现,它其实本质上是调用了System.arraycopy。之所以时间差距比较大,是因为很大一部分开销全花在了Math.min函数上了

20.定义有StringBuffer s1=new StringBuffer(10);s1.append(“1234”),则s1.length()和s1.capacity()分别是多少?

length 返回当前长度

如果字符串长度没有初始化长度大,capacity返回初始化的长度

如果append后的字符串长度超过初始化长度,capacity返回增长后的长度

21.String s = new String("xyz");创建了几个StringObject?

在用new一个String对象时,jvm会先在常量池中检索是否有对应的字符串,如果有则不会再字符串常量池中创建直接拿取,如果没有,则会在字符串常量池中创建一个新字符串对象,然后还会去堆内存中创建一个字符串对象,把常量池中的字符串对象拷贝到内存中的字符串对象,然后返回堆内存中字符串对象的地址。

这道题,如果常量池有“xyz”,则只会创建new String("xyz")对象,如果没有则会创建"xyz"和new String("xyz")两个对象

22.以下哪些类是线程安全的(ade)

A Vector

B HashMap

C ArrayList

D StringBuffer

E Properties

注:

A,Vector相当于一个线程安全的List

B,HashMap是非线程安全的,其对应的线程安全类是HashTable

C,Arraylist是非线程安全的,其对应的线程安全类是Vector

D,StringBuffer是线程安全的,相当于一个线程安全的StringBuilder

E,Properties实现了Map接口是HashTable的一个子类,是线程安全的

23.@SuppressWarnings(“deprecation”)的功能是什么?A

A 屏蔽不赞同使用的类和方法的警告

B 屏蔽在强制类型转换的时候编译器给出的警告

C 关闭所有警告信息

D 当在可序列化的类上缺少serialVersionUID定义的警告

注:本题考察java3大注解

Java三大注解分别是@Override @Suppresswarnings@Deprecated 

1 @Override 表名子类中覆盖了超类中的某个方法,如果写错了覆盖形式,编译器会报错

2.@Deprecated 可以修饰类、方法、变量,在java源码中被@Deprecated修饰的类、方法、变量等表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等,如果现在使用,则在以后使用了这些类、方法的程序在更新新的JDK、jar包等就会出错,不再提供支持,在自己的程序中则表明不希望别人在以后使用这个类,方法,变量等等

3.@Suppresswarnings 达到抑制编译器产生警告的目的,但是不建议使用,因为后期编码人员看不懂编译器提示的警告,不能更好的选择更好的类去完成任务

24.线程安全的map在JDK 1.5及其更高版本环境 有哪几种方法可以实现?C D

A Map map = new HashMap()

B Map map = new TreeMap()

C Map map = new ConcurrentHashMap();

D Map map = Collections.synchronizedMap(new HashMap());

解析

1. HashMap,TreeMap 未进行同步考虑,是线程不安全的。

2. HashTable 和 ConcurrentHashMap 都是线程安全的。区别在于他们对加锁的范围不同,HashTable 对整张Hash表进行加锁,而ConcurrentHashMap将Hash表分为16桶(segment),每次只对需要的桶进行加锁。

3. Collections 类提供了synchronizedXxx()方法,可以将指定的集合包装成线程同步的集合。比如,

List  list = Collections.synchronizedList(new ArrayList());

Set  set = Collections.synchronizedSet(new HashSet());

25.下面有关 Java ThreadLocal 说法正确的有? A B C D

A ThreadLocal存放的值是线程封闭,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递

B 线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收

C 在Thread类中有一个Map,用于存储每一个线程的变量的副本。

D 对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式

解析:

ThreadLocal类用于创建一个线程本地变量
在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map,它的键是threadLocal,值就是变量的副本,ThreadLocal为每一个使用该变量的线程都提供了一个变量值的副本,每一个线程都可以独立地改变自己的副本,是线程隔离的。通过ThreadLocal的get()方法可以获取该线程变量的本地副本,在get方法之前要先set,否则就要重写initialValue()方法。
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

ThreadLocal的使用场景:

        数据库连接:在多线程中,如果使用懒汉式的单例模式创建Connection对象,由于该对象是共享的,那么必须要使用同步方法保证线程安全,这样当一个线程在连接数据库时,那么另外一个线程只能等待。这样就造成性能降低。如果改为哪里要连接数据库就来进行连接,那么就会频繁的对数据库进行连接,性能还是不高。这时使用ThreadLocal就可以既可以保证线程安全又可以让性能不会太低。但是ThreadLocal的缺点时占用了较多的空间。

26.已知int a[3][4];则下列能表示a[1][2]元素值的是(A)

A *(*(a+1)+2)

B *(a+1+2)

C (&a[0]+1)[2]

D *(a[0]+1)

解析:

在**数组中
*(a+0)=a[0]        第0行

*(a+1)=a[1]        第1行

*(a+2)=a[2]        第2行

*(a+n)=a[n]        第n行

*(*(a+0) + 0)=a[0][0] 第0行第0列

*(*(a+0) + 1)=a[0][1] 第0行第1列

*(*(a+1) + 0)=a[1][0] 第1行第0列

*(*(a+1) + 1)=a[1][1] 第1行第1列

...

*(*(a+n)+m)=a[n][m] 第n行第m列

==>

a[1][2] = *(*(a+1)+2)

27.对于线程局部存储TLS(thread local storage),以下表述正确的是A B D

A 解决多线程中的对同一变量的访问冲突的一种技术

B TLS会为每一个线程维护一个和该线程绑定的变量的副本

C 每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了
D Java平台的java.lang.ThreadLocal是TLS技术的一种实现

解析:

同一全局变量或者静态变量每个线程访问的是同一变量,多个线程同时访存同一全局变量或者静态变量时会导致冲突,尤其是多个线程同时需要修改这一变量时,通过TLS机制,为每一个使用该全局变量的线程都提供一个变量值的副本,每一个线程均可以独立地改变自己的副本,而不会和其它线程的副本冲突

  ThreadLocal可以给一个初始值,而每个线程都会获得这个初始化值的一个副本,这样才能保证不同的线程都有一份拷贝。ThreadLocal 不是用于解决共享变量的问题的,也不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制.

28.检查程序,是否存在问题,如果存在指出问题所在,如果不存在,说明输出结果。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

public class HelloB extends HelloA 

{

 public HelloB()

 {

 }

 {

     System.out.println("I’m B class");

 }

 static

 {

     System.out.println("static B");

 }

 public static void main(String[] args)

 {

     new HelloB();

 }

}

class HelloA

{

 public HelloA()

 {

 }

 {

     System.out.println("I’m A class");

 }

 static

 {

     System.out.println("static A");

 }

}

结果:

static A
static B
I’m A class
I’m B class

解析:

子由父生,执行顺序为:
父类的静态代码块>子类的静态代码块>父类的构造代码块>父类的构造函数>子类的构造代码块>子类的构造函数

 29.以下哪几种方式可用来实现线程间通知和唤醒:( A C )

A Object.wait/notify/notifyAll

B ReentrantLock.wait/notify/notifyAll

C Condition.await/signal/signalAll

D Thread.wait/notify/notifyAll

解析:

 在Java中,常用的线程通信方式有两种,分别是利用Monitor实现线程通信、利用Condition实现线程通信。线程同步是线程通信的前提,所以究竟采用哪种方式实现通信,取决于线程同步的方式。

如果是采用synchronized关键字进行同步,则需要依赖Monitor(同步监视器)实现线程通信,Monitor就是锁对象。在synchronized同步模式下,锁对象可以是任意的类型,所以通信方法自然就被定义在Object类中了,这些方法包括:wait()、notify()、notifyAll()。一个线程通过Monitor调用wait()时,它就会释放锁并在此等待。当其他线程通过Monitor调用notify()时,则会唤醒在此等待的一个线程。当其他线程通过Monitor调用notifyAll()时,则会唤醒在此等待的所有线程。

JDK 1.5新增了Lock接口及其实现类,提供了更为灵活的同步方式。如果是采用Lock对象进行同步,则需要依赖Condition实现线程通信,Condition对象是由Lock对象创建出来的,它依赖于Lock对象。Condition对象中定义的通信方法,与Object类中的通信方法类似,它包括await()、signal()、signalAll()。通过名字就能看出它们的含义了,当通过Condition调用await()时当前线程释放锁并等待,当通过Condition调用signal()时唤醒一个等待的线程,当通过Condition调用signalAll()时则唤醒所有等待的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cqq00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值