java 面试问题

多线程,并发

  1. java中能否创建volatile数组

    可以,但是只是一个指向数组的引用,而不是整个数组。也就是如果改变引用指向的数据,将会受到volatile的保护,但是如果多个线程同时改变数组内的元素,就不能起到保护作用

  2. volatile能使得一个非原子操作变成原子操作吗

    如果在类中有一个long类型的成员变量,如果了解这个成员变量会被多个线程访问,最好是将其设置为volatile,因为在java中long类型变量的读取并非是原子的,需要分成两步,如果一个线程在修改这个long变量,的值,那么另一个线程有可能只看见了该数值的一半(前32位)但是对一个volatile类型的变量读写就会是原子的double也是一样的。

  3. volatile变量类型提供什么保证?

    volatile变量提供顺序和可见性保证,例如,jvm为了获得更好的性能会对语句重新排序,但是volatile类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。volatile提供memory-barrier,意思就是当正在写一个volatile域的时候,能够保证任何线程都能够看见你写的值。

  4. 十个线程和两个线程的同步代码块那个更容易写?

    从写代码的角度来说,两者的复杂度是相同的,因为同步代码和线程数量是相互独立的,但是同步策略的选择依赖于线程的数量,越多的线程意味着越多的竞争,所以需要利用同步技术,例如锁分离,要求更复杂的代码和专业知识

  5. 如何调用wait()?用if 还是while why?

    wait()应该在循环内被调用,因为当线程获取cpu开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检查条件是否会满足会更好

  6. 什么是Busy spin?为什么要使用它

    Busy spin 是一种不释放cpu的基础上等待事件的技术,它经常用于避免丢失CPU中的缓冲数据(如果线程先暂停,之后在其他cpu上运行就会消失) 所以如果工作要求低延迟,并且你的线程目前没有任何顺序,这样你就可以通过循环检测队列中的新消息来代替调用wait或者是sleep方法

  7. java如何获取一份线程中的dump文件?

    在linux下,通过kill -3 PID来获取java应用的dump文件,jvm会把dump文件打入标准输出或者是错误日志文件中

  8. 什么是线程局部变量?

    线程局部变量就是局限于线程内部的变量,属于线程自身所有,不在多个线程之间共享,java提供ThreadLocal类来支持局部线程,但是在web服务器环境下使用线程局部变量的时候要非常小心,这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成之后没有释放,java就存在内存泄漏的危险。

  9. java中的sleep和wait方法

    虽然两种都是用来暂停当前运行的线程,但是sleep()实际上只是短暂停顿,因为他不会释放锁,而wait是条件等待,这就是为什么该方法会释放锁,因为只有这样,其他等待的线程才能在满足条件的时候获取到该锁。

  10. immutable object ,能否创建一个包含可变对象的不可变对象?

    immutable object 一旦被创建,状态就不能被改变,任何的修改都只会创建一个新的对象,如String,Integer以及其他包装类。我们可以创建一个包含可变对象的不可变对象的,只要注意不要共享可变对象的引用就可以了,如果需要变化的话,就返回元对象的一个拷贝

数据类型和java基础

  1. java中应该使用什么数据类型来代表价格?

    如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的double类型。

  2. 在java中怎样将bytes转换成long.int…….类型

代码如下

public class Utilities{
    public static byte[] int2bytes(int num){
        byte[] byteNum = new byte[4];
        for(int ix = 0; ix < 4; ++ix){
            int offset = 32 - (ix + 1)*8;
            byteNum[ix] = (byte)((num >> offset) & 0xff);
        }
        return byteNum;
    }


    public static int bytes2Int(byte[] byteNum){
        int num = 0;
        for(int ix = 0;ix < 4;++ix){
            num<<=8;
            num |= (byteNum[ix] & 0xff);  
        }
        return num;
    }

    public static byte int2OneByte(int num){
        return (byte)(num & 0x000000ff);
    }

    public static int oneByte2Int(byte byteNum){
        //针对正数的int  
        return byteNum > 0 ? byteNum : (128 + (128 + byteNum)); 
    }

    public static byte[] long2Bytes(long num){
        byte[] byteNum = new byte[8];
        for(int ix = 0;ix < 8; ++x){
            int offset = 64 - (ix + 1)*8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff); 
        }
         return byteNum;  
    }

    public static long bytes2Long(byte[] byteNum) {  
            long num = 0;  
            for (int ix = 0; ix < 8; ++ix) {  
                    num <<= 8;  
                    num |= (byteNum[ix] & 0xff);  
            }  
            return num;  
    }  


}   

代码转自 http://blog.csdn.net/zgyulongfei/article/details/7738970

3.那个类包含clone方法?是Cloneable还是Object?

    java.lang.Cloneable是一个标识性接口,不包含任何方法,clone方法在object类中定义。并且需要知道clone()方法是一个本地方法,这意味着他是由c或者是c++或者是其他本地语言实现的

4.java 中++操作符是线程安全的吗?

不是线程安全的操作,它涉及到多个指令,如读取变量值,增加,然后储存回内存,这个过程有可能出现多个线程交叉。

5. a = a+b 与 a+=b的区别

+=隐式的将+操作的结果类型强制转换为持有结果的类型。如果两个类型相加,如byte,short,int首先会将它们提升到int类型,然后再执行加法操作,则a+b会出现编译错误,但是a += b 就没有问题,如下
   byte a = 127;
   byte b = 127;
   b = a+b;//error cannot convert from int to byte
   b += a; //ok

6.能否在不进行强制转换的情况下将一个double赋值给long类型的变量?

不行,不能因为double类型的范围比long类型的范围更广,必须要进行强制转换。

7.3*0.1 == 0.3将会返回什么》true还是false

false ,因为有些浮点数不能完全精确的表示出来。

8. 能在switch使用String吗?

从java7开始,可以在case上写字符串,但是系统内部是通过String的hashcode来记录的,其实还是数字类型

jvm底层与GC

  1. 64位jvm中,int的长度是多少?

    java中 int类型的变量长度是固定值,与平台无关,都是32 位
    
  2. Serial 和 Parallel GC之前的不同?

    Serial 与 Parallel在 GC执行的时候都会引起 stop-the-word 他们之前主要的不同是serial收集器是默认的复制收集器,执行GC的时候只有一个线程,Parallel收集器使用多个GC线程来执行
    
  3. WeakHashMap是怎么工作的?

    WeakHashMap的工作与正常的Hashmap类似,但是使用弱引用作为key 意思就是当key对象没有任何引用的时候 key/value将会被回收
    
  4. JVM选项,-XX +UseCompressedOops有什么作用,为什么要用

    当你将你的应用从32位jvm迁移到64位jvm的时候,由于对象的指针由32位增加到了64位,因此堆内存会突然增加,差不多要翻倍,这也会对cpu缓存(容量比内存小很多)的数据产生不利的影响,因为,迁移到64位的jvm主要动机可能在于可以制定最大堆内存的大小,通过压缩OOP可以节省一定的内存。
    
  5. JRE,JDK,JVM,JIT之间有什么不同

    JRE(Java run-time) 是运行java引用所必须的,JDK代表 java开发工具(Java Development kit) JVM(Java Virtual Machine)用来运行java应用。JIT(Just in time Compilation)当代码执行的次数超过一定的阈值的时候,会将java字节码转换为本地代码,这样会大幅的提高java应用的性能。 
    
  6. 如何获取 Java程序使用的内存,堆使用的百分比?

    可以通过 Java.lang.Runtime类中与内存相关的方法来获取剩余的内存,总内存以及最大堆内存。通过这些方法也可以获取到堆使用的百分比以及堆内存的剩余空间。Runtime.freememory() 方法返回剩余空间的字节数,Runtime.totalMemory返回总内存的字节数,Runtime.maxMemory()返回最大内存的字节数。
    
  7. Java中的编译期常量是什么,使用有什么风险?

    公共静态不可变(public static final) 变量也就是我们所说的编译期常量,这里的public是可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行的时候不会改变,这种方式存在一个问题,是你使用了一个内部的或者是第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然使用老值,甚至已经部署了一个新的jar,为了避免这种情况,当你在更新依赖Jar文件的时候,确保重新编译你的程序。
    

集合框架相关

  1. List Set Map 的区别

    List是一个有序集合,允许元素重复。它的某些实现可以提供基于下标值的常量访问.但是这个并不是list接口实现的。要注意这点。Set是一个无序不可重复集合。Map中,可以将key序列 value序列单独的抽取出来,使用keySet()抽取key序列,将map中的所有keys生成一个Set。使用values()抽取value序列,将map中的所有values生成一个Collection。至于为什么一个key一个Collection,因为key是独一无二的,而value允许重复。
    扩展:Collection没有get方法来取得特定的某个元素,只能通过literator遍历,Set和Collection拥有一模一样的接口
    
  2. poll()方法和remove()方法的区别?

    poll()和remove()都是从队列中取出一个元素,但是poll()方法在获取元素失败的时候会返回空,但是remove()失败的时候会抛出异常
    
  3. Java中LinkedHashMap和PriorityQueue的区别是什么?

    PriorityQueue保证最高或者是最低优先级的元素总是在队列头部,但是LinkedhashMap维持的顺序是元素的插入顺序,当遍历一个priorityQueue的时候,没有任何的顺序保证,但是LinkedHashMap可以保证顺序
    
  4. 用那两种方式来实现集合的排序?

    可以使用有序集合,如TreeSet或者是TreeMap也可以通过list然后使用Collections.sort()来排序。
    
  5. Java中如何打印数组?

    可以使用Arrays.toString()和Arrays.deepToString()方法来打印数组
    
  6. Java LinkedList是双向链表,Java中的TreeMap是采用红黑树来实现的

  7. Java中的HashSet内部是如何工作的?

    HashSet内部是采用HashMap来实现,由于Map需要Key和Value,所以所有key都要有一个默认的value,而且hashSet不允许有重复的key只允许有一个null key 这点也和hashMap一致
    
  8. 我们能够自己写一个容器类,然后使用for-each循环吗?

    可以,可以写一个自己的容器类,如果你想使用java中的增强for循环来遍历,只需要实现iterable接口,如果实现Collection接口,默认就具有该属性。
    
  9. ArrayList和HashMap的默认大小。

    Java7中,ArrayList的默认大小是10,hashmap默认大小是16
    
private static final int DEFAULT_CAPACITY = 10;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

10.两个不相等的对象可能有相同的hashcode,但是两个相同的对象一定具有相同的hashcode。

11.我们能在hashCode()中使用随机数字吗?

不行,因为相同对象的hashcode()值必须是相同的,参见重写java hashcode()代码

Java IO和NIO的面试题

1.在java程序中,有三个Socket,那么需要多少个线程来处理?

    这里有一个问题,基本上一个Socket至少要一个线程来处理,但是也可以用多个线程来处理一个Socket,所以至少需要三个线程。

2.Java中怎么创建ByteBuffer

ByteBuffer allocate(int capacity) //创建一个指定capacity的ByteBuffer。
ByteBuffer allocateDirect(int capacity) //创建一个direct的ByteBuffer
ByteBuffer wrap(byte [] array)
ByteBuffer wrap(byte [] array, int offset, int length) //把一个byte数组或byte数组的一部分包装成ByteBuffer。

3.Java中怎么读写ByteBuffer

//从socket中读取
int bytesReaded=socketChannel.read(buffer);

//写入Socket
socketChannel.write(buffer);

//文件信道写入
FileChannel fc = new FileInputStream().getChannel();  
fc.write(buff);
fc.close();

//文件信道读取
FileChannel fc =  new FileOutputStream().getChannel();
fc.read( buff);
fc.flip();

4.java采用的是大端还是小端

    大端:就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
    小端:就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
    java貌似将大小端给隐蔽了,所以我们在编程的时候没有注意到这点。

5.ByteBuffer中的字节序是什么?

public class JVMEndianTest {
public static void main(String[] args) {
                int x = 0x01020304;
                ByteBuffer bb = ByteBuffer.wrap(new byte[4]);
                bb.asIntBuffer().put(x);
                String ss_before = Arrays.toString(bb.array());
                System.out.println("默认字节序 " + bb.order().toString() + "," + " 内存数据 " + ss_before);
                bb.order(ByteOrder.LITTLE_ENDIAN);
                bb.asIntBuffer().put(x);
                String ss_after = Arrays.toString(bb.array());
                System.out.println("修改字节序 " +  bb.order().toString() + "," + " 内存数据 " + ss_after);
    }
}

默认字节序 BIG_ENDIAN, 内存数据 [1, 2, 3, 4]
修改字节序 LITTLE_ENDIAN, 内存数据 [4, 3, 2, 1]

9.ByteBuffer与String转换

public static Charset charset = Charset.forName("UTF-8");
public static CharsetEncoder encoder = charset.newEncoder();
public static CharsetDecoder decoder = charset.newDecoder();

public static ByteBuffer str_to_bb(String msg){
  try{
    return encoder.encode(CharBuffer.wrap(msg));
  }catch(Exception e){e.printStackTrace();}
  return null;
}

public static String bb_to_str(ByteBuffer buffer){
  String data = "";
  try{
    int old_position = buffer.position();
    data = decoder.decode(buffer).toString();
    // reset buffer's position to its original so it is not altered:
    buffer.position(old_position);  
  }catch (Exception e){
    e.printStackTrace();
    return "";
  }
  return data;
}

上述代码转自:http://stackoverflow.com/questions/1252468/java-converting-string-to-and-from-bytebuffer-and-associated-problems

Java中的最佳实践

  1. Java中编写多线程程序的时候你会遵循那些最佳实践?

    • 给线程命名,这样可以帮助调试
    • 最小化同步的范围,而不是将整个方法进行同步.只对关键部分进行同步。
    • 如果可以,更倾向与使用volatile而不是synchronized\
    • 使用更高层次的开发工具,而不是使用wait和notify来实现线程间的通信。如BlockingQueue,CountDownLatch,以及Semeaphore
    • 优先使用并发集合而不是对集合进行同步
  2. 说出几点Java中使用Collections的最佳实践

    • 使用正确的集合类,比如,如果不需要同步列表,使用ArrayList而不是Vector
    • 优先使用并发集合,而不是对集合进行同步
    • 使用接口代表访问集合,如使用List代表ArrayList。Map存储代表HashMap
    • 使用迭代器来循环集合
    • 使用集合的时候使用泛型
  3. IO的最佳实践

    • 使用有缓冲区的IO类而不要单独的读取字节或者是字符
    • 看情况使用NIO和AIO
    • 在finally块中关闭流或者使用try-with-resource语句
    • 使用内存映射文件获取更快的io
  4. JDBC最佳实践

    • 使用批量的操作来插入和更新数据
    • 使用PreparedStatement避免异常,并且提高性能
    • 使用数据库连接池
    • 通过列名来获取结果集不要使用列的下标来获取
  5. Java中方法重载的最佳实践
    主要是为了避免造成自动装箱的混乱

    • 不要重载这样的方法,一个方法接收int参数,而另一个方法接收Integer参数
    • 不要重载参数数量一致。而只是参数顺序不同的方法
    • 如果重载的参数多于五个 采用可变参数

Date,Time 以及 Calendar

1.在多线程的环境下,SimpleDateFormat是线程安全的吗?

不是,DateFormat的所有实现都不是线程安全的,因此不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如将SimpleDateFormat限制在ThreadLocal中,如果不这么做,在解析或者格式化日期的时候,可能获取到一个不正确的结构,因此从日期,时间处理的所有实践来说,推荐 joda-time 库
  1. Java中如何格式化一个日期 如格式化ddMMyyyy的形式?
  2. Java中,怎么在格式化的日期中显示时区
  3. java中怎么计算两个日期之间的差距
  4. Java中如何将字符串YYYYMMDD转化为日期

下面是利用joda-time库进行日期格式化的方法,可以解决上述问题

public static void main(String[] args) {  
        //初始化时间  
                DateTime dateTime=new DateTime(2012, 12, 13, 18, 23,55);  

                // 年,月,日,时,分,秒,毫秒    
                DateTime dt3 = new DateTime(2011, 2, 13, 10, 30, 50, 333);// 2010年2月13日10点30分50秒333毫秒  

                //下面就是按照一点的格式输出时间  
                String str2 = dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa");  
                String str3 = dateTime.toString("dd-MM-yyyy HH:mm:ss");  
                String str4 = dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa");  
                String str5 = dateTime.toString("MM/dd/yyyy HH:mm ZZZZ");  
                String str6 = dateTime.toString("MM/dd/yyyy HH:mm Z");  

                DateTimeFormatter format = DateTimeFormat .forPattern("yyyy-MM-dd HH:mm:ss");  
                //时间解析    
                DateTime dateTime2 = DateTime.parse("2012-12-21 23:22:45", format);    

                //时间格式化,输出==> 2012/12/21 23:22:45 Fri    
                String string_u = dateTime2.toString("yyyy/MM/dd HH:mm:ss EE");    
                System.out.println(string_u);    

                //格式化带Locale,输出==> 2012年12月21日 23:22:45 星期五    
                String string_c = dateTime2.toString("yyyy年MM月dd日 HH:mm:ss EE",Locale.CHINESE);    
                System.out.println(string_c);  

                DateTime dt1 = new DateTime();// 取得当前时间  

                // 根据指定格式,将时间字符串转换成DateTime对象,这里的格式和上面的输出格式是一样的    
                DateTime dt2 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2012-12-26 03:27:39");  

                //计算两个日期间隔的天数  
                LocalDate start=new LocalDate(2012, 12,14);    
                LocalDate end=new LocalDate(2013, 01, 15);    
                int days = Days.daysBetween(start, end).getDays();  

                //计算两个日期间隔的小时数,分钟数,秒数  

                //增加日期  
                DateTime dateTime1 = DateTime.parse("2012-12-03");  
                dateTime1 = dateTime1.plusDays(30);  
                dateTime1 = dateTime1.plusHours(3);  
                dateTime1 = dateTime1.plusMinutes(3);  
                dateTime1 = dateTime1.plusMonths(2);  
                dateTime1 = dateTime1.plusSeconds(4);  
                dateTime1 = dateTime1.plusWeeks(5);  
                dateTime1 = dateTime1.plusYears(3);  

                // Joda-time 各种操作.....    
                dateTime = dateTime.plusDays(1) // 增加天    
                                    .plusYears(1)// 增加年    
                                    .plusMonths(1)// 增加月    
                                    .plusWeeks(1)// 增加星期    
                                    .minusMillis(1)// 减分钟    
                                    .minusHours(1)// 减小时    
                                    .minusSeconds(1);// 减秒数  

                //判断是否闰月    
                DateTime dt4 = new DateTime();    
                org.joda.time.DateTime.Property month = dt4.monthOfYear();    
                System.out.println("是否闰月:" + month.isLeap());  

                //取得 3秒前的时间    
                DateTime dt5 = dateTime1.secondOfMinute().addToCopy(-3);    
                dateTime1.getSecondOfMinute();// 得到整分钟后,过的秒钟数    
                dateTime1.getSecondOfDay();// 得到整天后,过的秒钟数    
                dateTime1.secondOfMinute();// 得到分钟对象,例如做闰年判断等使用  

                // DateTime与java.util.Date对象,当前系统TimeMillis转换    
                DateTime dt6 = new DateTime(new Date());    
                Date date = dateTime1.toDate();    
                DateTime dt7 = new DateTime(System.currentTimeMillis());    
                dateTime1.getMillis();   

                Calendar calendar = Calendar.getInstance();    
                dateTime = new DateTime(calendar);  
    }  

关于OOP和设计模式

  1. 接口是什么?为什么要使用接口而不直接使用具体类?

    接口用于定义API。它定义了类必须得准寻的规则,同时,它提供了一种抽象,因为客户端只使用接口,这样就可以有多种实现,如list接口,你可以使用可以随机访问的ArrayList也可以使用方便插入和删除的LinkedList。在java8中你可以在接口声明静态的默认方法,这种方法是具体的
    
  2. 解释一下里式替换原则

  3. 什么情况下会违反迪米特法则?为什么会有这个问题?

  4. 适配器模式是什么?什么时候使用?

    适配器模式提供对接口的转换,如果你的客户端使用某些接口,但是你有另外一些接口,你就可以写一个适配器去链接这些接口
    
  5. 构造器注入和setter注入那种方式更好?

    每种方式都有缺点和优点.构造器注入保证所有的注入都被初始化。但是setter注入提供更好的灵活性来设置可选依赖,如果使用xml来描述依赖,Setter注入的可读写性会更强,
    
  6. 依赖注入和工厂模式之间有什么不同

    虽然这两种模式都是将对象的创建从应用的逻辑中分离,但是依赖注入比工厂模式更加清晰,通过依赖注入,你的类就是POJO它只知道依赖而不关心他们怎么获取。使用工厂模式你的类需要通过工厂来获取依赖,因此使用DI会比使用工厂模式更加容易测试
    
  7. 适配器模式和装饰器模式有什么区别?

    虽然适配器模式和装饰器模式的结构类似,但是每种模式的出现意图不同,适配器模式是用来桥接两个接口,而装饰模式的目的是在不修改类的情况下给类添加功能
    
  8. 适配器模式和代理模式有什么不同?

    这个问题与前面的类似,适配器模式和代理模式区别也是在于他们的意图不同,由于适配器模式和代理模式都是封装真正执行动作的类,因此结构是一致的,但是适配器模式用于接口之间的转换,而代理模式则是增加一个额外的中间层,以便支持分配,控制,或者智能访问
    
  9. 什么是模板方法模式?

    模板方法提供算法的框架,你可以自己去配置或者定义步骤,例如,你可以将排序栓发看作是一个模板,它定义了排序的步骤,但是具体的比较,可以使用Comparable或者其他语言中类似东西。列出算法的该要的方法就是众所周知的模板方法
    
  10. 什么时候使用访问者模式?

    访问者模式用于解决在类的继承层次上增加操作,但是不直接与之关联,这种模式采用双派发的形式来增加中间层
    
  11. 什么时候使用组合模式?

    组合模式使用树形结构来展示部分与整体继承关系。它允许客户端采用统一的形式来对待但和对象和对象容器,当你想要展示对象这种部分与整体的关系时采用组合模式
    
  12. 继承和组合之间有什么不同?

    虽然两种都可以实现代码复用,但是组合比继承更灵活,用组合允许你在代码运行时选择不同的实现,用组合实现的代码也比继承测试起来更加简单。
    
  13. Java中嵌套公共静态类与顶级类有什么不同?

    类的内部可以有多个嵌套公共静态类,但是一个java源文件只能有一个顶级公共类,并且顶级公共类的名称与源文件的名称必须一样。
    
  14. OOP 中的组合 聚合 和 关联有什么区别?

    如果两个对象彼此有关系,就说他们是彼此关联的,组合和聚合是面向对象中的两种形式的关联。组合是一种比聚合更加强力的关联。组合中,一个对象是另一个对象的拥有者,而聚合是一个对象使用另一个对象。如果对象A 是由对象B 组合的则A不存在的话B一定不存在,但是如果A对象聚合了一个对象B,即使A不存在了,B也可以单独存在
    
  15. 提供一个符合开闭原则的设计模式的例子

    开闭原则要求你的代码对扩展开放,对修改关闭。这个意思就是说,如果你想增加一个新的功能,你可以很容易的在不改变已测试过的代码的前提下增加新的代码。有好几个设计模式是基于开闭原则的,如策略模式,如果你需要一个新的策略,只需要实现接口,增加配置,不需要改变核心逻辑。一个正在工作的例子是Collection.sort()方法,这就是基于策略模式,准循开闭原则的,你不需要为新的对象修改sort方法,你需要做的仅仅是实现你自己的Comparator接口
    
  16. 什么时候使用享元模式?

    享元模式通过共享对象来避免创建太多的对象,为了使用享元模式,你需要确保你的对象是不可变的,这样你才能安全的共享,JDK中的String池,Integer池以及Long池都是很好的使用了享元模式的例子
    

Java中关于XML的面试题,JDBC面试题,正则表达式,Java错误以及序列化方面的问题

  1. 你能写出一个正则表达式来判断一个字符串是否是一个数字吗?
  2. Java中 受检查异常 和 不受检查异常的区别

    受检查异常编译器在编译期间检查,对于这种异常,方法强制处理通过throws子句声明。其中一种情况是Exception的子类但是不是RuntimeException的子类,非受检查是RuntimeException的子类,在编译阶段不接受编译器的检查 
    
  3. Java中,Serializable和Externalizable的区别

    Serializable 接口是一个序列化的Java类的接口,以便于他们可以在网络上传输或者可以将他们的状态保存在磁盘上,JVM内嵌的默认序列化方式成本高,脆弱而且不安全,Externalizable允许你控制整个序列化过程,指定特定的二进制格式,增加安全机制
    
  4. Java中DOM和SAX解析器有什么不同?

    DOM解析器将整个XML文档加载到内存来创建一颗DOM模型树,这样可以更快的查找节点和修改XML结构,而SAX解析器是一个基于时间的解析器,不会将整个XML文档加载到内存。由于这个原因DOM比SAX更快但是也要求更高的内存,不适合于解析大XML文件
    
  5. JDK 1.7中的三个新特性

    • try-with-resource语句,这样你在使用流或者使用资源的时候就不需要手动关闭,Java会自动关闭。

    • Fork-Join池某种情况下实现了Java版的Map-reduce

    • 允许Switch中有String变量

    • <>操作符用于类型推断,不再需要在变量声明的右边声明泛型。因此可以写出读写更强,更简洁的代码。

    • 另一个值得一题的就是改善一场处理,可以允许在同一个catch块中捕获多个异常

  6. JDK 1.8中引入的新特性

    • Lambda表达式,允许像对象一样传递匿名函数

    • Stream API, 充分利用现代多核CPU,可以写出很简介的代码

    • Date TimeAPI 有一个稳定,简单的日期和时间库可供使用

-扩展方法,现在接口中可以有静态,默认的方法。

-重复注解。你可以将相同的注解在同一类型上使用多次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值