关于java面试问答

一.Java中的String,StringBuilder,StringBuffer三者的区别

1.从创建的速度来看,是stringbuilder>stringBuffer>String.

      String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

1 String str="abc";
2 System.out.println(str);
3 str=str+"de";
4 System.out.println(str);

如果运行这段代码会发现先输出“abc”,然后又输出“abcde”。其实质为:JVM先创建一个abc的str,然后又创建一个str,把旧的和de相加,放到新的str里面,然后旧的str会被垃圾回收机制回收。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。

2.线程安全性:StringBuilder是线程不安全的,而StringBuffer是线程安全的

stringbuffer多线程调用时,会有大量的同步关键字:synchronized。

二、java中的集合

1.map接口:HashMap和TreeMap

什么是map?在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。特点:HashMap是无序的集合而TreeMap则是有序的集合,但是都不是线程安全的。

影像HashMap 的速度因子是容量和负载因子

2.关于map集合

map里面的几个重要方法:put(k,v),将键值对放在map里面;remove(k)将对应的键值对删除;map.keyset(),是将map里面的K值全部存放到一个set集合里面。其中set集合是无序集合,将会在下面讲到。其中,map.entry(),这是一个类,这个类类似于map,一样是键值对。eg:Map.Entry<String,String> mapentry : map.entrySet   。

          System.out.println("通过Map.entrySet使用iterator遍历key和value:");
          Iterator<Map.Entry<String, String>> its = map.entrySet().iterator();//iterator为迭代器  简单的理解为,把entrySet里面的元素放在这个its里面。便于操作
          while (its.hasNext()) {//判断是不是还存在不存在值
           Map.Entry<String, String> entry = its.next();
           System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
           }

深入理解hashmap:

1).hashmap的数据结构是什么?实质上,他是一个数组+链表。其中K是数组,而V则是与K相关的链表。首先,Hashmap是实现的Map.entry,初始化容量是16,负载因子是0.75,如果超过了0.75则产生扩容(resize)机制。resize就是把之前的这个数组容量重新扩大,但是在扩大的过程中,需要对里面的数据进行重新排列。而根据里面数据的不同,所以创建的大小也是不同的,反正就是要控制在0.75以内。

2).为什么hashmap线程不安全?在进行put操作的时候,线程A.B都同时对同一个数组位置调用addEntry,两个线程会同时得到现在的头结点,然后A写入新的头结点之后,B也写入新的头结点,那B的写入操作就会覆盖A的写入操作造成A的写入操作丢失。在进行扩容的时候,因为是把头尾相反的指向,所以不安全。见:https://juejin.im/post/5a66a08d5188253dc3321da0

为了在高并发的情况下正常操作,该使用什么?ConcurrentHashmap!为什么hashmap并不是线程安全的呢?因为他并没加上锁。而为什么大多数都是用的ConcurrentHashmap,而不是hashtable,因为ConcurrentHashmap是针对部分值,意思就是他只是锁了一部分表而不是一张表,而HashTable是锁的一张表。那么,在面对很多人同时访问的时候,hashtable就会让别的线程等待,浪费了大量的时间。而ConcurrentHashmap则采用的是分段锁,这样的话,就不会造成资源的浪费。

ConcurrentHashmap中的分段锁称为Segment,每一个Segment据拥有一个内部锁。但是在需要扫描一些整个map的方法,比如:size();containsValue()这类方法时,就只能是特殊的实现。虽然,ConcurrentHashmap被认为是线程安全的,但是在实际上,操作起来很有难度,原因是在于increase,这是操作的是一个ConcurrentHashmap对象,有可能出现覆盖。所以我们就采用CAS操作来避免这个问题。CAS:比较后交换。当我们要进行添加的时候,先得到位置V,然后经过操作得到V的旧值A,然后在将A改为B的过程中,如果V的地址不是A,就失败。

3).hashtable和hashmap 的区别?hashmap支持key为null,但是hashtable不支持key或者value为空;hashtable是线程安全的,而hashmap则不是;hashmap的扩容是*2,hashtable是*2+1;

关于Treemap的了解:

1).treemap是基于红黑树进行实现的,不具有调优选项,处于平衡状态。问:什么是红黑树? 红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。五大特性是?每个节点都只能是红色或者黑色;根节点是黑色;每个叶节点(NIL节点,空节点)是黑色的;如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点;从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。TreeMap的新增:从根节点开始检索-->与当前的节点进行比较,如果是大则在右边,小就在左边-->重复2找到合适的叶子节点-->找到正确的位置后插入-->对二叉树进行平衡(包括:左旋,右旋,着色着三个步骤)。TreeMap 的删除:找到被删除的节点D的子节点C,用C来代替D,然后直接删除C。C的规则:右分支最左边,左分支最右边。

TreeMap和HashMap的区别和联系?两者都不是线程安全的。其中TreeMap是基于二叉树实现,没有调优选项,总是处在平衡状态;HashMap是基于hash表的实现,可以对初始容量和负载因子进行调优;TreeMap是有序的,HashMap是无序的。总的来说,HashMap适用于在Map中插入,删除元素;而TreeMap则是适用于按照一定的顺序遍历K。

3.关于Collection集合:List和Set,Vector

List集合:有序性,元素都是有索引的,元素是可以重复的。

Set集合:无序性(存储顺序和取出顺序不一致),元素不能重复,所以必须保证元素的唯一性。

1).ArrayList和LinkedList和Vector的区别:从数据结构来说:ArrayList的数据结构是动态数组,LinkedList的数组结构是Link(链表),Vector的数据饥结构也是数组;从效率来说:ArrayList插入、删除数组很慢,LinkedList插入、删除数据快;ArrayList定位数组非常快,LinkedList定位慢,Vector和ArrayList差不多;从线程安全性来说:只有Vector是线程安全的;从扩容来说:Vector每次扩容是之前的2倍,而ArrayList只是1.5倍,两者的初始容量都是10。

2).使用场景:需要考虑到线程安全的-->Vector;需要快速插入的-->LinkedList;需要快读访问的-->ArrayList

3).HashSet和LinkedHashSet和TreeSet 的区别?TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件

安全失败fail-safe:你在迭代的时候会去底层集合做一个拷贝,所以你在修改上层集合的时候是不会受影响的,不会抛出ConcurrentModification异常。 
在java.util.concurrent包下的全是安全失败的。

Final在java中的作用

Final可以修饰类,修饰方法,修饰变量。
修饰的类叫最终类。该类不能被继承。
修饰的方法不能被重写。
修饰的变量叫常量,常量必须初始化,一旦初始化后,常量的值不能发生改变

重载与重写

重写:重写是子类对父类的允许访问方法的实现过程进行重新编写,返回值和形式参数都不会发生任何变化。即外壳不变,核心改变。

重写的几大规则:参数列表、返回类型必须和被重写的一致;声明为final和static的方法不能被重写;构造方法不能被重写;父类的成员方法只能被它的子类重写;

public static void main( String[] args )
    {
        Animals a=new Animals();
        a.call();
        Animals bAnimals=new Cat();
        bAnimals.call();      
    }

public class Animals {
    public void call() {
        System.out.println("这是全部动物的叫声");
    }
}

public class Cat extends Animals {    
    public void call() {
        System.out.println("这是猫在叫");    
    }
}

public class Cat extends Animals {    
    @Override
    public void call() {
        super.call();
        System.out.println("这是猫在叫");    
    }
}

重载:是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法都必须有一个独一无二的参数类型列表。最常用的就是构造器的重载。

重载规则:被重载的必须改变参数列表;被重载的方法可以改变修饰符和返回类型;方法能在同一个类或者子类里面被重载;无法以返回值类型作为重载函数的区分标准。

public class App 
{
    public int overloadtest() {
        return 0;
    }
    public int overloadtest(int a) {
        return a ;
    }    
    public String overloadtest(String aString) {
        return aString;
    }
    public static void main( String[] args )
    {
        App app=new App();
        System.out.println(app.overloadtest());
        System.out.println(app.overloadtest("hello"));
        System.out.println(app.overloadtest(6));    
    }
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值