java面试题:


1.字节


byte一字节,8位
short两字节 16位
int四字节32位
long八字节64位

2.string 与 stringbuffer


    创建对象:string字符串为常量 ,stringBuffer 为变量
 string 字符串改变是,旧的对象将会被垃圾回收机制处理
总结一下
  String:适用于少量的字符串操作的情况

  StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

  StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

3.GC


GC(GarbageCollection)是垃圾回收机制,在Java中开发人员无法使用指针来自由的管理内存,GC是JVM对内存(实际上就是对象)进行管理的方式。GC使得Java开发人员摆脱了繁琐的内存管理工作,让程序的开发更有效率。
计数法,可达性
当两个对象相互调用时,会被gc。

4.GC原理- 垃圾收集算法


分代收集算法 VS 分区收集算法

    分代收集(新生代-复制算法,老年代-标记清除算法,老年代-标记整理算法,永久代-方法区回收)
    当前主流VM垃圾收集都采用”分代收集”(Generational Collection)算法, 这种算法会根据对象存活周期的不同将内存划分为几块, 如JVM中的 新生代、老年代、永久代. 这样就可以根据各年代特点分别采用最适当的GC算法:

        在新生代: 每次垃圾收集都能发现大批对象已死, 只有少量存活. 因此选用复制算法, 只需要付出少量存活对象的复制成本就可以完成收集.
        在老年代: 因为对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标记—整理”算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存.
    分区收集
    上面介绍的分代收集算法是将对象的生命周期按长短划分为两个部分, 而分区算法则将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收. 这样做的好处是可以控制一次回收多少个小区间.
    在相同条件下, 堆空间越大, 一次GC耗时就越长, 从而产生的停顿也越长. 为了更好地控制GC产生的停顿时间, 将一块大的内存区域分割为多个小块, 根据目标停顿时间, 每次合理地回收若干个小区间(而不是整个堆), 从而减少一次GC所产生的停顿

5.反射作用


1.class:得到类的名字,类的包名、父类和实现的接口
2.构造器:构造器参数,参数类型
3.变量:变量名,类型
4.方法:方法名,方法的参数,方法的返回类型,以及调用方法
5.注解:类注解,方法注解,参数注解,变量注解。
6.泛型:获取泛型
7.数组:获取值,设置值

6.springmvc AND mybatis


springmvn:视图,模型,控制器,view,modle,colltroller
mybatis:是一个基于Java的持久层框架。注重sql。配置dataSource,sqlSessionFactory,sqlSession

==数据结构

1.HashMap与HashTable

1.存储:HashMap中key和value都允许为null
2.线程安全:HashMap线程不安全的,而Hashtable线程安全的,因为所以方法都是Synchronize的。
3.hash值不同: 
   哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
   hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。
   Hashtable计算hash值,直接用key的hashCode(),而HashMap重新计算了key的hash值,Hashtable在求      hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用          hash&0x7FFFFFFF后,再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值    有可 能为负数,而&0x7FFFFFFF后,只有符号外改变,而后面的位都不变。
4.内部实现使用的数组初始化和扩容方式不同
   HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量        一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
   Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
   Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大    ,增加的方式是 old*2+1。

==流

1.IO与NIO


1.面向流(Stream),面向块(buffer)
2.非阻塞,阻塞
3.Java NIO的selectors允许一条线程去监控多个channels的输入

==异常

1. error,Exception区别


ERROR:表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。
Exception:表示可恢复的例外,这是可捕捉到的.
Exceptin包括两种:
1.  需要检查的异常:必须抛出的,如io,sqlException ,可以处理
2.不需要检查的异常:不抛出的,如nullPointException ,不可以处理,程序编写错误。(RuntimeException)


#Thread
##状态:![thread](C:\Users\Administrator\Desktop\JDK\thread.png)

初始化(准备):new就绪:start()等待: 主动等待:wait(), join() 主动睡眠:wait(senconds), join(senconds),sleep() 进入阻塞:synchronized()运行:run()死亡:run()结束;interrupt()

==线程

1.线程间怎么通讯:


1.同步:synchronized
   private static void demo1(){
        String lock = "";
        new Thread(()->{
            util(lock);
        }).start();
        new Thread(()->{
            util(lock);
        }).start();
    }
    private static void util(String string){
        //如果传入string一个对象,只能允许一个访问,
        //           传入不同对象,可以同时访问。
        synchronized (string){
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("print ..." + string);
        }
    }
2.wait/notify机制
   private static void demo3() {
        Object lock = new Object();
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println("A 1");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("A 2");
                    System.out.println("A 3");
                }
    
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println("B 1");
                    System.out.println("B 2");
                    System.out.println("B 3");
    
                    lock.notify();
                }
            }
        });
        A.start();
        B.start();
    }
3.join() 等待另一个线程完成
   private static void demo2() {
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                printNumber("A");
            }
        });
    
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("B 开始等待 A");
                try {
                    A.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                printNumber("B");
            }
        });
    
        B.start();
        A.start();
    }
   private static void printNumber(String threadName) {
        int i=0;
        while (i++ < 3) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + " print: " + i);
        }
    }
4.CountdownLatch(计数器),CyclicBarrier(同时进行)
  private static void runDAfterABC() {
        int worker = 3;
        CountDownLatch countDownLatch = new CountDownLatch(worker);
        new Thread(() -> {
            System.out.println("D is waiting for other three threads");
            try {
                countDownLatch.await();
                System.out.println("All done, D starts working");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }).start();
        for (char threadName='A'; threadName <= 'C'; threadName++) {
            final String tN = String.valueOf(threadName);
            new Thread(() -> {
                System.out.println(tN + " is working");
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                System.out.println(tN + " finished");
                countDownLatch.countDown();
            }).start();
        }
    }
    
    /**
     * 每个线程逐渐进入等待
     * 都进入等待状态时:同时触发
     */
    private static void runABCWhenAllReady() {
        int runner = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
        final Random random = new Random();
        for (char runnerName='A'; runnerName <= 'C'; runnerName++) {
            final String rN = String.valueOf(runnerName);
            new Thread(() -> {
                long prepareTime = random.nextInt(10000) + 100;
                System.out.println(rN + " is preparing for time: " + prepareTime);
                try {
                    Thread.sleep(prepareTime);
                    System.out.println(rN + " is prepared, waiting for others");
                    cyclicBarrier.await(); // 当前运动员准备完毕,等待别人准备好
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(rN + " starts running"); // 所有运动员都准备好了,一起开始跑
            }).start();
        }
    }
5.FutureTask

   private static void doTaskWithResultInWorker() {
        Callable<Integer> callable = () -> {
            System.out.println("Task starts");
            Thread.sleep(1000);
            int result = 0;
            for (int i=0; i<=100; i++) {
                result += i;
            }
            System.out.println("Task finished and return result");
            return result;
        };
    
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();
        try {
            System.out.println("Before futureTask.get()");
            System.out.println("Result: " + futureTask.get());
            System.out.println("After futureTask.get()");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.守护线程

private static void doemon(){


    // 守护线程,当程序中只剩下守护线程时程序终止。
    Thread t = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("i=" + i);
        }
    });
    //t.setDaemon(true);//this is set t thread as a daemon thread.
    t.start();
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("main thread exit.");
}

3.线程安全与线程不安全


线程安全:一个线程访问一个数据对象时,将对象锁住,其他线程不能访问,直到此线程操作结束,才将该对象释放。
线程不安全:多个线程可以同时访问一个对象,容易造成数据污染,脏读。

==MYSQL

1.事务的隔离级别


                  √: 可能出现    ×: 不会出现
                    脏读 不可重复读 幻读
Read uncommitted        
Read committed      ×     
Repeatable read     ×   ×   
Serializable        ×   ×   ×

Read uncommitted 读未提交

公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有2000元,singo空欢喜一场。
出现上述情况,即我们所说的脏读,两个并发的事务,“事务A:领导给singo发工资”、“事务B:singo查询工资账户”,事务B读取了事务A尚未提交的数据。
当隔离级别设置为Read uncommitted时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

Read committed 读提交

singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为何......
出现上述情况,即我们所说的不可重复读,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读。
大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

Repeatable read 重复读

当隔离级别设置为Repeatable read时,可以避免不可重复读。当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。
虽然Repeatable read避免了不可重复读,但还有可能出现幻读。
singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction ... ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出现了幻觉,幻读就这样产生了。
注:Mysql的默认隔离级别就是Repeatable read。

Serializable 序列化

Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。 

2.mysql索引有哪几种:

MySQL里的索引类型主要有以下几种。

1. B-Tree索引

最常见的索引类型,基于B-Tree数据结构。B-Tree的基本思想是,所有值(被索引的列)都是排过序的,每个叶节点到跟节点距离相等。所以B-Tree适合用来查找某一范围内的数据,而且可以直接支持数据排序(ORDER BY)。但是当索引多列时,列的顺序特别重要,需要格外注意。InnoDB和MyISAM都支持B-Tree索引。InnoDB用的是一个变种B+Tree,而MyISAM为了节省空间对索引进行了压缩,从而牺牲了性能。

2. Hash索引

基于hash表。所以这种索引只支持精确查找,不支持范围查找,不支持排序。这意味着范围查找或ORDER BY都要依赖server层的额外工作。目前只有Memory引擎支持显式的hash索引(但是它的hash是nonunique的,冲突太多时也会影响查找性能)。Memory引擎默认的索引类型即是Hash索引,虽然它也支持B-Tree索引。

例子:

CREATE TABLE testhash (
    fname VARCHAR(50) NOT NULL,
    lname VARCHAR(50) NOT NULL,
    KEY USING HASH(fname)
) ENGINE =MEMORY;

3. Spatial (R-Tree)(空间)索引

只有MyISAM引擎支持,并且支持的不好。可以忽略。

4. Full-text索引

主要用来查找文本中的关键字,而不是直接与索引中的值相比较。Full-text索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的WHERE语句的参数匹配。你可以对某列分别进行full-text索引和B-Tree索引,两者互不冲突。Full-text索引配合MATCH AGAINST操作使用,而不是一般的WHERE语句加LIKE。

问题处理:

1.分布式事务

分布式事务,本质上是对多个数据库的事务进行统一控制,
按照控制力度可以分为:不控制、部分控制和完全控制。
不控制就是不引入分布式事务,部分控制就是各种变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC模式,而完全控制就是完全实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,完全控制则是牺牲了性能,保障了一致性,具体用哪种方式,最终还是取决于业务场景。作为技术人员,一定不能忘了技术是为业务服务的,不要为了技术而技术,针对不同业务进行技术选型也是一种很重要的能力http://blog.csdn.net/mine_song/article/details/64118963


猜你喜欢

转载自blog.csdn.net/qq_37751454/article/details/80019627