一,单例模式的[懒汉式]和[饿汉式]

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

  • 饿汉式:多线程安全的,这种方式比较常用,但容易产生垃圾对象,优点是没有加锁执行效率会提高,缺点是类加载时就初始化,浪费内存。
    类一旦加载就把单例初始化完成,保证getInstance的时候,单例是已经存在的了。

  • 饿汉式:非线程安全的,这种方式是最基本的实现方式,因为没有加锁 synchronized,所以严格意义上它并不算单例模式。为了实现线程安全需要加锁synchronized保证单例,但加锁会影响效率。
    懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例

饿汉式

public class SingletonEH {
    /**
     *是否 Lazy 初始化:否
     *是否多线程安全:是
     *实现难度:易
     *描述:这种方式比较常用,但容易产生垃圾对象。
     *优点:没有加锁,执行效率会提高。
     *缺点:类加载时就初始化,浪费内存。
     *它基于 classloder 机制避免了多线程的同步问题,
     * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
    * 在单例模式中大多数都是调用 getInstance 方法,
     * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
     * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
     */
    private static SingletonEH instance = new SingletonEH();
    private SingletonEH (){}
    public static SingletonEH getInstance() {
        System.out.println("instance:"+instance);
        System.out.println("加载饿汉式....");
        return instance;
    }
}

懒汉式-非线程安全

public class SingletonLH {
    /**
     *是否 Lazy 初始化:是
     *是否多线程安全:否
     *实现难度:易
     *描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
     *这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
     */
    private static SingletonLH instance;
    private SingletonLH (){}

    public static SingletonLH getInstance() {
        if (instance == null) {
            instance = new SingletonLH();
        }
        return instance;
    }
}

懒汉式-线程安全

public class SingletonLHsyn {
    /**
     *是否 Lazy 初始化:是
     *是否多线程安全:是
     *实现难度:易
     *描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
     *优点:第一次调用才初始化,避免内存浪费。
     *缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
     *getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
     */
    private static SingletonLHsyn instance;
    private SingletonLHsyn (){}
    public static synchronized SingletonLHsyn getInstance() {
        if (instance == null) {
            instance = new SingletonLHsyn();
        }
        return instance;
    }
}

饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。

而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。


二,List去重,几种方式?

比较常用的List去重复方式有如下:

新建一个list数组:

List list = new ArrayList(); 
list.add(26); 
list.add(39); 
list.add(5); 
list.add(40); 
list.add(39); 
list.add(25); 
System.out.println(list); 

方法一:使用java8新特性stream进行List去重复,java8中有collectingAndThen;

List newList = list.stream().distinct().collect(Collectors.toList()); 
System.out.println(“java8新特性stream去重:”+newList); 
list.add(39); 

方法二:常规遍历List去重(嵌套for循环),循环list中的所有元素然后删除重复

for (int i = 0; i < list.size(); i++) { 
   for (int j = 0; j < list.size(); j++) { 
      if(i!=j&&list.get(i)==list.get(j)) { 
         list.remove(list.get(j)); 
      } 
   } 
} 

方法三:List和Set互转 - (Set集合本身是无序不可重复的)

public static List removeDuplicate(List list) {   
    HashSet h = new HashSet(list);   
    list.clear();   
    list.addAll(h);   
    return list;   
}   

三,Collection和Collections的区别?

前者Conllection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法;Conllection接口在Java类库中有很多具体的实现。

简单说Conllection就是抽取各种集合的主要功能并作出统一的行为规范。

后者Collections是一个包装类,此类不能实例化,就想工具类服务于Conllection框架,它包含有各种各样的又关集合操作的静态多态方法。使用方式:类名.方法名()。

简单来说Collections就是一个集合工具类,里面有各种集合的方法用来实现对各种集合的操作。


四,final,finally, e finalize 区别?

简单区别
final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。

finally是异常处理语句结构的一部分,表示总是执行。

finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

中等区别
虽然这个单词在Java中都存在,但是并没太多关联:

final:java中的关键字,修饰符。
A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
  1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
  2)被声明final的方法只能使用,不能重载。
  
finally:java的一种异常处理机制。
  finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
  
finalize:Java中的一个方法名。
Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。


五,流是什么?

一切有序的数据都叫流;流是对数据传输的总称或抽象;流的本质是数据传输。
缓冲流,推回流,字节流,字符流,管道流(最为特殊)。
注: 字节,字符,缓冲是统称,并不是指一种特别的流。推回流是按照缓存大小读取的时候,可以把任意有序数据推回。

流的类型:↓

流的方向
按流的方向 输入流OutputStream 和 输出流InputStream
按处理数据单位分 字节流 和字符流
按实现功能 节点流 和 处理流

六,重载Overloading 和 重写Ovriding ?

方法重写(0veriding)
在Java程序中,类的继承关系可以产生一个子类,子类继承父类,它具备了父类所有的特征,继承了父类所有的方法和变量。
子类可以定义新的特征,当子类需要修改父类的一些方法进行扩展,增大功能,程序设计者常常把这样的一种操作方法称为重写,也叫称为覆写或覆盖。
重写是建立在继承关系上,也可以覆盖继承父类的方法。

在重写方法时,需要遵循以下的规则:
(一) 父类方法的参数列表必须完全与被子类重写的方法的参数列表相同,否则不能称其为重写而是重载。
(二) 父类的返回类型必须与被子类重写的方法返回类型相同,否则不能称其为重写而是重载。…
(三) Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限
(四) 由于父类的访问权限修饰符的限制一定要大于被子类重写方法的访问权限修饰符,而private权限最小。(五) 在继承过程中如果父类当中的方法抛出异常,那么在子类中重写父类的该方法时,也要抛出异常,而且抛出的异常不能多于父类中抛出的异常(可以等于父类中抛出的异常)。

方法重载(Overloading)

方法重载是让类以统一的方式处理不同类型数据的一种手段。调用方法时通过传递给它们的不同个数和类型的参数来决定具体使用哪个方法,这就是多态性。
所谓方法重载是指在一个类中,多个方法的方法名相同,但是参数列表不同。参数列表不同指的是参数个数、参数类型或者参数的顺序不同。

在使用重载要注意以下的几点:
1.在使用重载时只能通过不同的参数列表,必须具有不同的参数列表。
2.不能通过访问权限、返回类型、抛出的异常进行重载。
3.方法的异常类型和数目不会对重载造成影响。
4.可以有不同的返回类型,只要参数列表不同就可以了。
5.可以有不同的访问修饰符。
6.可以抛出不同的异常。

如图:
Java面试题总汇(一)

七,三大集合:List、Map、Set 的区别与联系?

1、结构特点

List:中存储的数据是有顺序的,并且值允许重复;是存储单列数据的集合

Map:中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;是存储键值对这样的双列数据的集合。

Set:中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的)。是存储单列数据的集合。

2、实现类

List接口有三个实现类:

LinkedList 基于链表实现,链表内存是散列的,增删快,查找慢;
ArrayList 基于数组实现,非线程安全,效率高,增删慢,查找快;
Vector 基于数组实现,线程安全,效率低,增删慢,查找慢;

Map接口有四个实现类:

HashMap 是线程不安全的,HashMap 是一个接口,是 Map的一个子接口,是将键映射到值得对象,不允许键值重复,允许空键和空值;由于非线程安全, HashMap的效率要较 HashTable 的效率高一些. (基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null 键;)
HashTable HashTable 是线程安全的一个集合,不允许 null 值作为一个 key 值或者 Value 值; HashTable 是 sychronize(同步化),多个线程访问时不需要自己为它的方法实现同步,而 HashMap 在被多个线程访问的时候需要自己为它的方法实现同步.(线程安全,低效,不支持 null 值和 null 键;)
LinkedHashMap 是 HashMap 的一个子类,保存了记录的插入顺序;
SortMap TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序

Set接口有两个实现类:

HashSet 底层是由 Hash Map 实现,不允许集合中有重复的值,使用该方式时需要重写 equals()和 hash Code()方法;
LinkedHashSet 继承于 HashSet,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMap

3、List、Map、Set的区别

List :集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get(i)方法来获取集合中的元素;

Map :中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复;

Set :集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如 Tree Set 类,可以按照默认顺序,也可以通过实现 Java.util.Comparator< Type >接口来自定义排序方式。


八,Char型变量中能不能存储一个中文汉字?

在Java中,char类型占2个字节,而且Java默认采用Unicode编码,以个Unicode码是16位,所以一个Unicode码占两个字节,Java中无论汉子还是英文字母都是用Unicode编码来表示的。所以,在Java中,char类型变量可以存储一个中文汉字。


九,float型 float f=3.4 是否正确?

不正确。精度不准确,应该用强制类型转换,如下所示:float f=(float)3.4 或float f = 3.4f
在java里面,没小数点的默认是int,有小数点的默认是 double;


十,Error 和 Exception 区别?

首先,Error类和Exception类都是继承Throwable类

Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

Error和Exception就像是水池和水池里的水的区别
  “水池”,就是代码正常运行的外部环境,如果水池崩溃(系统崩溃),或者池水溢出(内存溢出)等,这些都是跟水池外部环境有关。这些就是java中的error
  “水池里的水”,就是正常运行的代码,水污染了、有杂质了,浑浊了,这些影响水质的因素就是Exception。

相关文章: