面试/笔试第五弹 —— Java面试问题集锦(上篇)

                版权声明:欢迎转载,注明作者和出处就好!如果不喜欢或文章存在明显的谬误,请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步!                    https://blog.csdn.net/justloveyou_/article/details/78653660                </div>
                      <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
                          <div id="content_views" class="markdown_views">
        <!-- flowchart 箭头图标 勿删 -->
        <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
          <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
        </svg>
        <p><strong>写在前面:</strong></p>

  找工作告一段落,期间经历了很多事情,也思考了许多问题,最后也收获了一些沉甸甸的东西 —— 成长和来自阿里、百度、京东(sp)、华为等厂的Offer。好在一切又回到正轨,接下来要好好总结一番才不枉这段经历,遂将此过程中笔者的一些笔试/面试心得、干货发表出来,与众共享之。在此特别要感谢CSDN以及广大朋友的支持,我将坚持记录并分享自己所学、所想、所悟,央请大家不吝赐教,提出您宝贵的意见和建议,以期共同探讨提高。


摘要:

  本文对面试过程中经常会被问到的一些关于Java基础问题进行了梳理和总结,包括 JVM虚拟机、常用容器、设计原则与模式以及Java语言特性等基础知识点,一方面方便自己温故知新,另一方面也希望为找工作的同学们提供一个复习参考。考虑到篇幅太长,现将 《面试/笔试第五弹 —— Java面试问题集锦》 一文分为上下两篇:《面试/笔试第五弹 —— Java面试问题集锦(上篇)》《面试/笔试第五弹 —— Java面试问题集锦(下篇)》


版权声明:

  本文原创作者:书呆子Rico
  作者博客地址:http://blog.csdn.net/justloveyou_/


1、Struts2和SpringMVC的区别

  • 设计理念:前者为有状态的Action(均为多例),Action对象属性字段承载请求、响应,后者一般为无状态的Controller,请求直接封装到方法的参数中;

  • 集中访问点不同:都属于前端控制器,用于接收请求、处理请求和生成响应,但集中访问点不同,前者为Filter,后者为Servlet;

  • 请求处理粒度不同:前者一个Action对应一个请求上下文,后者一个方法对应一个请求上下文,因此更容易实现Rest;

  • 拦截器机制不同:Struts2和SpringMVC的拦截器机制均是对AOP理念的应用,但Struts2的interceptor机制是通过代理机制(ActionProxy)+责任链模式实现的,而SpringMVC的interceptor机制实现比较简单,其通过循环的方式在handler处理请求前后分别调用preHandle()方法和postHandle()方法对请求和响应进行处理,与Spring AOP、责任链模式等基本无关;

  • 对Ajax的支持不同:前者需要插件或者手动转化,而后者集成了对Ajax请求的处理(HttpMessageConverter);

  • 与Spring的整合:前者需要插件,后者无缝整合(子容器);

  • 配置/效率:后者几乎是零配置,开发效率更高。


2、Spring中IoC的理解

  关键词:超级大工厂对象控制权解耦对象间的依赖关系

  • 超级大工厂,对象控制权由调用者移交给容器,使得调用者不必关心对象的创建和管理,专注于业务逻辑开发;

  • 优秀的解耦方式,解耦对象间的依赖关系,避免通过硬编码的方式耦合在一起;

  • 底层实现:反射机制;


3、Spring中AOP的理解

  关键词:模块化交叉关注点横切性质的系统级业务

  • 一种新的模块化方式,专门处理系统各模块中的交叉关注点问题,将具有横切性质的系统级业务提取到切面中,与核心业务逻辑分离(解耦);

  • 便于系统的扩展,符合开-闭原则;

  • 动态AOP的实现,Java动态代理(接口代理)与cglib(类代理),具体由Bean后处理器生成代理;

  • AOP理念实践:Spring AOP,Java Web Filter,Struts2 Interceptor, SpringMVC Interceptor,…


4、JVM 基础

1). 内存模型

 (1). 程序计数器: 线程私有,CPU调度的基本单位,用于保证线程切换(程序能够在多线程环境下连续执行);

 (2). 栈(服务Java方法虚拟机栈、服务Native方法的本地方法栈):线程私有,局部变量/引用,栈深度(SOF)/无法申请内存(OOM);

 (3). 堆(Java代码可及的Java堆和JVM自身使用的方法区):线程共享,对象分配和回收主要区域,OOM

  更多关于JVM内存模型相关内容,请参见博文《JVM 内存模型概述》


2). 垃圾回收机制

 (1). Stop-the-World

  JVM由于要执行GC而停止了应用程序的执行称之为Stop-the-World,该情形会在任何一种GC算法中发生。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态直到GC任务完成。事实上,GC优化很多时候就是指减少Stop-the-world发生的时间,从而使系统具有 高吞吐 、低停顿 的特点。


 (2). Java堆的回收

  关于Java对象的回收主要考虑以下两个问题:哪些对象可以被回收、怎么回收(有哪些回收算法以及有哪些垃圾回收器)。

  • 判断对象是否可被回收:引用计数法(相互引用)、可达性算法(对象的引用链是否可达,GCRoots)

  • 垃圾回收算法:标记-清除算法(内存碎片)、复制算法(垃圾回收较为频繁、对象存活率较低的新生代)、标记-整理算法(垃圾回收不频繁、对象存活率较高的老年代)、分代收集算法

  • 垃圾回收器:串行收集器(新生代、老年代)、并行收集器(新生代、老年代)、并行清除收集器(并发,新生代,追求高吞吐)、CMS收集器(并发,老年代,标记-清除算法,追求低停顿)、G1垃圾收集器(整个堆,追求低停顿)

 GC Roots一般包括虚拟机栈中引用的对象,本地方法栈中引用的对象,方法区中类静态属性引用的对象、方法区中常量引用的对象。

 分代收集算法的基本思想是 不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。Minor GC 发生频率较高,不一定等 Eden区满了才触发;Major GC在老年代满时触发,对年轻代和老年代进行回收。


 (3). 方法区的回收

  • 对常量池的回收

  • 对类型的卸载:该类的所有实例被回收,该类的ClassLoader被回收,不存在对该类的Class对象的引用

  更多关于JVM垃圾回收机制相关内容,请参见博文《图解Java垃圾回收机制》


3). OOM/SOF

  • OOM for Heap:内存泄露(GC Roots的引用链,对象的生命周期超出预期)或者内存溢出(调节JVM参数 -Xms,-Xmx 等)

  • OOM for Stack:一般在单线程程序中不会出现;在多线程环境下,无法申请到足够的内存去创建线程

  • SOF for Stack:程序是否有深度递归

  • OOM for Perm :用到像Spring等框架的时候,常常会动态地生成大量的类导致永久代不够用而导致OutOfMemoryError: PermGen Space异常(调大 -XX:MaxPermSize)


4、JVM 调优

  JVM 调优的主要目标是使系统具有 高吞吐 、低停顿 的特点,其优化手段应从两方面着手:Java虚拟机Java应用程序。前者指根据应用程序的设计通过虚拟机参数控制虚拟机逻辑内存分区的大小以使虚拟机的内存与程序对内存的需求相得益彰;后者指优化程序算法,降低GC负担,提高GC回收成功率。

  以下是一些常用的JVM调优工具:

  • Jconsole 与 Visual VM

  JConsole 与 Visual VM 都是JDK自带的 Java 性能分析器,可以从命令行或在 GUI shell 中运行,从而可以轻松使用 JConsole来监控 Java 应用程序性能和跟踪 Java 中的代码,其可以从JAVA_HOME/bin/这个目录下找到。使用 Jconsole 监测死锁示例如下:

         Jconsole.png-21.4kB


  • Jstack

  JDK自带的命令行工具,可以查看某个Java进程内的线程堆栈信息,主要用于线程Dump分析。

         jstack.png-10.3kB


  • jps

  jps位于jdk的bin目录下,其作用是显示当前系统的java进程情况及其id。

           jps.png-2kB


6、责任链(CoR)模式

 目的:请求的发送者与请求的处理者解耦,便于动态的重新组织链和分配责任

 角色:抽象处理者、具体处理者、客户端

 UML:
 
         责任链模式结构1.png-65.5kB

  传统责任链(CoR)模式的缺点在于:具体处理角色存在着共同的实现责任链结构的行为行为,即责任链的建立和指派包含在实现角色的类中,并没有抽象出来,这直接导致责任链的指派不够灵活。因此,改进的CoR模式为:使用AOP理念将责任链结构的实现用切面抽象出来,使得各个对象只关注自身必须实现的功能性需求,准确地分离出责任链模式中不同角色的共同行为,例如,

          模拟Filter类图.png-21.3kB

  改进后责任链(CoR)模式的应用是比较广泛的,包括 Java Web Filter(链式调用),Struts2 Interceptor(Action代理)和SpringMVC等。


7、单例模式

  单例模式核心在于为整个系统提供一个唯一的实例,为整个系统提供一个全局访问点。单例模式从实现上可以分为饿汉式单例和懒汉式单例两种,前者天生就是线程安全的,后者则需要考虑线程安全性,常见的线程安全的懒汉式单例的实现有内部类式和双重检查式两种。下面给出单例模式几种常见的形式:

                 单例模式类图.gif-9.2kB


(1). 饿汉式单例

// 饿汉式单例
public class Singleton1 {

    // 指向自己实例的私有静态引用,主动创建
    private static Singleton1 singleton1 = new Singleton1();

    // 私有的构造方法
    private Singleton1(){}

    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton1 getSingleton1(){
        return singleton1;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(2). 懒汉式单例

// 懒汉式单例
public class Singleton2 {

    // 指向自己实例的私有静态引用
    private static Singleton2 singleton2;

    // 私有的构造方法
    private Singleton2(){}

    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton2 getSingleton2(){
        // 被动创建,在真正需要使用时才去创建
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

(3). 线程安全的懒汉式单例 —— 内部类方式

public class Singleton {
    //静态私有内部类
    private static class InnerClass {
        private final static Singleton instance = new Singleton();
    }

    private Singleton(){

    }

    public static Singleton getInstance(){
        return InnerClass.instance;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

  内部类方式线程安全懒汉式单例的内在原理在于:虚拟机会保证一个类的类构造器<clinit>()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器<clinit>(),其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行<clinit>()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行<clinit>()方法,因为 在同一个类加载器下,一个类型只会被初始化一次。


(4). 线程安全的懒汉式单例 —— 双重检查方式

public class Singleton {

    // volatile: 防止指令重排序
    private volatile static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        // 第一次检查
        if(instance == null){
            // 只在最初几次会进入该同步块,提高效率
            synchronized(Singleton.class){
                // 第二次检查
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

8、类的生命周期及其初始化时机

  类的生命周期主要包括加载、链接、初始化、使用和卸载五个阶段,如下图所示:

            类的生命周期-11.2kB

  其中,虚拟机规范指明 有且只有 五种情况必须立即对类进行初始化,包括:

 1). 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时:注意,newarray指令触发的只是数组类型本身的初始化,而不会导致其相关类型的初始化,比如,new String[]只会直接触发String[]类的初始化,也就是触发对类[Ljava.lang.String的初始化,而直接不会触发String类的初始化时,如果类没有进行过初始化,则需要先对其进行初始化。生成这四条指令的最常见的Java代码场景是:

  • 使用new关键字实例化对象的时候;

  • 读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候;

  • 调用一个类的静态方法的时候。


 2). 对类进行反射调用时:使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。


 3). 初始化子类时:当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。


 4). 虚拟机启动时:当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。


 5). 当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。


9、类加载过程中各阶段的作用

1、 加载(Loading)

  (1). 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);

  (2). 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;

  (3). 在内存中(对于HotSpot虚拟就而言就是方法区)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;


2、 验证(Verification):验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。


3、准备(Preparation):准备阶段是正式为类变量(static 成员变量)分配内存并设置类变量初始值(零值)的阶段,这些变量所使用的内存都将在方法区中进行分配。


4、解析(Resolution):解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。


5、初始化(Initialization):初始化阶段是执行类构造器<clinit>()方法的过程。虚拟机会保证一个类的类构造器<clinit>()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器<clinit>(),其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行<clinit>()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行<clinit>()方法,因为 在同一个类加载器下,一个类型只会被初始化一次。


10、对象的创建过程

  在Java中,创建一个对象常常需要经历如下几个过程:父类的类构造器<clinit>() -> 子类的类构造器<clinit>() -> 父类的实例构造器(成员变量和实例代码块,父类的构造函数) -> 子类的实例构造器(成员变量和实例代码块,子类的构造函数)。其中,类构造器<clinit>()由静态变量和静态语句块组成,而类的实例构造器<init>()类的实例变量/语句块以及其构造函数组成,更多相关内容请参见笔者的博文《深入理解Java对象的创建过程:类的初始化与实例化》


11、双亲委派模型

  双亲委派模型很好地解决了类加载器的统一加载问题:越基础的类由越上层的加载器进行加载,进而保证Java类型体系中最基础的行为,防止应用程序变得混乱。比如,java.lang.Object 类总是由启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类型(是否是同一类型由类加载器与类本身共同决定)。

                 类加载器默认委派关系图-11.2kB


          自定义类加载器加载类的过程-54.2kB


12、异常机制

  Java体系中异常的组织分类如下图所示,所有异常类型的根类为 Throwable,具体包括两大类:Error 与 Exception。其中,Error是指程序无法处理的错误,表示运行应用程序中较严重问题;Exception是指程序本身可以处理的错误,具体可分为运行时异常(派生于 RuntimeException 的异常) 和 其他异常。

  此外,从异常是否必须需要被处理的角度来看,异常又可分为不受检查异常和受检查异常两种情况:

  • 不受检查异常:派生于 Error 或 RuntimeException 的所有异常;

  • 受检查异常:除去不受检查异常的所有异常。

         异常-52.7kB


  下面着重介绍一下使用finally子句,在对应的try子句执行的前提下,finally 子句总会被执行。并且,finally子句 总是在诸如return、break、throw和continue等控制转移语句之前执行。看以下几个经典例子:


1)、 try子句执行,finally子句必然执行

// 代码片段1
 public class Test { 
    public static void main(String[] args) {  
        try {  
            System.out.println("try block");  
            return ;  
        } finally {  
            System.out.println("finally block");  
        }  
    }  
 }/* Output:
        try block 
        finally block
 *///:~ 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2)、 try子句执行,finally子句必然执行,且在控制转移语句之前执行

// 代码片段2
public class Test { 
    public static void main(String[] args) {  
        System.out.println("reture value of test() : " + test()); 
    } 

    public static int test(){ 
        int i = 1; 

        try {  
            System.out.println("try block");  
            i = 1 / 0; 
            return 1;  
        }catch (Exception e){ 
            System.out.println("exception block"); 
            return 2; 
        }finally {  
            System.out.println("finally block");  
        } 
    } 
}/* Output:
        try block 
        exception block 
        finally block 
        reture value of test() : 2
 *///:~ 
 
 
  • 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

3)、 try子句执行,finally子句必然执行,且在控制转移语句throw子句之前执行

// 代码片段3
public class ExceptionSilencer { 
    public static void main(String[] args) { 
        try { 
            throw new RuntimeException(); 
        } finally { 
            // Using ‘return’ inside the finally block 
            // will silence any thrown exception. 
            return; 
        } 
    } 
} ///:~
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

  更多关于Java异常机制的相关内容请参见笔者博文《 Java 异常模型综述》


13、七大设计原则

  • 单一职责原则:高内聚,一个类只做它该做的事情;

  • 接口隔离原则:接口小而专,避免大而全;

  • 依赖倒置原则:依赖抽象而非实现,面向接口编程;

  • 里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能;

  • 开闭原则:Open for Extension, Closed for Modification,例如 AOP,代理模式,适配器模式就是其经典应用;

  • 迪米特法则:高内聚,低耦合;


14、代理模式

   根据代理类的创建时机和创建方式的不同,我们可以将代理模式分为静态代理和动态代理两种形式,其中,在程序运行前就已经存在的编译好的代理类是为静态代理,在程序运行期间根据需要动态的创建代理类及其实例来完成具体的功能是为动态代理。其中,代理对象的作用如下:

  • 代理对象存在的价值主要用于拦截对真实业务对象的访问;

  • 代理对象应该具有和目标对象(真实业务对象)相同的方法,即实现共同的接口或继承于同一个类;

  • 代理对象应该是目标对象的增强,否则我们就没有必要使用代理了。

          代理模式.png-22kB


  JDK 动态代理是动态代理模式的经典实现,主要包括三个角色对象:Subject (接口)、被代理的类以及InvocationHandler接口(一般持有被代理对象),例如:

  • 实现 InvocationHandler 接口
public class ProxyHandler implements InvocationHandler {

    private Object proxied;   // 被代理对象

    public ProxyHandler(Object proxied) {
        this.proxied = proxied;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        // 在转调具体目标对象之前,可以执行一些功能处理
        System.out.println("前置增强处理: yoyoyo...");

        // 转调具体目标对象的方法(三要素:实例对象 + 实例方法 + 实例方法的参数)
        Object obj = method.invoke(proxied, args);

        // 在转调具体目标对象之后,可以执行一些功能处理
        System.out.println("后置增强处理:hahaha...");

        return obj;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

  • Proxy.newProxyInstance
// 真实对象real
Subject real = new RealSubject();

// 生成real的代理对象
Subject proxySubject = (Subject) Proxy.newProxyInstance(
    Subject.class.getClassLoader(), new Class[] { Subject.class },
    new ProxyHandler(real));

proxySubject.doSomething();
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  但是,JDK动态代理只能完成对接口的代理,而不能完成对类的代理,关键原因为:Java只允许单继承。具体地,代理对象proxySubject的类型为“com.sun.proxy.$Proxy0”,这恰好印证了proxySubject对象是一个代理对象。除此之外,我们还发现代理对象proxySubject所对应的类继承自java.lang.reflect.Proxy类,这也正是JDK动态代理机制无法实现对class的动态代理的原因。


15、迭代器模式

  迭代器模式是与集合共生共死的。一般来说,我们只要实现一个容器,就需要同时提供这个容器的迭代器,使用迭代器的好处是:封装容器的内部实现细节,对于不同的集合,可以提供统一的遍历方式,简化客户端的访问和获取容器内数据。

            迭代器模式结构图.jpg-53.9kB

  特别需要注意的是,在迭代器模式中,具体迭代器角色和具体容器角色是耦合在一起的 —— 遍历算法是与容器的内部细节紧密相关的。为了使客户程序从与具体迭代器角色耦合的困境中脱离出来,避免具体迭代器角色的更换给客户程序带来的修改,迭代器模式抽象了具体迭代器角色,使得客户程序更具一般性和重用性,这被称为多态迭代。

  在 Java Collection FrameWork中,提供的具体迭代器角色是定义在容器角色中的内部类,这样便保护了容器的封装。但是,同时容器也提供了遍历算法接口,并且你可以扩展自己的迭代器。大家考虑一个问题,为什么一定要去实现 Iterable 这个接口呢? 为什么不直接实现 Iterator接口 呢?

  看一下 JDK 中的集合类,比如 List一族或者Set一族,都是实现了 Iterable 接口,但并不直接实现 Iterator 接口。仔细想一下这么做是有道理的:因为 Iterator接口的核心方法 next() 或者 hasNext() 是依赖于迭代器的当前迭代位置的。若 Collection 直接实现 Iterator 接口,势必导致集合对象中包含当前迭代位置的数据(指针)。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么 next() 方法的结果会变成不可预知。除非再为 Iterator接口 添加一个 reset() 方法,用来重置当前迭代位置。但即使这样,Collection 也只能同时存在一个当前迭代位置(不能同时多次迭代同一个序列:必须要等到当前次迭代完成并reset后,才能再一次从头迭代)。 而选择实现 Iterable 接口则不然,每次调用都会返回一个从头开始计数的迭代器(Iterator),因此,多个迭代器间是互不干扰的。


16、适配器模式

  适配器模式将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间。也就是说,适配器模式用于实现新、老接口之间的转换与适配,其魅力在于:不改变原有接口,却还能使用新接口的功能。

             适配器模式.png-8.4kB


  适配器模式主要包含以下四个角色,其内涵分别为:

  • Target: 客户所期待的接口;

  • Adaptee: Adapter 所包装的对象,即被适配的类(适配者);

  • Adapter: 一个用于包装不兼容接口的对象的包装类,通过包装一个需要适配的对象,把原接口转换成目标接口;

  • Client: 客户端;


  适配器模式的三个特点:

  • 适配器对象实现原有接口;

  • 适配器对象组合一个实现新接口的对象(这个对象也可以不实现一个接口,只是一个单纯的对象);

  • 对适配器原有接口方法的调用被 委托 给新接口的实例的特定方法。


  适配器模式在Java中最经典的应用为IO中字节流与字符流的转换:

java.io.InputStreamReader(InputStream)

java.io.OutputStreamWriter(OutputStream)
 
 
  • 1
  • 2
  • 3

  更多关于适配器模式的内容详见一个示例让你明白适配器模式
运用适配器模式应对项目中的变化两篇博文。


17、模板方法模式

  模板方法模式是一种基于继承的代码复用技术,是一种类行为型模式,其核心在于:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

            模板方法.png-57kB

  模板方法模式的经典应用包括 HibernateTemplate,AQS 等,其优点包括:

  • 封装不变部分,扩展可变部分;

  • 提取公共代码,便于维护;

  • 行为由父类控制,子类实现。


18、策略模式

  策略模式属于对象的行为模式,其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换,核心思想是:面向接口编程

            策略模式.jpg-29.7kB

  策略模式的经典应用包括Spring的PlatfromTransactionManager,JDK 排序策略 (不同的Comparator)等,其优点包括:

  • 算法可以自由切换,避免使用多重条件判断;

  • 扩展性良好。


1). 策略模式与模板方法的区别

  对于策略模式而言,一个“策略”是一个整体的(完整的)算法,算法是可以被整体替换的;而模板方法只能被替换其中的特定点,算法流程是固定不可变的。在思想和意图上看,模板方法更加强调:

  • 定义一条线(算法流程),线上的多个点是可以变化的(具体实现在子类中完成),线上的多个点一定是会被执行的,并且一定是按照特定流程被执行的。

  • 算法流程只有唯一的入口,对于点的访问是受限的。


19、Java 自动装箱、拆箱机制

  Java为每种基本数据类型都提供了对应的包装器类型。所谓自动装箱机制就是自动将基本数据类型转换为包装器类型,而自动拆箱机制就是自动将包装器类型转换为基本数据类型。在JDK中,装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的(xxx代表对应的基本数据类型)。但是,

  • Integer、Short、Byte、Character、Long 这几个类的valueOf方法的实现是类似的,有限可列举,共享[-128,127];

  • Double、Float的valueOf方法的实现是类似的,无限不可列举,不共享;

  • Boolean的valueOf方法的实现不同于以上的整型和浮点型,只有两个值,有限可列举,共享;


(1). 什么时候装箱/拆箱?

  至于什么时候装箱,什么时候拆箱主要取决于:在当前场景下,你需要的是引用类型还是原生类型。若需要引用类型,但传进来的值是原生类型,则自动装箱(例如,使用equals方法时传进来原生类型的值);若需要的是原生类型,但传进来的值是引用类型,则自动拆箱(例如,使用运算符进行运算时,操作数是包装类型)。

  更多关于Java自动装箱与拆箱机制的内容可以参见笔者的博文《Java 原生类型与包装器类型深度剖析》


20、内部类

  内部类指的是在一个类的内部所定义的类,类名不需要和源文件名相同。在Java中,内部类是一个编译时的概念,一旦编译成功,内部类和外部类就会成为两个完全不同的类,共有四种类型:

  • 成员内部类:成员内部类是外围类的一个成员,是依附于外围类的,所以,只有先创建了外围类对象才能够创建内部类对象。也正是由于这个原因,成员内部类也不能含有 static 的变量和方法;

  • 静态内部类:静态内部类,就是修饰为static的内部类,该内部类对象不依赖于外部类对象,就是说我们可以直接创建内部类对象,但其只可以直接访问外部类的所有静态成员和静态方法;

  • 局部内部类:局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效;

  • 匿名内部类:定义匿名内部类的前提是,内部类必须要继承一个类或者实现接口,格式为 new 父类或者接口(){定义子类的内容(如函数等)}。也就是说,匿名内部类最终提供给我们的是一个 匿名子类的对象


1)、内部类的作用

  • 间接实现多重继承,例如:
//父类Example1
public class Example1 {
    public String name() {
        return "rico";
    }
}

//父类Example2
public class Example2 {
    public int age() {
        return 25;
    }
}

//实现多重继承的效果
public class MainExample {

    //内部类Test1继承类Example1
    private class Test1 extends Example1 {
        public String name() {
            return super.name();
        }
    }

    //内部类Test2继承类Example2
    private class Test2 extends Example2 {
        public int age() {
            return super.age();
        }
    }

    public String name() {
        return new Test1().name();
    }

    public int age() {
        return new Test2().age();
    }

    public static void main(String args[]) {
        MainExample mexam = new MainExample();
        System.out.println("姓名:" + mexam.name());
        System.out.println("年龄:" + mexam.age());
    }
}/* Output:
        姓名:rico
        年龄:25
 *///:~ 
 
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

  • 内部类还可以很好的实现隐藏(一般的非内部类,是不允许有 private 与 protected 权限的,但内部类可以)。

21、equals, hashCode, ==

  • == 用于判断两个对象是否为同一个对象或者两基本类型的值是否相等;

  • equals 用于判断两个对象内容是否相同;

  • hashCode 是一个对象的 消息摘要函数,一种 压缩映射,其一般与equals()方法同时重写;若不重写hashCode方法,默认使用Object类的hashCode方法,该方法是一个本地方法,由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数。


1). equals与hashCode的区别

  • 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;

  • 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。


2). 在HashMap中使用可变对象作为Key带来的问题

  HashMap用Key的哈希值来存储和查找键值对,如果HashMap Key的哈希值在存储键值对后发生改变,那么Map可能再也查找不到这个Entry了。也就是说,在HashMap中可变对象作为Key会造成 数据丢失。因此,

  • 在HashMap中尽量使用不可变对象作为Key,比如,使用String、Integer等不可变类型用作Key是非常明智的或者使用自己定义的不可变类。

  • 如果可变对象在HashMap中被用作键,那就要小心在改变对象状态的时候,不要改变它的哈希值了,例如,可以只根据对象的标识属性生成HashCode。

public class MutableSafeKeyDemo {

    public static void main(String[] args) {
        Employee emp = new Employee(2);
        emp.setName("Robin");

        // Put object in HashMap.
        Map<Employee, String> map = new HashMap<>();
        map.put(emp, "Showbasky");

        System.out.println(map.get(emp));

        // Change Employee name. Change in 'name' has no effect
        // on hash code.
        emp.setName("Lily");
        System.out.println(map.get(emp));
    }
}

class Employee {
    // It is specified while object creation.
    // Cannot be changed once object is created. No setter for this field.
    private int id;
    private String name;

    public Employee(final int id) {
        this.id = id;
    }

    public final String getName() {
        return name;
    }

    public final void setName(final String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    // Hash code depends only on 'id' which cannot be
    // changed once object is created. So hash code will not change
    // on object's state change
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        return true;
    }
}
 
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

3). 重写equals但不重写HashCode会出现的问题

  在使用Set时,若向其加入两个相同(equals返回为true)的对象,由于hashCode函数没有进行重写,那么这两个对象的hashCode值必然不同,它们很有可能被分散到不同的桶中,容易造成重复对象的存在。


4). JDK中equals()方法实现逻辑

  • 先 比较引用是否相同(是否为同一对象),
  • 再 判断类型是否一致(是否为同一类型),
  • 最后 比较内容是否一致

 更多关于Java中关于相等的内容可以参见笔者的博文《Java 中的 ==, equals 与 hashCode 的区别与联系》


22、什么是不可变对象

  一个不可变对象应该满足以下几个条件:

  • 基本类型变量的值不可变;

  • 引用类型变量不能指向其他对象;

  • 引用类型所指向的对象的状态不可变;

  • 除了构造函数之外,不应该有其它任何函数(至少是任何public函数)修改任何成员变量;

  • 任何使成员变量获得新值的函数都应该将新的值保存在新的对象中,而保持原来的对象不被修改。


23、Java的序列化/反序列化机制

(1)、使用Serializable序列化/反序列化

  将实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象,序列化可以弥补不同操作系统之间的差异。其中,需要注意以下几点:

  • 需要序列化的对象必须实现Serializable接口;

  • 只有非静态字段和非transient字段进行序列化,与字段的可见性无关;

  • 序列化/反序列化的实质上操纵的是一个对象图;

public class Student implements Cloneable, Serializable {

    private int id;

    public Student(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student [id=" + id + "]";
    }

    public static void main(String[] args) throws Exception {

        Constructor<Student> constructor = Student.class
                .getConstructor(Integer.class);
        Student stu3 = constructor.newInstance(123);

        // 写对象
        ObjectOutputStream output = new ObjectOutputStream(
                new FileOutputStream("student.bin"));
        output.writeObject(stu3);
        output.close();

        // 读对象
        ObjectInputStream input = new ObjectInputStream(new FileInputStream(
                "student.bin"));
        Student stu5 = (Student) input.readObject();
        System.out.println(stu5);
    }
}
 
 
  • 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
  • 31
  • 32

  此外,Java中常用到的序列化方法还有 XML、JSON 等,此不赘述。


Java 软件工程师面试资料大整合 1 Java 面霸 1 1. int 和 Integer 有什么区别? 8 2. String 和StringBuffer的区别 8 3. 运行时异常与一般异常有何异同? 8 4. 说出ArrayList,Vector,LinkedList的存储性能和特性 8 5. EJB是基于哪些技术实现的?并说出SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别。 9 6. Collection 和 Collections的区别。 9 7. &和&&的区别。 9 8. HashMap和Hashtable的区别。 10 9. final, finally, finalize的区别。 10 10. sleep() 和 wait() 有什么区别? 10 11. Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? 10 12. error和exception有什么区别? 11 13. 同步和异步有何异同,在什么情况下分别使用他们?举例说明。 11 14. 简述synchronized和java.util.concurrent.locks.Lock的异同 ? 11 15. 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 11 16. abstract class和interface有什么区别? 12 17. abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized? 12 18. 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)? 12 19. heap和stack有什么区别。 13 20. forward 和redirect的区别 13 21. EJB与JAVA BEAN的区别? 13 22. Static Nested Class 和 Inner Class的不同。 13 23. JSP中动态INCLUDE与静态INCLUDE的区别? 14 24. List, Set, Map区别 14 25. 集合类都有哪些?主要方法? 14 26. 简述逻辑操作(&,|,^)与条件操作(&&,||)的区别。 14 27. XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 14 28. JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么? 15 29. Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 15 30. 构造器Constructor是否可被override 15 31. try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 16 32. 应用服务器与WEB SERVER的区别? 16 33. BS与CS的联系与区别。 16 34. 启动一个线程是用run()还是start()? 17 35. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 18 36. swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上? 18 37. 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 18 38. 比较truncate和delete 命令 18 39. 解释$ORACLE_HOME 和$ORACLE_BASE的区别? 19 40. session与cookie的区别和联系? 19 41. Statement和PrepareStatement的区别 19 42. JSP的内置对象及方法。 19 43. JSP的常用指令 20 44. 四种会话跟踪技术 20 45. Request对象的主要方法: 21 46. jsp有哪些动作?作用分别是什么? 21 47. 两种跳转方式分别是什么?有什么区别? 22 48. get和post的区别? 22 49. JDK,JRE,JVM的区别? 22 50. Java中常见类,方法,接口 23 51. 多线程 23 51.1. 线程的基本概念 23 51.2. Java中的线程有四种状态 23 51.3. 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 24 51.4. 线程同步的方法。 24 51.5. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 25 52. 数据连接池 25 52.1. 连接池的基本原理: 25 52.2. 连接池的工作机制 25 52.3. 建立连接池 26 52.4. 连接池内连接的使用与释放 26 52.5. 配置连接池 26 52.6. 配置tomcat 6.0.10连接池 26 52.7. Hibernate实现数据库的连接不同方式: 28 52.8. 有几种开源的数据库连接池: 29 53. 描述一下JVM加载class文件的原理机制? 30 54. socket编程 30 54.1. 什么是TCP/IP、UDP? 30 54.2. Socket在哪里呢? 31 54.3. Socket是什么呢? 32 54.4. socket的实现步骤 37 55. Servlet 38 55.1. Servlet工作流程 38 55.2. servlet的生命周期 38 55.3. Servlet执行时一般实现哪几个方法? 38 56. 会话跟踪 39 56.1. Cookie 39 56.2. session 39 56.2.1. Session 生命周期 39 57. EJB的几种类型 39 58. 排序都有哪几种方法?请列举。用JAVA实现一个快速排序。 40 59. 请对以下在J2EE中常用的名词进行解释(或简单描述) 40 59.1. web 容器 40 59.2. EJB容器 40 59.3. JNDI 40 59.4. JMS 41 59.5. JTA 41 59.6. JAF 41 59.7. RMI/IIOP 41 60. JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗? 41 61. MVC的各个部分都有那些技术来实现?如何实现? 42 62. java中实现多态的机制是什么? 42 63. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收? 42 63.1. 判断该对象是否是时候可以收集方法 43 63.1.1. 引用计数 43 63.1.2. 对象引用遍历 43 63.2. 几种垃圾回收机制 43 63.2.1. 标记-清除收集器 43 63.2.2. 标记-压缩收集器 43 63.2.3. 复制收集器 44 63.2.4. 增量收集器 44 63.2.5. 分代收集器 44 63.2.6. 并发收集器 44 63.2.7. 并行收集器 44 63.3. Sun HotSpot 1.4.1 JVM堆大小的调整 44 63.4. BEA JRockit JVM的使用 45 63.4.1. Bea JRockit JVM支持4种垃圾收集器: 46 63.5. 如何从JVM中获取信息来进行调整 46 63.6. Pdm系统JVM调整 47 63.6.1. 服务器:前提内存1G 单CPU 47 63.6.2. 客户机:通过在JNLP文件中设置参数来调整客户端JVM 47 64. 什么时候用assert。 47 65. 什么是java序列化,如何实现java序列化? 48 65.1. java序列化、反序列化 48 65.2. 对象的序列化主要有两种用途: 48 65.3. 对象序列化包括如下步骤: 49 65.4. 对象反序列化的步骤如下: 49 66. 反射机制 49 66.1.1. 传统的类型转换。 49 66.1.2. 通过Class对象来获取对象的类型。 49 66.1.3. 通过关键字instanceof或Class.isInstance()方法 49 67. 说出一些常用的类,包,接口,请各举5个 50 68. XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 51 69. jdbc 51 69.1. 简述 51 69.2. JDBC调用数据库的基本步骤 52 69.3. JDBC URL 52 70. MVC设计模式 53 71. Hibernate 54 71.1. Hibernate 介绍 54 71.2. Hibernate 实现原理 55 71.3. Hibernate 优点 56 71.4. Hibernate 的缓存体系 56 71.4.1. 一级缓存: 56 71.4.2. 二级缓存: 56 71.4.3. 缓存管理 56 71.5. Hibernate 中Java对象的状态 58 71.5.1. 临时状态 (transient) 58 71.5.2. 持久化状态(persisted) 58 71.5.3. 游离状态(detached) 58 71.5.4. hibernate的三种状态之间如何转换 59 71.6. Hibernate并发机制,并发问题的处理。 59 71.6.1. Hibernate并发机制 59 71.6.2. 并发问题解决方案 59 71.7. Hibernate是如何延迟加载? 60 71.8. Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系) 60 71.9. 说下Hibernate的缓存机制 60 71.10. Hibernate的查询方式 60 71.11. 如何优化Hibernate? 61 71.12. Hibernate和spring中常出现的几个异常 61 71.13. Hibernate与jdbc的联系 62 71.14. Hibernate与Spring的联系 62 71.15. Hibernate自带的分页机制是什么?如果不使用Hibernate自带的分页,则采用什么方式分页? 62 71.16. hibernate中一对多配置文件返回的是什么? 63 71.17. hibernate拒绝连接、服务器崩溃的原因?最少写5个 63 71.18. Hibernate主键介绍 63 71.18.1. Assigned 63 71.18.2. Hilo 63 71.18.3. Increment 64 71.18.4. Identity 64 71.18.5. Sequence 64 71.18.6. Native 64 71.18.7. UUID 64 71.18.8. Foreign GUID 65 71.19. Hibernate源码中几个包的作用简要介绍 65 72. struts 66 72.1. struts 简介 66 72.2. STRUTS的应用(如STRUTS架构) 66 72.3. 请写出Struts的工作原理、工作机制 67 72.4. struts的处理流程。 67 72.5. Struts 2框架的大致处理流程如下: 68 72.6. Struts体系结构中的组件 69 72.7. struts如何实现国际化 70 72.8. struts2.0的常用标签 71 72.9. action是单实例还是多实例,为什么? 73 72.10. Struts的validate框架是如何验证的? 74 72.11. dispatchAction是用什么技术实现的? 74 72.12. struts2.0的mvc模式?与struts1.0的区别? 74 72.13. struts1.2和struts2.0的区别?如何控制两种框架中的单例模式? 74 73. Spring 75 73.1. Spring 简介 75 73.2. 为什么要用Spring? 76 73.3. spring工作机制或工作原理 76 73.4. Spring是什么?根据你的理解详细谈谈你的见解。 76 73.5. 项目中如何体现Spring中的切面编程,具体说明。 77 73.6. 项目中用到的Spring中的切面编程最多的地方:声明式事务管理。 77 73.7. spring的事务如何配置 77 73.8. transaction有那几种实现(事务处理)(Spring) 79 73.9. Spring IoC 79 73.10. Spring AOP面向方面编程 82 74. 项目中为什么使用SSH 85 75. Spring在SSH中的作用 86 76. weblogic 86 76.1. 如何给weblogic指定大小的内存? 86 76.2. 如何设定的weblogic的热启动模式(开发模式)与产品发布模式? 86 76.3. 如何启动时不需输入用户名与密码? 86 76.4. 在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中? 86 76.5. 在weblogic中发布ejb需涉及到哪些配置文件 87 76.6. 如何在weblogic中进行ssl配置与客户端的认证配置或说说j2ee(标准)进行ssl的配置 87 76.7. 如何查看在weblogic中已经发布的EJB? 87 76.8. 说说在weblogic中开发消息Bean时的persistent与non-persisten的差别 87 77. tomcat 87 77.1. 解决端口冲突导致tomcat无法启动的问题 87 77.2. 修改java虚拟机内存 88 77.3. 修改tomcat连接数 88 77.4. 禁止列出目录下的文件 88 77.5. 设置session失效的时间 89 77.6. 设置MIME响应类型 89 77.7. 设置tomcat的默认访问页面 89 77.8. 设置tomcat管理用户 89 77.9. 附录 90 78. websphere 90 79. 常见异常 90 79.1. nullpointerexception 90 79.2. classnotfoundexception 90 79.3. arithmeticexception 90 79.4. arrayindexoutofboundsexception 91 79.5. illegalargumentexception 91 79.6. illegalaccessexception 91 80. 异常机制 97 81. 异常的分类 97 82. 异常的使用方法 98 83. JAVA代码查错 101 83.1. 判断 101 83.2. 判断 102 83.3. 判断 102 83.4. 判断 102 83.5. 判断 102 83.6. 判断 103 83.7. 判断 103 83.8. 判断 103 83.9. 判断 104 83.10. 判断 104 83.11. 判断 105 84. 编码 106 84.1. 写出一个单例模式 106 84.2. 我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 106 84.3. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 107 84.4. 现在输入n个数字,以逗号”,”分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset 108 84.5. 金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 109 84.6. 内部类的实现方式? 112 84.7. 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”。 113 84.8. 将一个键盘输入的数字转化成中文输出(例如:输入1234567,输出:一百二拾三万四千五百六拾七),请用java语言编一段程序实现! 114 84.9. 题目1:用1、2、2、3、4、5这六个数字,用java写一个main函数,打印出所有不同的排列,如:512234、412345等,要求:"4"不能在第三位,"3"与"5"不能相连. 117 84.10. 写一个方法,实现字符串的反转,如:输入abc,输出cba 119 84.11. 请用java写二叉树算法,实现添加数据形成二叉树功能,并以先序的方式打印出来. 119 84.12. 请写一个java程序实现线程连接池功能? 122 84.13. 编一段代码,实现在控制台输入一组数字后,排序后在控制台输出; 122 84.14. 列出某文件夹下的所有文件; 123 84.15. java调用系统命令实现删除文件的操作; 123 84.16. java实现从文件中一次读出一个字符的操作; 124 84.17. 列出一些控制流程的方法; 124 84.18. 编写了一个服务器端的程序实现在客户端输入字符然后在控制台上显示,直到输入"END"为止,让你写出客户端的程序; 124 84.19. 用jdom解析xml文件时如何解决中文问题?如何解析? 127 84.20. Jquery ajax 实现异步 129
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值