1.Java 面向对象有哪些特征
封装、继承、多态。
2.short s1=1;s1=s1+1 有什么错?short s1=1;s1+=1;有什么错?
第一个是有错的,short 在内存中占 2 个字节,而整数 1 默认为 int 型占 4 个字节,s1+1 其实这个时候就向上转型为 int 类型了,因此第一行代码必须强转才行。第二个之所以可以是以为这句话翻译过来就是 s1++,也就是 short 类型的数据自身加增 1,因此不会有问题
3.静态成员类、非静态成员类有什么区别?什么是匿名内部类?
静态成员类相当于外部类的静态成员,是外部类在加载的时候进行初始化,非静态成员类相当于外部类的普通成员,当外部类创建对象的时候才会初始化。匿名内部一般都是在方法里面直接通过 newClassName(){};形式的类。比如我们 new Thread(new Runnable(){}).start();就用到了匿名内部类。
4.abstract class 和 interface 有什么区别?
前者是抽象类,可以有抽象方法,也可以没有。后者是接口,只能有抽象方法。他们都不能创建对象,需要被继承
5.ArrayList 是不是线程安全的?如果不是,如何是 ArrayList 成为线程安全的?
不安全的。可以使用 Collections.synchronizedList(list)将 list 变为线程安全的。
6.以下两条语句返回值为 true 的有:A:“yiyaowang”==“yiyaowang”; B: “yiyaowang”.equals(new String(“yiyaowang”));
第一个返回 true,都是字符串常量,存储在字符串常量池中,且只有一份。第二个返回 true,用equals 比较的是字符串内容。
7.当一个对象被当做参数传递到一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
java 中只有值传递,没有引用传递。这里的引用本身就是值,传递的是引用这个值。
8.请描述下 JVM 加载 class 文件的原理机制
JVM 加载 class 是动态性的,也就是当“需要”的时候才会加载,这是也是为节约 JVM 内存来考虑的。同时 JVM 的类加载是父类委托机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其 Parent 使用其搜索路径帮忙载入,如果 Parent 找不到,那么才由自己依照自己的搜索路径搜索类”。
9.ArrayList、HashSet、HashMap 源码
每个方法都没有加锁,显然都是线程不安全的
10.如何将一个 "java 对象"序列化到文件里
在 java 中能够被序列化的类必须先实现 Serializable 接口,该接口没有任何抽象方法只是起到一个标记作用。
//对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new
FileOutputStream(new File("D://obj")));
objectOutputStream.writeObject(new User("zhangsan", 100));
objectOutputStream.close();
//对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(new
FileInputStream(new File("D://obj")));
User user = (User)objectInputStream.readObject();
System.out.println(user);
objectInputStream.close();
11.字符和字节
底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向 IO 设别写入或读取字符串提供了一点点方便。字符向字节转换时,要注意编码的问题,因为字符串转成字节数组,其实是转成该字符的某种编码的字节形式,读取也是反之的道理。
12.HashMap 排序题
13.abstract class 和 interface 有什么区别?
含有 abstract 修饰符的 class 即为抽象类,abstract 类不能创建的实例对象。含有 abstract 方法的类必须
定义为 abstract class,abstract class 类中的方法不必是抽象的。abstract class 类中定义抽象方法必须在具体
(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果的子类没有实现抽象父类中的所
有抽象方法,那么子类也必须定义为 abstract 类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定
义默认为 public abstract 类型,接口中的成员变量类型默认为 public static final。
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方
法。
4. 抽象类中的抽象方法的访问类型可以是 public,protected 和(默认类型,虽然
eclipse 下不报错,但应该也不行),但接口中的抽象方法只能是 public 类型的,并且默认即为 public
abstract 类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口
中定义的变量只能是 public static final 类型,并且默认即为 public static final 类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
下面接着再说说两者在应用上的区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实
现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项
目的所有 Servlet 类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象
的基类,让所有的 Servlet 都继承这个抽象基类,在抽象基类的 service 方法中完成权限判断、记录访问日
志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码,伪代码如下:
public abstract class BaseServlet extends HttpServlet{
public final void service(HttpServletRequest request, HttpServletResponse response) throws
IOExcetion,ServletException {
记录访问日志
进行权限判断
if(具有权限){
try{
doService(request,response);
}
catch(Excetpion e) {
记录异常信息
}
}
}
protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws
IOExcetion,ServletException;
//注意访问权限定义成 protected,显得既专业,又严谨,因为它是专门给子类用的
}
public class MyServlet1 extends BaseServlet
{
protected void doService(HttpServletRequest request, HttpServletResponse response) throws
IOExcetion,ServletException
{
本 Servlet 只处理的具体业务逻辑代码
}
}
父类方法中间的某段代码不确定,留给子类干,就用模板方法设计模式。
备注:这道题的思路是先从总体解释抽象类和接口的基本概念,然后再比较两者的语法细节,最后再
说两者的应用区别。比较两者语法细节区别的条理是:先从一个类中的构造方法、普通成员变量和方法(包
括抽象方法),静态变量和方法,继承性等 6 个方面逐一去比较回答,接着从第三者继承的角度的回答,特
别是最后用了一个典型的例子来展现自己深厚的技术功底。
14.ArrayList 和 Vector 的区别
ArrayList 与 Vector 底层都是基于数组的,因此它们的实现代码也大致相似。区别在于
Vector 是一个古老的集合,Vector 还有一个特征:它是线程安全的,因此性能比较差。而 ArrayList 并不是线程安
全的,因此性能较好。实际上即使需要在多线程环境下使用 List 集合,也应该选择 ArrayList,
而不是 Vector,因为 Java 还提供了一个 Collections 工具类,它可以把 ArrayList 包装成线程
安全的集合类,例如如下代码:
List list = Collections.synchronizedList(new ArrayList());
15.Java中实现线程阻塞的方法:
(1)线程睡眠:Thread.sleep (long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
(2)线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait() 一样。wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用.
(3)线程礼让,Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.
(4)线程自闭,join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
16.wait和sleep方法的区别?