牛客面试题记录JAVA

有一个源代码,只包含import java.util.* ; 这一个import语句,下面叙述正确的是?   ( )

能访问java/util目录下的所有类,不能访问java/util子目录下的所有类

解析:导入java.util.*不能读取其子目录的类,因为如果java.util里面有个a类,java.util.regex里面也有个a类,我们若是要调用a类的方法或属性时,应该使用哪个a类呢。避免类名混淆,也是使用包的原因。


关于下面的程序Test.java说法正确的是(    )。

1

2

3

4

5

6

7

8

public class Test {

    static String x="1";

    static int y=1;

    public static void main(String args[]) {

        static int z=2;

        System.out.println(x+y+z);

    }

}

程序有编译错误

解析:被static修饰的变量称为静态变量(类变量),类变量属于整个类,只能定义在类中方法外。而局部变量属于方法,只在该方法内有效,所以static不能修饰局部变量。


在创建派生类对象,构造函数的执行顺序:

基类构造函数,派生类对象成员构造函数,派生类本身的构造函数

解析:父类静态域——》子类静态域——》父类成员初始化——》父类构造块——》父类构造方法——》子类成员初始化——》子类构造块——》子类构造方法;


下列有关Thread的描述,哪个是正确的?

将一个线程标记成daemon线程,意味着当主线程结束,并且没有其它正在运行的非daemon线程时,该daemon线程也会自动结束。

解析:

1.启动一个线程的方法是 start()

2.结束线程用的是interrupt()方法,而stop()是强制结束线程,并不推荐使用,同时stop()方法已被弃用

3.daemon线程是守护线程,当主线程结束时,守护线程会自动结束

4.一个线程等待另外一个线程的方法是wait()方法


关于 JAVA 堆栈

解析:

Java把内存分成两种,一种叫做栈内存,一种叫做堆内存。

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。

堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。

引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候(比如先前的引用变量x=null时),才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因。

   总结起来就是对象存储在堆内存,引用变量存储在栈内存。栈内存指向堆内存。


代码片段: 

1

2

3

4

5

byte b1=1,b2=2,b3,b6; 

final byte b4=4,b5=6

b6=b4+b5; 

b3=(b1+b2); 

System.out.println(b3+b6);

关于上面代码片段叙述正确的是()

语句:b3=b1+b2编译出错

解析:没有final修饰的变量相加后会被自动提升为int型,与目标类型byte不相容,需要强制转换(向下转型)。

表达式的数据类型自动提升, 关于类型的自动提升,注意下面的规则。

①所有的byte,short,char型的值将被提升为int型;

②如果有一个操作数是long型,计算结果是long型;

③如果有一个操作数是float型,计算结果是float型;

④如果有一个操作数是double型,计算结果是double型;

而声明为final的变量会被JVM优化,第3行相当于 b6 = 10


 

下面代码的输出是什么?

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

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();

    }

}

解析:

1.首先,需要明白类的加载顺序

(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)

(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )

(3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )

(4) 父类构造函数

(5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )

(6) 子类构造函数

其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)

2.其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。

Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。

当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。

由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。

 new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。

创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null

 


若所用变量都已正确定义,以下选项中,非法的表达式是()

’a’ = 1/3

解析:'a'是个常数,不能赋值。当字符型与整型运算时会自动转换成整型。a的ASCII码为97


以下是java concurrent包下的4个类,选出差别最大的一个c

A、Semaphore:类,控制某个资源可被同时访问的个数;

B、ReentrantLock:类,具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大;

C、 Future:接口,表示异步计算的结果;

D、 CountDownLatch: 类,可以用来在一个线程中等待多个线程完成任务的类。


java接口的方法修饰符可以为?(忽略内部接口)

abstract

解析:1、抽象类中的抽象方法(其前有abstract修饰)不能用private、static、synchronized、native访问修饰符修饰。原因如下:抽象方法没有方法体,是用来被继承的,所以不能用private修饰;static修饰的方法可以通过类名来访问该方法(即该方法的方法体),抽象方法用static修饰没有意义;使用synchronized关键字是为该方法加一个锁。。而如果该关键字修饰的方法是static方法。则使用的锁就是class变量的锁。如果是修饰 类方法。则用this变量锁。但是抽象类不能实例化对象,因为该方法不是在该抽象类中实现的。是在其子类实现的。所以。锁应该归其子类所有。所以。抽象方 法也就不能用synchronized关键字修饰了;native,这个东西本身就和abstract冲突,他们都是方法的声明,只是一个吧方法实现移交给子类,另一个是移交给本地操作系统。如果同时出现,就相当于即把实现移交给子类,又把实现移交给本地操作系统,那到底谁来实现具体方法呢? 

2、接口是一种特殊的抽象类,接口中的方法全部是抽象方法(但其前的abstract可以省略),所以抽象类中的抽象方法不能用的访问修饰符这里也不能用。而且protected访问修饰符也不能使用,因为接口可以让所有的类去 实现(非继承) ,不只是其子类,但是要用public去修饰。接口可以去继承一个已有的接口。 

考察点:抽象类和接口

相同点:都不能被实例化,位于继承树的顶端,都包含抽象方法

不同点:1、设计目的:接口体现的一种规范,类似与整个系统的总纲,制订了系统各模块应该遵循的标准,因此接口不应该经常改变,一旦改变对整个系统是辐射性的。

               抽象类作为多个子类的共同父类,体现的是一种模板式设计,可以当作系统实现过程中的中间产品,已经实现了系统部分功能。

            2、使用不同:(1)接口只能包含抽象方法,抽象类可以包含普通方法。

                                   (2)接口里不能定义静态方法,抽象类可以。

                                   (3)接口只能定义静态常量属性不能定义普通属性,抽象类可以。

                                   (4)接口不包含构造器,抽象类可以(不是用于创建对象而是让子类完成初始化)。

                                   (5)接口里不能包含初始化块,抽象类完全可以。

                                   (6)接口多继承,抽象类但继承(只能有一个直接父类)。

总结:接口所有方法全是抽象方法只能 public abstract修饰 (默认public abstract修饰 ),属性默认public static final修饰。

             抽象类除了包含抽象方法外与普通类无区别。 


关于构造方法:

A:静态成员变量或静态代码块>main方法>非静态成员变量或非静态代码块>构造方法

B:think in java中提到构造器本身并没有任何返回值。

C: 构造方法的主要作用是完成对类的对象的初始化工作。

D: 一般在创建(new)新对象时,系统会自动调用构造方法。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孟林洁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值