美文网首页我爱编程
面试篇-Java基础

面试篇-Java基础

作者: terry蒋 | 来源:发表于2018-06-21 14:05 被阅读0次

    本问很多内容摘录和参考自下面的文章,感谢他们的共享:

    面经整理-Java基础 https://blog.csdn.net/u012294820/article/details/78664716

    Object类的常用方法。
    (1)clone
    保护方法,实现对象的浅拷贝,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常

    (2)equals
    在Object中与==是一样的,子类一般需要重写该方法,重写的同时需要重写hashCode

    (3)hashCode
    该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到

    (4)getClass
    final方法,获得运行时类型

    (5)wait
    必须在synchronized块中调用,否则会报异常。调用某个对象的wait()方法,当前线程释放对象锁,暂停执行进入等待状态,不用等前一个线程同步块执行完,下一个线程就可以获得对象锁。

    释放锁给其他等待锁的线程。使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

    调用该方法后当前线程进入睡眠状态,直到以下事件发生:
    其他线程调用了该对象的notify方法 ;
    其他线程调用了该对象的notifyAll方法 ;
    其他线程调用了interrupt中断当前线程 ;
    时间间隔到了 ;

    此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常

    (6)notify
    必须在synchronized块中调用,否则会报异常。调用某个对象的notify()方法,当前线程释放对象锁,并唤醒一个正在等待该对象锁的线程,只有前一个线程同步块执行完,下一个线程才会获得对象锁。

    (7)notifyAll
    必须在synchronized块中调用,否则会报异常。调用某个对象的notify()方法,当前线程释放对象锁,并唤醒所有正在等待该对象锁的线程,只有前一个线程同步块执行完,下一个线程才会获得对象锁。

    (8)toString

    转换成字符串,一般子类都有重写,否则打印句柄

    (9)finallize

    (a)finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize()对该对象做一下标记需要清除,但是只有在下一次垃圾收集过程中,才会真正回收对象的内存。
    (b)finalize()在什么时候被调用?

    • 所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候。

    • 程序退出时为每个对象调用一次finalize方法。

    • 显式的调用finalize方法

    clone方法的深拷贝和浅拷贝的区别
    浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所拷贝的对象,而不复制它所引用的对象。

    深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

    彻底的深拷贝:实现Serializable接口,将对象写到流中,并从流中读取重建对象,前提是该对象以及它内部引用的对象必须可序列化,否则不可序列化的对象必须设为transient;如果序列化的对象字段有改动,反序列化时会抛出异常,所以需要设置serialVersionUID属性,在反序列化过程中会判断serialVersionUID的值是否一致,新添加或更改的字段值将设为初始化值(对象为null,基本类型为相应的初始默认值),字段被删除将不设置

    参考一:Java对象的深复制和浅复制

    wait操作和sleep的操作的区别
    ①这两个方法来自不同的类分别是,sleep来自Thread类,而wait来自Object类。

    sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。

    ②锁: 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

    sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。

    Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。

    ③使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。

    synchronized(x){ 
         x.notify();//或者wait() 
    }
    

    多线程之间的通信,用wait sleep notify notifyAll配合使用? wait和sleep一样吗?

    Object:wait、notify、notifyAll
    1.wait():当前线程等待,释放锁
    2.notify():当前线程释放锁,唤醒等一个等待该锁的线程
    3.notifyAll():当前线程释放锁,唤醒等所有等待该锁的线程

    Thread:sleep、join、yield
    1.sleep():使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。可以使优先级低的线程得到执行的机会。
    2.join():等待当前线程死亡,如果当前线程未死亡,则程序就会一直阻塞在那。(当前线程未死亡,则循环调用wait(0))
    3.yield():让步,建议当前线程将cpu资源让给具有相同优先级的线程(包括当前线程自己),但是不能保证其他线程一定可以得到cpu资源。

    java如何实现多态

    含义:多态就是同一个接口,使用不同的实例而执行不同操作

    方式:通过重载和重写
    (a)重载:方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同,无法以返回类型作为重载函数的区分标准。

    1. 必须具有不同的参数列表;
    2. 可以有相同的返回类型,只要参数列表不同就可以了;
    3. 可以有不同的访问修饰符;
    4. 可以抛出不同的异常;

    (b)重写:重写父类的方法,子类函数的访问修饰权限不能小于父类的权限

    1. 参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。
    2. 返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
    3. 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
    4. 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:
      父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。

    泛型怎么实现的

    含义:泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法
    特性:在编译阶段进行类型检查,之后进行类型擦除(运行时List<String>和List<Integer>的类型都是List)

    泛型模式
    K ——键,比如映射的键。
    V ——值,比如 List 和 Set 的内容,或者 Map 中的值。
    E ——异常类。
    T ——泛型。

    泛型通配符:?,?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类,当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能,那么可以用 "?" 通配符来表未知类型

    泛型方法:public <T> void printMsg( T arg)

    参考java 泛型详解-绝对是对泛型方法讲解最详细的

    拆箱和装箱

    自动装箱
    例如:Integer i = 100;

    相当于编译器自动为您作以下的语法编译:Integer i = Integer.valueOf(100);

    自动拆箱
    自动拆箱,也就是将对象中的基本数据从对象中自动取出。如下可实现自动拆箱:

    Integer i = 10; //装箱
    int t = i; //拆箱,实际上执行了 int t = i.intValue();

    String、StringBuffer、StringBuilder的区别

    String字符串常量
    String 是不可变的对象, 每次对 String 类型进行改变时都会生成了一个新的 String 对象,然后将指针指向新的 String对象,经常改变String会生成许多无引用对象,触发JVM的 GC 开始工作,影响程序执行的性能。

    StringBuffer字符串变量(线程安全)
    StringBuffer 类每次修改都是对 StringBuffer 对象本身进行操作(JVM内部生成一个StringBuilder进行操作),不会生成新的对象。多线程需要经常修改字符串值的情况下推荐使用 StringBuffer 。

    StringBuilder字符串变量(非线程安全)
    StringBuilder类每次修改都是对 StringBuilder对象本身进行操作,不会生成新的对象。单线程中需要经常修改字符串值的情况下推荐使用 StringBuilder。

    比较Java和C++

    (1)Java比C++程序可靠性更高。
    (2)Java语言不需要程序对内存进行分配和回收。
    (3)Java语言中没有指针的概念,引入了真正的数组。
    (4)Java用接口(Interface)技术取代C++程序中的多继承性。

    序列化的好处与原理

    实现方式:实现Serializable或者Externalizable接口
    好处:可以完全还原对象
    应用场景:1)网络中传递对象,2)将对象保存在硬盘中,用于服务器重启恢复对象状态
    原理:将对象转为字节

    transient:忽略字段,不参与序列化

    参考Java序列化机制和原理

    Exception与Error

    (1)Java异常
    Java中有Error和Exception,它们都是继承自Throwable类。

    二者的不同之处
    Exception
    可以是可被控制(checked) 或不可控制的(unchecked)。
    表示一个由程序员导致的错误。
    应该在应用程序级被处理。

    Error
    总是不可控制的(unchecked)。
    经常用来用于表示系统错误或低层资源的错误。
    如果可能的话,应该在系统级被捕捉。

    Exception的分类
    Checked exception: 这类异常都是Exception的子类。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。
    Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception。

    相关文章

      网友评论

        本文标题:面试篇-Java基础

        本文链接:https://www.haomeiwen.com/subject/pqbqyftx.html