Java基础面试题

1,java两个对象的比较,Java中equals和==之间的区别

  1. 如果是基本类型比较,那么只能用==来比较,不能用equals。

  2. 对于基本类型的包装类型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的

  3. “==”运算符用于比较两个变量的值是否相等,equals()用于比较两个对象中的内容是否一样

  4. “==”操作符用于比较我们引用数据的类型的变量的值是否相等,那么equals()比较两个引用变量所指对象的内容是否相等

2,java重载和重写的区别,那个是运行时多态,那个是编译时多态,那个静态绑定,那个是动态绑定。

  1. 方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式,

  2. 重写:方法名参数都一样;重载:方法名相同,参数不同

  3. 在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定;另一种就是动态绑定,也叫后期绑定

  4. 静态绑定发生在编译时期,动态绑定发生在运行时;静态绑定使用类信息来完成,而动态绑定则需要使用对象信息来完成

  5. 重载的方法是用静态绑定完成,而重写的方法则使用动态绑定完成,

  6. 根据何时确定执行多态方法中的哪一个,多态分为两种情况:编译时多态和运行时多态。如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态。

  7. 方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。

  8. 方法重写表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。例如,以下声明p、m引用本类实例,调用toString()方法是编译时多态。

3,hashMap和HashTable的区别

  1. 继承的父类不同,Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。

  2. 线程安全性不同,Hashtable 中的方法是Synchronize的

  3. 是否提供contains方法,HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。
      Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同、

  4. key和value是否允许null值, Hashtable中,key和value都不允许出现null值,HashMap中,null可以作为键,这样的键只有一个。

  5. hash值不同,哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值

  6. 内部实现使用的数组初始化和扩容方式不同, HashTable在不指定容量的情况下的默认容量为11,而HashMap为16

5,接口和抽象类

  1. 接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。

  2. 抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)接口可继承接口,并可多继承接口,但类只能单根继承抽象类可以实现接口,而且可以只实现部分接口

  3. 抽象类可以继承普通类

6.Java中,char型变量中能不能存储一个中文汉字,为什么?

  1. char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。

7,能不能自己写个类,也叫Java.util.String

  1. 可以,但是即使你写了这个类,也没有用。这个问题涉及到加载器的委托机制,

  2. 在类加载器中,BootStrap是顶层父类,ExtClassLoader是BootStrap类的子类,ExtClassLoader又是AppClassLoader的父类这里以java.lang.String为例,

  3. 当我是使用到这个类时,Java虚拟机会将java.lang.String类的字节码加载到内存中。为什么只加载系统通过的java.lang.String类而不加载用户自定义的java.lang.String类呢?

  4. 因加载某个类时,优先使用父类加载器加载需要使用的类。如果我们自定义了java.lang.String这个类,加载该自定义的String类,

  5. 该自定义String类使用的加载器是AppClassLoader,根据优先使用父类加载器原理,AppClassLoader加载器的父类为ExtClassLoader,

  6. 所以这时加载String使用的类加载器是ExtClassLoader,但是类加载器ExtClassLoader在jre/lib/ext目录下没有找到String.class类。

  7. 然后使用ExtClassLoader父类的加载器BootStrap,父类加载器BootStrap在JRE/lib目录的rt.jar找到了String.class,将其加载到内存中。这就是类加载器的委托机制。所以,用户自定义的java.lang.String不被加载,也就是不会被使用。

 8,java中集合的结构,以及常用的集合类,各自的特点是什么?

1、List、Set是存储单列的数据集合,都继承与Collection接口。
2、Map是存储键值对这样的双列数据的集合,是个独立接口。
4、List中存储的数据是有序的,可以是重复的。
5、Set中存储的数据是无序的,且不允许重复。
6、Map中存储的数据是无序的,他的键是不允许重复的,值是可以重复的。
List的接口有三个实现类。
   1.1 ArrayList
   优点: 底层数据结构是数组,查询快,增删慢。
   缺点: 线程不安全(一般不考虑到线程的安全因素,用Arraylist效率比较高)
   1.2 LinkedList
   优点: 底层数据结构是链表,增删快,查询慢。
   缺点: 线程不安全。
   1.3 Vector
   优点: 底层数据结构是数组,查询快,增删慢。线程安全。
   缺点: 效率低。
Set接口有三个实现类
   2.1 HashSet
   为快速查找而设计的Set,依赖hashCode()和equals()方法保证元素的唯一性。如果没有其他限制,这就是我们的默认选择,因为他对速度进行了优化。
   2.2 TreeSet
   保证元素处于排序状态,底层为树结构,元素必须实现Comparable接口。
   2.3 LinkedHashSet
   具有HsahSet的查询速度,内部使用链表维护元素的顺序(插入的次序)在使用迭代器遍历Set时,结果会按元素插入的次序显示。元素也必须定义hashCode()方法。
Map接口有6个实现类。
   3.1 HashMap
   Map基于散列表的实现(取代了Hashtable)。插入和查询"键值对"的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器性能。
   3.2 LinkedHashMap
   类似于HashMap,但是迭代遍历他时,取得的"键值对"的顺序是其插入次序,或是最近最少使用的(LRU)的次序。只比HashMap慢一点;而在迭代访问时反而更快,因为他使用链表维护内部次序。
   3.3 TreeMap
   是SortedMap现阶段的唯一实现。基于红黑树实现。查看"键"或者"键值对"时,他们会被排序(次序由Comparable或Comparator j决定)。TreeMap的特点在于,所得到的结果是经过排序的。
   3.4 WeakHashMap
   弱键(weak key)映射,允许释放映射所指的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向某个"键",则此"键"可以被垃圾回收器回收。
   3.5 ConcurrentHashMap
   一种线程安全的Map。
   3.6 IdentityHashMap
   使用"=="代替"equals()"对键进行比较的散列映射,专门解决特殊问题而设计出的。

9,java是如何解决线程安全问题的,有几种方式?有什么不同?

  1. 使用同步代码块 : synchronized (锁对象) { 可能会产生线程安全问题的代码 }

  2. 同步方法:在方法声明上加上synchronized同步方法中的锁对象是 this,静态同步方法: 在方法声明上加上static synchronized,静态同步方法中的锁对象是 类名.class

  3. 同步锁:Lock接口提供了与synchronized关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。使用Lock一定要在try{}cahch中,在finally中释放

10,synchronized和lock的区别?

  1. 异常时锁的释放:synchronized修饰的代码在执行异常时,jdk会自动释放线程占有的锁,不需要程序员去控制释放锁,因此不会导致死锁现象发生;但是,当Lock发生异常时,如果程序没有通过unLock()去释放锁,则很可能造成死锁现象,因此Lock一般都是在finally块中释放锁。

  2. 锁的中断:Lock可以让等待锁的线程响应中断处理,如tryLock(long time, TimeUnit unit) ,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够中断,程序员无法控制

  3. 用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了

11,写一个线程安全的单例模式?

//饥饿模式
public final class EagerSingleton{
    private static EagerSingleton singObj = new EagerSingleton();

    private EagerSingleton(){
    }

    public static EagerSingleton getSingleInstance(){
       return singObj;
    }
}

//懒汉模式 public final class LazySingleton{   private static LazySingleton singObj = null;   private LazySingleton(){   }
  
public static LazySingleton getSingleInstance(){     if(null == singObj ){

      singObj = new LazySingleton();       return singObj;     } }
//懒汉模式加Synchronized public final class ThreadSafeSingleton{   private static ThreadSafeSingleton singObj = null;   private ThreadSafeSingleton(){   }
  
public static Synchronized ThreadSafeSingleton getSingleInstance(){     if(null == singObj ){

      singObj = new ThreadSafeSingleton();       return singObj;     } }

12,sleep()和wait()方法的异同?

  1. 对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中

  2. sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。

  3. 当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。

13,创建线程的四种方式?

  1. 继承Thread类创建线程

  2. 实现Runnable接口创建线程

  3. 使用Callable和Future创建线程

  4. 使用线程池例如用Executor框架

 14,类的加载机制

  加载   连接(检验  准备  解析) 初始化

  加载就是把.class加载到内存中     验证文件的格式  为类的静态变量分配内存 把类的符号引用转换成直接引用  初始化 静态变量设置正确的初始值

posted @ 2020-08-20 15:38  panda's  阅读(106)  评论(0编辑  收藏  举报