【JAVA秒会技术之秒杀面试官】JavaSE常见面试题(二)

  1. 云栖社区>
  2. 博客>
  3. 正文

【JAVA秒会技术之秒杀面试官】JavaSE常见面试题(二)

java隋七哥 2018-08-21 16:31:00 浏览437
展开阅读全文

21.在Java中,如何跳出当前的多重嵌套循环?

答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环。(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)

22.构造器(constructor)是否可被重写(override)? 

答:构造器不能被继承,因此不能被重写,但可以被重载。

23.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:

(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;

(2)如果两个对象的hashCode相同,它们并不一定相同。

当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

补充:关于equals和hashCode方法,很多Java程序都知道,但很多人也就是仅仅知道而已,在Joshua Bloch的大作《Effective Java》(很多软件公司,《Effective Java》、《Java编程思想》以及《重构:改善既有代码质量》是Java程序员必看书籍,如果你还没看过,那就赶紧去亚马逊买一本吧)中是这样介绍equals方法的:首先equals方法必须满足自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(当x和y引用的对象信息没有被修改时,多次调用x.equals(y)应该得到同样的返回值),而且对于任何非null值的引用x,x.equals(null)必须返回false。实现高质量的equals方法的诀窍包括:1.使用==操作符检查"参数是否为这个对象的引用";2.使用instanceof操作符检查"参数是否为正确的类型";3.对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;4.编写完equals方法后,问自己它是否满足对称性、传递性、一致性;5.重写equals时总是要重写hashCode;6.不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@Override注解。

24.是否可以继承String类? 

答:String 类是final类,不可以被继承。

补充:继承String本身就是一个错误的行为,对String类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)。

25.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

答:是值传递。Java语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。C++和C#中可以通过传引用或传输出参数来改变传入的参数的值。在C#中可以编写如下所示的代码,但是在Java中却做不到。

namespace CS01 {

    class Program {

        public static void swap(ref int x, ref int y) {

            int temp = x;

            x = y;

            y = temp;

        }

        public static void Main (string[] args) {

            int a = 5, b = 10;

            swap (ref a, ref b);

            // a = 10, b = 5;

            Console.WriteLine ("a = {0}, b = {1}", a, b);

        }

    }

}

说明:Java中没有传引用实在是非常的不方便,这一点在Java 8中仍然没有得到改进,正是如此在Java编写的代码中才会出现大量的Wrapper类(将需要通过方法调用修改的引用置于一个Wrapper类中,再将Wrapper对象传入方法),这样的做法只会让代码变得臃肿,尤其是让从C和C++转型为Java程序员的开发者无法容忍。

26.String和StringBuilder、StringBuffer的区别?

答:(1)String和StringBuffer、StringBuider:

        ①String:是不可变字符序列;

    ②StringBuffer、StringBuider:是可变字符序列;

③String覆盖了equals方法和hashCode方法,而StringBuffer没有覆盖equals方法和hashCode方法,所以,将StringBuffer对象存储进Java集合类中时会出现问题。

   (2)StringBuffer和StringBuider:

     ①StringBuffer:是JDK1.0版本的,线程安全,效率低;

    ②StringBuilder:是JDK1.5版本的,线程不安全,效率高;

③如果一个字符串变量是在方法里面定义,这种情况只可能有一个线程访问它,不存在不安全的因素了,则用StringBuilder。如果要在类里面定义成员变量,并且这个类的实例对象会在多线程环境下使用,那么最好用StringBuffer。

27.描述一下JVM加载class文件的原理机制? 

答:JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。

由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。

类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。从Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM不会向Java程序提供对Bootstrap的引用。下面是关于几个类加载器的说明:

Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);

Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;

System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中记载类,是用户自定义加载器的默认父加载器。

28.抽象类(abstract class)和接口(interface)有什么异同? 

答:(1)成员特点:

①构造方法:接口没有;抽象类有;

②成员变量:接口中只有常量;抽象类中常量、变量都可;

③成员方法:接口只有抽象方法;抽象类中抽象方法、非抽象方法都可;

(2)关系特点:

①类与类:只有单继承,但可以多层继承;

②类与接口:实现关系,可以单实现,也可以多实现;

③接口与接口:继承关系,可以单继承,也可以多继承;

(3)设计理念:

①接口是简单工厂设计模式,like a的关系 ,接口中定义的是该继承体系的扩展功能;

③抽象类是模板设计模式,is a的关系,抽象类中定义的是继承体系的共性功能;

29.Java中会存在内存泄漏吗,请简单描述?

答:理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

30.抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰? 

答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

31.是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用? 

答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

32.GC是什么?为什么要有GC? 

答:GC是垃圾收集的意思,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,从而有效的防止内存泄露。要请求垃圾收集,可以调用下面的方法之一:System.gc()或Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。

33.String st = null和 String st =“ ”的区别?String s = new String("xyz")创建了几个对象? 

答:(1)String st = null表示声明了一个String对象的引用str,但是没有为其分配存内存空间。

(2)String st =“ ”表示创建了一个长度等于0的空字符串,并在内存中分配了内存空间。

(3)String st = new String(“xyz”);表示创建了两个对象:

         ①堆内存中一个new String;

         ②常量池中一个字符串。

34.接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)? 

答:接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。

35.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 

答:可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和回调。

36.内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 

答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

37.final、finally和finalized的区别? 

答:(1)final:被final修饰的类,不被能继承;被final修饰的方法,不能被重写;被fianl修饰的量,为常量,只能被赋值一次;

   (2)finally:异常处理,和try、catch结合使用,可加可不加,用于执行一些必须执行的代码,如释放资源等;

   (3)finalized:Object类中的方法,其中定义了对象要被垃圾回收器回收之前,要做的一些清理工作。

38.数据类型之间的转换?

答:(1)如何将字符串转换为基本数据类型?

调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;

   (2)如何将基本数据类型转换为字符串?

一种方法是将基本数据类型与空字符串("")连接(+)即可获得其所对应的字符串;另一种方法是调用String类中的valueOf()方法返回相应字符串

39.如何实现字符串的反转及替换? 

答:方法很多,可以自己写实现也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:

    public static String reverse(String originStr) {

        if(originStr == null || originStr.length() <= 1)

            return originStr;

        return reverse(originStr.substring(1)) + originStr.charAt(0);

    }

40.怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串? 

答:代码如下所示:

String s1 = "你好";

String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");

需要免费Java架构学习资料视频请加扣扣群:835544715 群内提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导

网友评论

登录后评论
0/500
评论
java隋七哥
+ 关注