java面试容易错的基础知识

1、float f=3.4;是否正确
答:不正确;3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。

    public static void main(String[] args) {
        float a=(float) 3.4;
        float b=3.4F;
    }

2、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上
答:在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

enum Color
    {
        RED, GREEN, BLUE;
    }
    
    public static void main(String[] args) {
        float a=(float) 3.4;
        float b=3.4F;
        int s=1;
        //double s=2.0;
        //String s="1";
        //float s=1.1F;
         long l1=111; 
         switch (l1){
             
         }

        switch (Color.BLUE){

            default:
                throw new IllegalStateException("Unexpected value: " + s);
        }

    }

3、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

public static void main(String[] args) {
       short s1=1;
       //s1=s1+1;//编译错误
       s1=(short)(s1+1);
       System.out.println(s1);
       short s2=1;
       s2+=1;
       System.out.println(s2);
    }

4、在 Java 中,如何跳出当前的多重嵌套循环

public static void main(String[] args) {
     ok:
        for(int i=0;i<10;i++){
            for(int j=0;i<10;j++){
                System.out.println("i="+i+",j="+j);
                if(j==5){
                    break ok;
                }
            }
        }
    }

5、面向对象五大基本原则是什么?
单一职责原则SRP(Single Responsibility Principle)
类的功能要单一,不能包罗万象,跟杂货铺似的。
开放封闭原则OCP(Open-Close Principle)
一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
里式替换原则LSP(the Liskov Substitution Principle LSP)
子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
依赖倒置原则DIP(the Dependency Inversion Principle DIP)
高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
接口分离原则ISP(the Interface Segregation Principle ISP)
设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。
6、抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
7、在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。


public class Father {
//    public Father() {
//        System.out.println("不做事情的构造方法");
//    }
    public  Father(String name){
        System.out.println("这是一个有名字的爸爸"+name);
    }
}
public class Son extends Father{

    public Son(String name) {
        super(name);
    }
}

8、内部类
将一个类定义在另一个类的内部,就叫做内部类,内部类是类的一个属性。内部类的分类:成员内部类,局部内部类,匿名内部类,静态内部类。
静态内部类:
定义在类内部的静态类,叫做静态内部类,


public class Outer {
    private static int radius=1;
    private int numner=10;
    //静态内部类
    static  class staticInnerclass{
        public  int  num=100;
        public void visit(){
            //numner++; 静态内部类不能访问外部的非静态方法
            num++;
            System.out.println("visit outer static veriable"+radius);
        }
    }
    //成员内部类
    class MemberClass{
        public void visit(){
            System.out.println("visit outer static variable:"+radius);
            System.out.println("cisit outer veriable"+numner);
        }
    }
    //局部内部类
    //定义在方法中的内部类,叫做局部内部类
    public void portionFunctionClass(){
        class FunctionClass{
            private  void fun(){
                System.out.println("visit outer static variable:"+radius);
                System.out.println("cisit outer veriable"+numner);
            }
        }
        FunctionClass functionClass=new FunctionClass();
        functionClass.fun();
    }

    /**
     * 匿名内部类就是没有名字的内部类
     * 匿名内部类必须继承一个抽象类或者实现一个接口
     * 匿名内部类不能定义任何静态成员和静态方法
     * 当所有的方法的形参需要被匿名内部类使用时,必须声明为final
     * 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
     * 内部类的优点:
     * 1、一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据
     * 2、内部类部位同一个包的其他类所见,具有很好的封装性
     * 3、内部类有效实现了多重继承,优化java单继承的缺陷
     * 4、匿名内部类可以方便的定义回调。
     *
     * @param i
     */
    private void anonymousCalss(final int i){
        new Service(){
            @Override
            public void publicServiceMethod() {
                for(int j=0;j<i;j++){
                    System.out.println("匿名内部类"+i);
                }
            }
        };

    }

    private int age =12;
    class Inner{
        private int age=13;
        public void print(){
            int age=14;
            System.out.println("局部变量:"+age);
            System.out.println("内部类变量:"+this.age);
            System.out.println("内部类变量:"+Outer.this.age);
        }
    }


    interface  Service{
        void publicServiceMethod();
    }


    public static void main(String[] args) {
        //静态内部类的调用方案 new 外部类.讲台内部类()
        Outer.staticInnerclass innerclass=new Outer.staticInnerclass();
        innerclass.visit();
        //静态方法不能调用非静态方法
        //Outer.memberClass memberClass=new Outer.memberClass();
        //成员内部类的调用方法
        Outer outer=new Outer();
        Outer.MemberClass memberClass=outer.new MemberClass();
        memberClass.visit();
        //局部内部类的调用方法
        outer.portionFunctionClass();
        //匿名内部类的调用方法
        outer.anonymousCalss(10);
        //测试局部变量,内部类变量
        Outer.Inner inner=new Outer().new Inner();
        inner.print();
    }
}

9、比较==和equals()的方法


public class TestEquals {
    public static void main(String[] args) {
        String a=new String("ab");
        String b=new String("ab");
        String aa="ab";
        String bb="ab";
        if(aa==bb){
            System.out.println("aa==bb is "+(aa==bb));
        }
        System.out.println("a==b is "+(a==b));
        if(aa.equals(bb)){
            System.out.println("aa.euals(bb) is "+(aa.equals(bb)));
        }
        if(b.equals(b)){
            System.out.println("a.equals(b)="+a.equals(b));
        }
        System.out.println("aa==a="+aa==a);
        System.out.println(" bb==a="+bb==a);
    }
}

10、BIO,NIO,AIO 有什么区别?

BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

11、怎么将list修改为不可以修改

public class TestUnmodifiableCollection {
    public static void main(String[] args) {
        List<String> list =new ArrayList<>();
        list.add("xyz");
        //将list修改为不可以修改的状态
        Collection<String> collection= Collections.unmodifiableCollection(list);
        collection.add("mmm");
        System.out.println(list.size());
    }
}

12、如何边遍历边移除 Collection 中的元素


public class RemoveCollection {
    public static void main(String[] args) {
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(3);
        list.add(7);
        list.add(2);
        list.add(5);

//        for (int i:list) {
//            System.out.println(list.size());
//            list.remove(i);//.ConcurrentModificationException
//
//        }
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
            it.remove();
        }
        System.out.println("list的大小:"+list.size());
    }
}

13、如何实现arrayList和数组之间的转化


/**
 * 优点:
 * ArrayList底层以数组实现,是一种随机访问模式,arrayList实现了randomAccess,查找的时候非常的快
 * ArrayList在顺序添加一个元素的时候非常的方便
 * 缺点:
 * 删除元素的时候,需要做一次元素复制操作,如果要复制的元素很多,那么就会比较的耗费性能
 * 插入的时候也要做一次元素的复制,如果元素很多,那么就会也会比较的耗费性能
 * 适应场景:
 * ArrayList 比较适合顺序添加和随机访问的场景。
 *
 *
 */
public class TestArrayList {
    public static void main(String[] args) {
        //声明arrayList
        ArrayList<String> strList=new ArrayList<String>();
        strList.add("XXXX");

        //将数组转化为arrayList
        String[] strings=new String[]{"2","3","333"};
        List list=Arrays.asList(strings);
        for (int i=0;i<list.size();i++){
            System.out.println("list的值"+list.get(i));
        }

        ArrayList<String> strings1=new ArrayList<>();
        strings1.add("x");
        strings1.add("y");
        strings1.add("z");
        Object[] strarray=strings1.toArray();
        for (Object s:strarray) {
            System.out.println("字符"+s.toString());
        }
    }
}

14、arrayList、linkedlist、vector的区别


public class TestArrayListAndLinkedList {
    public static void main(String[] args) {

        /**
         * arrayList是动态数组的数据结构实现的
         * arrayList比linkedlist在水机访问的时候效率要高
         * arrayList增删需要移动数组的元素及其下标
         *
         */
        ArrayList<String> strings=new ArrayList<>();

        /**
         * linkedList是双向链表的数据结构实现的
         * linkedlist采用的线性的数据存储方式,需要移动指针从前往后依次查找
         * linkedlist在非首尾增加和删除操作,比arraylist效率要高
         * linkedlist的占用空间要比arraylist的多,因为要存储两个引用,一个指向前一个元素,一个指向后一个元素
         * 
         * 共同点:
         * arraylist和linkedlist都是不同步的,不能保证线程的安全。
         */
        LinkedList<String> stringLinkedList=new LinkedList<>();
        stringLinkedList.add("xxx");

        /**
         * arraylist和vector的区别
         * 相同点:两个类都实现了list的接口,list接口集成了collection接口,他们都是有序集合
         * 不同点:
         * vector是线程安全的,arrayList不是线程安全的
         * arraylIst的性能要高于vector
         * 两者都可以动态扩容,vector可以直接扩容1倍,二arrayList一次只增加50%。
         */
        Vector<String> stringVector=new Vector<>();
    }
}

15、arrayList需要在多线程的环境下使用,怎么操作?


/**
 * arraylist因为是线程不安全的,如果需要做线程安全,应该怎么处理?
 * ArrayList 线程不安全,如果遇到多线程的场景,可以通过Collections的synchronizedList方法将其转化
 * 成线程安全的容器后再使用
 *
 */
public class TestSynchronizedList {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        list.add("xxx");
        List<String> synchronizedList= Collections.synchronizedList(list);
        synchronizedList.add("XXXXXX");
        synchronizedList.add("YYYYYY");

        for(int i=0;i< synchronizedList.size();i++){
            System.out.println(synchronizedList.get(i));
        }
    }
}

16、list和set的区别


/**
 * list set 都集成字collection接口
 * List特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,
 * 元素都有索引,常用的实现类有ArrayList和linkedList以及vector。
 * Set特点:一个无序(存入和取出的顺序有可能不一致)容器,不可以存储重复的值,只能存储一个null,必须保证元素
 * 唯一性。Set接口常用实现类是HashSet、linkedHashSet以及treeSet。
 *
 * set和list的对比
 * set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置的变化
 * List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低。
 *
 */
public class TestListAndSet {
    public static void main(String[] args) {
        ArrayList<String> arrayList=new ArrayList<>();
        LinkedList linkedList=new LinkedList();
        Vector vector=new Vector();

        /**
         * HashSet是基于HashMap实现的,HashMap的值存放在HashMap的key上,HashMap的value
         * 统一为present,因此HashSet的实现比较简单,相关HashSet的操作,基本都是直接调用底层的HashMap的相关方法老
         * 来实现的,只是HashSet不允许重复。
         * HashSet是如何检查重复的?HashSet是如何保证数据不可重复的?
         * 向HashSet中add()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles方法比较。
         * HashSet中的add()方法会使用HashMap的put方法
         *
         */
        HashSet hashSet=new HashSet();// map = new HashMap<>();
        hashSet.add("sss");//map.put(e, PRESENT); PRESENT=new Object();
        LinkedHashSet linkedHashSet=new LinkedHashSet();
        TreeSet treeSet=new TreeSet();
    }
}

17、hashcode()方法和equals()方法

/**
 * 1.如果两个对象相等,则hashcode一定也是相同的。
 * 2、两个对象相等,两个equals方法返回true
 * 3、两个对象有相同的hashcode值,他们也不一定是相等的
 * 4、quuals方法被覆盖过,则hashcode方法也必须被覆盖。
 * 5、hasecode()的默认行为是堆上的对象产生的独特值。如果没有重写hashcode(),则该class的两个对象无论如何都不会相等
 * (即使这两个对象指向相同的数据)
 */
public class TestHashCodeAndEquals {
    public static void main(String[] args) {

        String s="s";
        String a="s";
        System.out.println(s.hashCode()==a.hashCode());
    }
}

18、HashSet和HashMap的区别


/**
 * hashset和HashMap的区别
 * 1、hashMap实现了Map接口,hashset实现了set接口
 * 2、hashMap存储的键值对,hashset存储的值
 * 3、hashMap调用的是put方法向Map中加值,而hashset调用add方法向set中加值
 * 4、HashMap相对于HashSet较快,因为它使用唯一的键获取对象,hashset交hashMap来说比较慢。
 */
public class TestHashMapAndHashSet {
    public static void main(String[] args) {
        HashMap<String,String> hashMap=new HashMap<>();
        HashSet<String> hashSet=new HashSet<>();

    }
}

19、blockingqueue 的理解


/**
 * blockingqueue 当队列为空时,会阻塞队列弹出操作,直到队列不为空。当队列满了时,会阻塞入队操作,直到队列不满。
 * 实现的接口:collection,iterable,queue
 * 常用实现类:
 * ArrayBlockingQueue:底层为数组的阻塞队列
 * linkedBlockingDeque:底层为链表的双端阻塞队列
 * linkedBlockingQueue:底层为链表的单端阻塞队列
 * SynchronousQueue:同步队列
 *
 */
public class TestBlockingQueue {
    public static void main(String[] args) {


        BlockingQueue<Integer> blockingQueue=new ArrayBlockingQueue<Integer>(3);

        // add、remove、element 抛出异常
        blockingQueue.add(1);
        blockingQueue.add(2);
        blockingQueue.add(3);
        //如果是容量为3的队列中加入第4个元素,抛出队列已满的异常。
        //blockingQueue.add(4);

        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //在空队列中remove,将会抛出异常
        //System.out.println(blockingQueue.remove());
        //一个null队列,继续调用element对象,获取队列中的值则会抛出异常
        //System.out.println(blockingQueue.element());

        //offer(),poll(),peek() 超出队列容量用offer不会抛出异常,空队列使用poll()也不会抛出异常,空队列使用peek()方法也不会抛出异常
        blockingQueue.offer(1);
        blockingQueue.offer(2);
        blockingQueue.offer(3);
        blockingQueue.offer(4);

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());

        System.out.println(blockingQueue.peek());

        //put take 阻塞等待
        try{
            BlockingQueue<Integer> blockingQueue1=new ArrayBlockingQueue<>(3);
            blockingQueue1.put(1);
            blockingQueue1.put(2);
            blockingQueue1.put(3);
            //blockingQueue1.put(4);//队列已满是,不会被阻塞在这里,直到队列不满为止

            System.out.println(blockingQueue1.take());
            System.out.println(blockingQueue1.take());
            System.out.println(blockingQueue1.take());
            //System.out.println(blockingQueue1.take());//队列为空,会一直阻塞在这里,直到队列不为空为止
        }catch (Exception e){
            e.printStackTrace();
        }
        //因为不能一直阻塞,现在需要设置阻塞超时等待
        testBlockWaitApiWithTimeout();
        //测试同步阻塞队列,用于线程1对1的通信
        testSynchronousQueueDemo();

    }

    /**
     * 如果队列一直阻塞,设置一个超时时间,当超过这个超时时间就会自动等待超时
     */
    public static void testBlockWaitApiWithTimeout(){
        BlockingQueue<Integer> blockingQueue=new ArrayBlockingQueue<>(3);
        try{
            System.out.println(blockingQueue.offer(1,3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.offer(2,3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.offer(3,3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.offer(4,3,TimeUnit.SECONDS));


            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));

        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }

    /**
     * 同步阻塞队列:同步队列添加元素后,就会阻塞当前线程,然后等待其他线程移除该元素后,才会唤醒这个线程,可以用来做线程一对一的线程间的通信
     */
    public static void testSynchronousQueueDemo(){
        SynchronousQueue<Integer> synchronousQueue=new SynchronousQueue<>();
        //启动一个线程,向线程中添加数组
        new Thread(()->{
            try{
                synchronousQueue.put(1);
                synchronousQueue.put(2);
                synchronousQueue.put(3);
            }catch (Exception e){
                e.printStackTrace();
            }
        }).start();
        //启动另外的一个线程从阻塞队列中取出数据
        new Thread(()->{
            try{
                synchronousQueue.take();
                synchronousQueue.take();
                synchronousQueue.take();
            }catch (Exception e){
                e.printStackTrace();
            }
        }).start();
    }

}

运行的结果:

1
2
3
1
2
3
null
null
1
2
3
true
true
true
false
1
2
3
null

20、hashMap,hashTable,concurrentHashMap


/**
 * hashMap的实现原理
 * hashMap是基于hash算法实现的
 * 向hashMap中put元素,利用key的hashcode重新hash计算出当前对象的元素在数组中的下标。
 * hash值相同的key,1)如果key相同,则覆盖原始值 2)如果key不同,则将当前key-value放入链表。
 * JDK1.8对hashMap做了优化,当链表中的节点超过了8个点之后,该链表会转为红黑树来提高查询效率,从原来的o(n)到o(logn)
 * JDK1.8之前使用的是拉链法:将链表和数组结合,也就是创建一个链表数组,数组中每一个都是一个链表,若存在哈希冲突,则将冲突
 * 加到链表中。
 *
 * hashMap 是非线程安全的,多线程时可能会造成数据丢失问题
 *
 * 总结:hashMap使用什么方法来有效的解决hash冲突的
 * 1、使用链地址法(使用赛列表)来链接拥有相同hash值的数据
 * 2、使用2次扰动函数(一次位运算一次异或运算)来降低哈希冲突的概率,使得数据分布更平均
 * 3、引入红黑树进一步降低遍历的时间复杂度,使得遍历更快
 *
 * 使用object作为hashMap的key,应该怎么办?
 * 重写hashCode()和equals()方法
 * 1、重写hashcode()是因为需要计算存储数据的存储位置。
 * 2、重写equls()方法,目的是为了保证key在hash表中唯一性。
 *
 *
 * HashMap与HashTable的区别
 * 1、线程安全:hashMap是非线程安全的,hashTable是线程安全的;HashTable内部的方法基本都经过synchronized修改
 * 如果hashmap要线程安全的话可以使用concurrentHashMap
 * 2、因为线程安全问题,hashmap比hashtable要高,hashtable应用的场景已经非常小了
 * 3、对null key和null value: hashmap只有一个null作为键值,可以有多个null作为value值。而hashtable对put的键值就会
 * 报nullpointerException
 * 
 * 如何决定使用hashMap红寺湖treeMap
 * 对于Map的插入、删除和定位元素这类操作,HashMap是最好的选择,然而,假如你需要对一个有序的key集合进行遍历,treeMap是更好的选择。
 * 
 * HashMap和COncurrentHashMap的区别:
 * 1、ConcurrentHashMap对整个桶数组进行了分割分段(segment),然后在每一个分段上都用了lock锁进行保护,相对于HashTable的synchronized锁
 * 的粒度更精细一些,并发性能更好一些,hashMap没有锁机制,不是线程安全的。
 * 2、HashMap的键值允许为空,但是只有一个null键值,concurrentHashMap都是不允许的。
 * 
 *
 */
public class TestHashMap {

    public static void main(String[] args) {
        HashMap<String,String> hashMap=new HashMap();
        Hashtable<String,String> hashtable=new Hashtable<String, String>();
        ConcurrentHashMap<String,String> concurrentHashMap=new ConcurrentHashMap<>();
    }
}

21、collection和collections的区别


/**
 * collection和collections 有什么区别
 * java.util.collection 是一个集合接口,他提供了对集合对象进行基本操作的通用接口方法。提供了对集合对象进行基本操作
 * 的通用接口方法。
 * collections则是集合类的一个工具类/帮助类,其中提供了一系列的静态方法,用于对集合中元素进行排序,搜素以及先生安全等各种操作。
 *
 */
public class TestCollection implements Collection {

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public Iterator iterator() {
        return null;
    }

    @Override
    public Object[] toArray() {
        return new Object[0];
    }

    @Override
    public boolean add(Object o) {
        return false;
    }

    @Override
    public boolean remove(Object o) {
        return false;
    }

    @Override
    public boolean addAll(Collection c) {
        return false;
    }

    @Override
    public void clear() {

    }

    @Override
    public boolean retainAll(Collection c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection c) {
        return false;
    }

    @Override
    public boolean containsAll(Collection c) {
        return false;
    }

    @Override
    public Object[] toArray(Object[] a) {
        return new Object[0];
    }
}

22、collections工具类是怎么排序的


/**
 * collections工具类的sort方法有两种重载形式:
 * 1)传入的待排序容器中存放的对象比较实现comparable接口以实现元素的比较
 * 2)不强制性的要求容器中的元素必须可以比较,但是要求传入的第二个参数,参数是comparator接口的子类型,需要重写compare方法
 * 实现元素的比较,相当于临时定义的排序规则,其实就是通过接口注入比较元素大小 的算法。
 */
public class TestSort {
}

23、

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值