【面试】一篇文章帮你彻底清楚"java"必考面试题

简介: 【面试】一篇文章帮你彻底清楚"java"必考面试题

51. super.getClass()方法调用?下面程序的输出结果是多少?


importjava.util.Date;
        public classTestextendsDate {
            public static void main (String[]args){
                new Test().test();
            }
            public void test () {
                System.out.println(super.getClass().getName());
            }
        }

      很奇怪,结果是 Test这属于脑筋急转弯的题目,在一个 qq 群有个网友正好问过这个问题,我觉得挺有趣,就研 究了一下,没想到今天还被你面到了,哈哈。在 test 方法中,直接调用 getClass().getName()方法,返回的是 Test 类名 由于 getClass()在 Object 类中定义成了 final,子类不能覆盖该方法,所以,在 test 方法中调 用 getClass().getName()方法,其实就是在调用从父类继承的 getClass()方法,等效于调用 super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也应该是 Test。如果想得到父类的名称,应该用如下代码:getClass().getSuperClass().getName();

52. String 是最基本的数据类型吗?

    基本数据类型包括 byte、int、char、long、float、double、boolean 和 short。java.lang.String 类是 final 类型,因此不可继承这个类、不能修改这个类。为提高效率节省空 间,我们应用 StringBuffer 类。

53. Strings= "Hello";s=s+" world!";这两行代码执行后,原始的 String 对象中的内容 到底变了没有? 

没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。这段 代码中,s 原先指向一个 String 对象,内容是 "Hello",然后我们对 s 进行了+操作,那么 s 所指向那个对象是否发生了改变呢?答案是没有。这时,s 不指向原来那个对象,而指向了 另一个 String 对象,内容为"Helloworld!",原来那个对象还存在于内存中,只是 s 这个引用 变量不再指向它了。通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改, 或者说,不可预见的修改,那么使用 String 来代表字符串的话会引起很大的内存开销。因为 String 对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个 String 对象来 表示。这时,应该考虑使用 StringBuffer 类,它允许修改,而不是每个不同的字符串都要生 成一个新的对象。并且,这两种类的对象转换十分容易。同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都 new 一个 String。例如 我们要在构造器中对一个名叫 s 的 String 引用变量进行初始化,把它设置为初始值,应当这 样做:


public class Demo {
            private String s;
            public Demo() {
                s = "InitialValue";
            }
        }

     而非 s= newString("InitialValue");

     后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为 String 对象不可改变,所以对于内容相同的字符串,只要一个 String 对象来表示就可以了。也就说, 多次调用上面的构造器创建多个对象,他们的 String 类型属性 s 都指向同一个对象。

     上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java 认为它们代表 同一个 String 对象。而用关键字 new 调用构造器,总是会创建一个新的对象,无论内容是 否相同。

     至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变 类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不 同的状态都要一个对象来代表,可能会造成性能上的问题。所以 Java 标准类库还提供了一 个可变版本,即 StringBuffer。

54. 是否可以继承 String 类?

     String 类是 final 类故不可以继承.

55. Strings=newString("xyz");创建了几个 String Object? 二者之间有什么区别? 

两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多 少遍,都是缓冲区中的那一个。NewString 每写一遍,就创建一个新的对象,它一句那个常 量”xyz”对象的内容来创建出一个新 String 对象。如果以前就用过’xyz’,这句代表就不会创 建”xyz”自己了,直接从缓冲区拿。 

56. String 和 StringBuffer 的区别? 

JAVA 平台提供了两个类:String 和 StringBuffer,它们可以储存和操作字符串,即包含多个 字符的字符数据。这个 String 类提供了数值不可改变的字符串。而这个 StringBuffer 类提供 的字符串进行修改。当你知道字符数据要改变的时候你就可以使用 StringBuffer。典型地, 你可以使用 StringBuffers 来动态构造字符数据。另外,String 实现了 equals 方法,new String(“abc”).equals(newString(“abc”)的结果为 true,而 StringBuffer 没有实现 equals 方法,所 以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为 false。接着要举一个具 体的例子来说明,我们要把 1 到 100 的所有数字拼起来,组成一个串。 


StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < 100; i++) {
            sbf.append(i);
        }

上面的代码效率很高,因为只创建了一个 StringBuffer 对象,而下面的代码效率很低,因为 创建了 101 个对象。


String str = new String();
        for (inti = 0; i < 100; i++) {
            str = str + i;          
}

   在讲两者区别时,应把循环的次数搞成 10000,然后用 endTime-beginTime 来比较两者执行 的时间差异,最后还要讲讲 StringBuilder 与 StringBuffer 的区别。 

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

57. 如何把一段逗号分割的字符串转换成一个数组?

  如果不查 jdkapi,我很难写出来!我可以说说我的思路:用正则表达式,代码大概为:


String[] result=orgStr.split(",");

用StingTokenizer,代码为:


StringTokenizer tokener= StringTokenizer(orgStr,”,”);


String[] result = new String[tokener.countTokens()];
        Int i = 0;
        while (tokener.hasNext() {
            result[i++] = toker.nextToken();
        }

58. 数组有没有 length()这个方法?String 有没有 length()这个方法?

  数组没有 length()这个方法,有 length 的属性。String 有有 length()这个方法。

59. 下面这条语句一共创建了多少个对象:Strings="a"+"b"+"c"+"d"?

  答:对于如下代码: 


String s1= "a"; 
String s2= s1+"b"; 
String s3= "a"+"b";
System.out.println(s2== "ab"); 
System.out.println(s3== "ab");

     第一条语句打印的结果为 false,第二条语句打印的结果为 true,这说明 javac 编译可以对字 符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译 时去掉其中的加号,直接将其编译成一个这些常量相连的结果。 题目中的第一行代码被编译器在编译时优化后,相当于直接定义了一个”abcd”的字符串,所 以,上面的代码应该只创建了一个 String 对象。写如下两行代码,


Strings ="a"+"b"+ "c"+"d"; 
System.out.println(s== "abcd");

     最终打印的结果应该为 true。

60. try{}里有一 return 语句,那紧跟在这个 try 后的 finally {}里的 code 是否被执行,什 么时候被执行,在 return 前还是后?

     也许你的答案是在 return 之前,但往更细地说,我的答案是在 return 中间执行,请看下面程 序代码的运行结果:


public class Test {
            public static void main(String[] args) {
                System.out.println(new Test().test());
            }
            static int test() {
                int x = 1;
                try {
                    return x;
                } finally {
                    ++x;
                }
            }
        }

     运行结果是 1,为什么呢?主函数调用子函数并得到结果的过程,好比主函数准备一个空罐 子,当子函数要返回结果时,先把结果放在罐子里,然后再将程序逻辑返回到主函数。所谓 返回,就是子函数说,我不运行了,你主函数继续运行吧,这没什么结果可言,结果是在说 这话之前放进罐子里的。

61. 下面的程序代码输出的结果是多少? 


 public class smallT {
            public static void main(String args[]) {
                smallT t = new smallT();
                int b = t.get();
                System.out.println(b);
            }
            publicint get() {
                try {
                    return1;
                } finally {
                    return2;
                }
            }
        }

      返回的结果是 2。我可以通过下面一个例子程序来帮助我解释这个答案,从下面例子的运行结果中可以发现, try 中的 return 语句调用的函数先于 finally 中调用的函数执行,也就是说 return 语句先执行, finally 语句后执行,所以,返回的结果是 2。Return 并不是让函数马上返回,而是 return 语 句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行 finally 语 句后才真正返回。


public class Test {
            public static void main(String[] args) {
                System.out.println(new Test().test());
            }
            inttest() {
                try {
                    return func1();
                } finally {
                    return func2();
                }
            }
            int func1() {
                System.out.println("func1");
                return 1;
            }
            int func2() {
                System.out.println("func2");
                return 2;
            }
        }
-----------执行结果----------------
func1 
func2 
2

   结论:finally 中的代码比 return 和 break 语句后执行

62. final,finally,finalize 的区别。 

   final: 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 内部类要访问局部变量,局部变量必须定义成 final 类型,例如,一段代码…… finally:是异常处理语句结构的一部分,是异常的统一出口,表示总是执行。 finalize:是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法, 可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM 不保证此方法总 被调用.

63. 运行时异常与一般异常有何异同?

   异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能 遇到的异常,是一种常见运行错误。 java 编译器要求方法必须声明抛出可能发生的非运行时 异常,但是并不要求必须声明抛出未被捕获的运行时异常。 

64. error 和 exception 有什么区别?

   error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指 望程序能处理这样的情况。 exception 表示一种设计或实现问题。也就是说,它表示如果程 序运行正常,从不会发生的情况。 Error 表示有 JVM 进行处理的,是 JVM 出错. Exctption 是可以用程序进行处理的,使用 try…catch 进行处理.

65. Java 中的异常处理机制的简单原理和应用。 

  异常是指 java 程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很 相似,现实生活中的事件可以包含事件发生的时间、地点、人物、情节等信息,可以用一个 对象来表示, Java 使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封 装到一个对象来表示的,该对象中包含有异常的信息。

  Java 对异常进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable,Throwable 下面又派生了两个子类:Error 和 Exception,Error 表示应 用程序本身无法克服和恢复的一种严重问题,程序只有死的份了,例如,说内存溢出和线程 死锁等系统问题。Exception 表示程序还能够克服和恢复的问题,其中又分为系统异常和普 通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问 题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者 让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常 (NullPointerException)、类转换异常(ClassCastException);普通异常是运行环境的变化 或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样 的异常后,程序不应该死掉。

     java 为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须 try..catch 处 理或用 throws 声明继续抛给上层调用方法处理,所以普通异常也称为 checked 异常,而系统 异常可以处理也可以不处理,所以,编译器不强制用 try..catch 处理或用 throws 声明,所以 系统异常也称为 unchecked 异常。

    提示答题者:就按照三个级别去思考:虚拟机必须宕机的错误,程序可以死掉也可以不死掉 的错误,程序不应该死掉的错误;

66. 请写出你最常见到的 5 个 runtime exception。

   这道题主要考你的代码量到底多大,如果你长期写代码的,应该经常都看到过一些系统方面 的异常,你不一定真要回答出 5 个具体的系统异常,但你要能够说出什么是系统异常,以及 几个系统异常就可以了,当然,这些异常完全用其英文名称来写是最好的,如果实在写不出, 那就用中文吧,有总比没有强! 

   所 谓 系 统 异 常 , 就 是 ….. , 它 们 都 是 RuntimeException 的 子 类 , 在 jdk doc 中 查 RuntimeException 类,就可以看到其所有的子类列表,也就是看到了所有的系统异常。我比 较 有 印 象 的 系 统 异 常 有 : NullPointerException 、 ArrayIndexOutOfBoundsException 、 ClassCastException。

◆  

67. java 如何进行异常处理,throws,throw,try,catch,finally 代表什么意义?

   在 try 块中可 以抛出异常吗? Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。 在 Java 中,每个异常都是一个对象,它是 Throwable 类或其它子类的实例。当一个方法出 现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到 这个异常并进行处理。 Java 的异常处理是通过 5 个关键词来实现的: try、 catch、 throw、 throws 和 finally。一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throws)一 个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来 处理; 

       try 用来指定一块预防所有“异常”的程序; 

       catch 子句紧跟在 try 块后面,用来指定你想要捕捉的“异常”的类型; 

       throw 语句用来明确地抛出一个“异常”; 

       throws 用来标明一个成员函数可能抛出的各种“异常”; 

       finally 为确保一段代码不管发生什么“异常”都被执行一段代码; 

可以在一个成员函数调用的外面写一个 try 语句,在这个成员函数内部写另一个 try 语 句保护其他代码。每当遇到一个 try 语句,“异常”的框架就放到堆栈上面,直到所有的 try 语句都完成。如果下一级的 try 语句没有对某种“异常”进行处理,堆栈就会展开,直到遇 到有处理这种“异常”的 try 语句。

68. 在 java 中如何进行 socket 编程。

    答:Sockets 有两种主要的操作方式:面向连接的和无连接的。无连接的操作使用数据报协议.这个模式下的 socket 不需要连接一个目的的 socket,它只是简 单地投出数据报.无连接的操作是快速的和高效的,但是数据安全性不佳.面向连接的操作使 用TCP协议.一个这个模式下的socket必须在发送数据之前与目的地的socket取得一个连接. 一旦连接建立了,sockets 就可以使用一个流接口:打开-读-写-关闭.所有的发送的信息都会在另一端以同样的顺序被接收.面向连接的操作比无连接的操作效率更低,但是数据的安全性更 高.

    在服务器,使用 ServerSocket 监听指定的端口,端口可以随意指定(由于 1024 以下的端口 通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于 1024 的端口), 等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。在客户端,使用 Socket 对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话 完成后,关闭 Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个 1024 以上的端口。

目录
相关文章
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
14天前
|
存储 负载均衡 Java
Elasticsearch集群面试系列文章一
【9月更文挑战第9天】Elasticsearch(简称ES)是一种基于Lucene构建的分布式搜索和分析引擎,广泛用于全文搜索、结构化搜索、分析以及日志实时分析等场景。
62 7
|
2月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
2月前
|
缓存 Java
【IO面试题 一】、介绍一下Java中的IO流
Java中的IO流是对数据输入输出操作的抽象,分为输入流和输出流,字节流和字符流,节点流和处理流,提供了多种类支持不同数据源和操作,如文件流、数组流、管道流、字符串流、缓冲流、转换流、对象流、打印流、推回输入流和数据流等。
【IO面试题 一】、介绍一下Java中的IO流
|
2月前
|
Java 编译器 开发工具
JDK vs JRE:面试大揭秘,一文让你彻底解锁Java开发和运行的秘密!
【8月更文挑战第24天】JDK(Java Development Kit)与JRE(Java Runtime Environment)是Java环境中两个核心概念。JDK作为开发工具包,不仅包含JRE,还提供编译器等开发工具,支持Java程序的开发与编译;而JRE仅包含运行Java程序所需的组件如JVM和核心类库。一个简单的&quot;Hello, World!&quot;示例展示了两者用途:需借助JDK编译程序,再利用JRE或JDK中的运行环境执行。因此,开发者应基于实际需求选择安装JDK或JRE。
41 0
|
2月前
|
算法 Java
【多线程面试题十八】、说一说Java中乐观锁和悲观锁的区别
这篇文章讨论了Java中的乐观锁和悲观锁的区别,其中悲观锁假设最坏情况并在访问数据时上锁,如通过`synchronized`或`Lock`接口实现;而乐观锁则在更新数据时检查是否被其他线程修改,适用于多读场景,并常通过CAS操作实现,如Java并发包`java.util.concurrent`中的类。
|
2月前
|
存储 Java 调度
【多线程面试题 八】、说一说Java同步机制中的wait和notify
Java同步机制中的wait()、notify()、notifyAll()是Object类的方法,用于线程间的通信,其中wait()使当前线程释放锁并进入阻塞状态,notify()唤醒单个等待线程,notifyAll()唤醒所有等待线程。
|
2月前
|
存储 安全 Java
【多线程面试题 七】、 说一说Java多线程之间的通信方式
Java多线程之间的通信方式主要有:使用Object类的wait()、notify()、notifyAll()方法进行线程间协调;使用Lock接口的Condition的await()、signal()、signalAll()方法实现更灵活的线程间协作;以及使用BlockingQueue作为线程安全的队列来实现生产者和消费者模型的线程通信。
|
2月前
|
Java
【Java基础面试四十九】、 说一说Java的四种引用方式
这篇文章介绍了Java中的四种引用方式:强引用、软引用、弱引用和虚引用,它们在垃圾回收时的不同行为及其适用场景。
|
2月前
|
XML Java 数据库连接
【Java基础面试四十八】、 Java反射在实际项目中有哪些应用场景?
这篇文章探讨了Java反射机制在实际项目中的应用场景,包括JDBC数据库驱动加载、框架注解/XML配置实例化,以及面向切面编程(AOP)的代理类创建等。
下一篇
无影云桌面