java总结-面试相关

1、java中socket的server和client
  • server端
    • 1.创建服务器端ServerSocket对象,ServerSocket serverSocket=new ServerSocket(9999);
    • 2.监听客户端对象, Socket socket=serverSocket.accept();
    • 3.获取输入流,读取客户端对象,BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
    • 4.获取输出流,对客户端请求进行响应,PrintWriter pw=new PrintWriter(socket.getOutputStream(),true);
    • 5.读取客户端信息,String data = br.readLine();
    • 6.转发给客户端,pw.println(data);
  • client端
    • 1.创建Socket对象,指定连接的服务器地址和端口号,socket = new Socket("localhost", 9999);
    • 2.获取输入流,读取服务器响应信息,br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    • 3.获取输出流,向服务器端发送信息,pw = new PrintWriter(socket.getOutputStream(),true);
    • 4.向服务器端发送信息,pw.println("你好,server");
    • 5.接收服务器端发回响应,
      String data = "";
      while (true) {
      	if ((data = br.readLine()) != null) {
      		System.out.println(data);
      		break;
      	}
      }
      
2、深拷贝、浅拷贝

简单地说,深拷贝对引用数据类型的成员变量的对象图中所有的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并没有对引用数据类型创建内存空间。

2.1、浅拷贝
  • 对于基本数据类型的成员变量,浅拷贝会直接进行值传递。对其中一个对象的成员值修改不会影响另外对象的该成员值。
  • 对于数据类型是引用数据类型的成员变量,浅拷贝是进行的引用传递。两个对象其实指向的是同一个对象实例,在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
2.2、深拷贝
  • 对象进行深拷贝要对整个对象图进行拷贝!不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象
3、前绑定与后绑定

绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。对java来说,绑定分为静态绑定和动态绑定;或者叫做前期绑定和后期绑定.

  • 前绑定(静态绑定):编译期就知道这个方法与类的关系。java当中的方法只有final,static,private和构造方法是前期绑定
  • 后期绑定(动态绑定):在运行时根据具体对象的类型进行绑定。虚拟机在调用实例方法的时候,会基于实际对象类型(只有运行的时候才知道)选择调用的方法。
4、一些主要特性名次
4.1、数据库事务的ACID
  • 数据库中的事务(Transaction)有四个特性,分别是:
    • 原子性(Atomicity)
    • 一致性(Consistency)
    • 隔离性(lsolation)–四种隔离层级:读未提交、读已提交、可重复读、串行化
    • 持久性(Durability)
  • 数据库的通配符:%,0个或者多个字符;_,单个字符;[]。正则表达式
4.2、分布式系统的CAP
  • Consistency (一致性):即更新操作成功并返回客户端后,所有节点在同一时间的数据完全一致
  • Availability (可用性):即服务一直可用,而且是正常响应时间
  • Partition Tolerance (分区容错性):分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务
    只能三选其二,案例:更新之后,不同服务器之前的同步出现问题,当请求来获取数据,若要确保一致性,则需要阻塞等待同步完成;若要满足可用性立即响应,则不能满足一致性
5、Java的异常
  • 分为两种,checked异常(编译时异常)和Runtime异常(运行时异常)
  • Java异常机制主要依赖于try、catch、finally、throw、throws五个关键字。
    • 1.try:它里面放置可能引发异常的代码
    • 2.catch:后面对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块,可以有多个catch块。
    • 3.finally:主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件),异常机制总是保证finally块总是被执行。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者 throw等终止方法的语句,则就不会跳回执行,直接停止。
    • 4.throw:用于抛出一个实际的异常,可以单独作为语句使用,抛出一个具体的异常对象。
    • 5.throws:用在方法签名中,用于声明该方法可能抛出的异常。
6、sleep与wait
  • 1、sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!)wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);

  • 2、sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;

  • 3、sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;

7、GC
  • (1)、什么时候触发GC?
    • 执行 system.gc()的时候
    • 老年代空间不足
    • 永久代空间不足
    • 新生代晋升为老年代时候,老年代剩余空间低于新生代晋升为老年代的速率,会触发老年代回收
    • new 一个大对象,新生代放不下,直接到老年代,空间不够,触发FullGC
  • (2)、怎么避免频繁GC
    • 不要频繁的new 对象
    • 不要显示的调研system.gc()
    • 不要用String+ 使用StringBuilder
    • 不要使用Long Integer 尽量使用基本类型
    • 少用静态变量 不会回收
    • 可以使用null 进行回收
  • (3)、什么是内存泄漏
    • 内存泄露,是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
  • (4)、什么是内存溢出?
    • 程序申请内存的时候,内存没有空间分配了。
8、创建线程两种方式的区别
8.1、两种方式
  • 1、扩展Thread类
  • 2、实现Runnable接口
8.2、采用继承Thread类方式:
  • 优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
  • 缺点:单继承,不能再继承其他父类
8.3、采用实现Runnable接口方式:
  • 优点:线程类只是**实现了Runable接口,还可以继承其他的类。**可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况。
  • 缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
9、java的反射
9.1、java反射的定义
  • 指在运行时状态中,获取类中的属性和方法,以及调用其中的方法的一种机制。这种机制的作用在于获取运行时才知道的类(Class)及其中的属性(Field)、方法(Method)以及调用其中的方法,也可以设置其中的属性值。
  • Java中实现反射最重要的一步,也是第一步就是获取Class对象,得到Class对象后可以通过该对象调用相应的方法来获取该类中的属性、方法以及调用该类中的方法。
9.2、java反射获取类的三种方式:
  • 通过Object类的getClass方法:Class cla = foo.getClass();
  • 通过对象实例方法获取对象:Class cla = foo.class;
  • 通过Class.forName方式:Class cla = Class.forName("xx.xx.Foo");
10、同步synchronized
10.1、三种方式:
  • 1.同步函数即同步实例方法
  • 2.同步静态方法
  • 3.同步代码块
10.2、区别
  • 修饰实例方法:一个对象中的加锁方法只允许一个线程访问。但要注意这种情况下锁的是访问该方法的实例对象, 如果多个线程不同对象访问该方法,则无法保证同步。
  • 修饰静态方法:由于静态方法是类方法, 所以这种情况下锁的是包含这个方法的类,也就是类对象;这样如果多个线程不同对象访问该静态方法,也是可以保证同步的。
  • 修饰代码块:这里的obj 可以为类中的一个属性、也可以是当前的对象,它的同步效果和修饰普通方法一样;Synchronized方法 (obj.class)静态代码块它的同步效果和修饰静态方法类似。
11、如果类a继承类b,实现接口c,而类b和接口c中定义了同名变量,请问会出现什么问题?
  • 当直接用实例对象调用变量名的时候,在编译时会发生错误(错误描述不同的JVM有不同的信息,意思就是未明确的x调用,两个x都匹配(就象在同时import java.util和java.sql两个包时直接声明Date一样)。对于父类的变量,可以用super.x来明确(输出的是1),而接口的属性默认隐含为 public static final.所以可以通过A.x来明确(输出的是0)。
12、java的四种引用方式:强引用,软引用,弱引用,虚引用
  • (1)强引用:引用关系最强,永远不会被垃圾回收,JVM宁愿抛出内存溢出错误也不回收(比如使用new来创建的对象)
  • (2)软引用:引用关系次强,只有内存空间不足时,垃圾回收器才会回收
  • (3)弱引用:内存回收时立即回收这类对象 (性能优化策略:建议将线程内创建的map型缓存类数据设为弱引用)
  • (4)虚引用:引用关系最弱,相当于在虚引用上加了一个通知机制,告诉程序该对象将要被回收
13、解释内存中栈(stack)、堆(heap)和方法区(method area)的用法。
  • 堆(heap):存放new对象和数组,可以被所有线程共享,不会存放别的对象引用。堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured
  • 栈(stack):存放基本数据类型的(包含具体数值)、存放引用类型的变量。具体栈存放的内容(1.局部变量表2.操作数栈3.栈帧数据区)
    • 局部变量表:基本数据类型值和引用变量等
    • 操作数栈:可以将指令在栈里面进行push和pop操作,也是一个数字数组类型。
    • 栈帧数据区:保存有常量池里面的数据,正常方法的返回,异常处理等信息。
  • 方法区(method area):包含了所有的class和静态变量(包含:类信息、常量池、方法信息、域名信息等),可以被所有线程共享
14、String和StringBuilder、StringBuffer的区别?
  • String和StringBuffer/StringBuilder,它们都可以储存和操作字符串。
  • String是只读字符串,String引用的字符串内容是不能被改变的(每次String的变化都是新创建了一个String,并把新String指向原来的变量)。
  • StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。区别在于StringBuilder在单线程下使用,因为它所有方面都没有被synchronized修饰(加锁),因此效率比StringBuffer高。
  • 字符串的+操作其本质是创建了StringBuilder对象进行append操作,然后将拼接后的StringBuilder对象用toString方法处理成String对象
15、String s = new String(“xyz”);操作产生的内容
  • 两个对象:一个是常量区的"xyz";一个是用new创建在堆上的对象;还有栈上的引用变量,指向堆的对象
16、Exception和Error的区别
  • Error一般指系统的问题,如系统崩溃,虚拟机错误,内存不足,方法调用栈溢出等。对这类错误导致的程序中断,仅靠程序本身无法恢复和预防,建议让程序终止。
  • Exception表示程序可处理的异常,可捕获且可能恢复。这类异常应该尽可能处理,使程序恢复运行,不应该随意终止异常。
  • Exception又分运行时异常(RuntimeException)和受检异常(CheckedException )。运行时异常(NullPointerException等),编译能通过,但一运行就终止,出现这类异常时程序会终止。而受检异常(强制必须处理,否则编译不通过)要么用try–catch捕获,要么用throws抛出给父类处理,否则编译不通过。
17、get和post请求的区别?
  • get用来从服务器获得数据,post用来向服务器提交数据;
  • get将表单数据按照name=value的形式,添加URL后面,并且使用"?“连接,而各个变量间使用”&"连接;post是将表单数据放在HTTP协议的请求头或消息体中传递URL; (http://xxx.com/visitRecord?type=weixin&userId=107 )
  • get传输数据要受到URL长度限制(1024字节);而post可以传输大量数据,上传文件通常使用post方式;
  • 使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据则应使用post
18、过滤器,拦截器,监听器的区别
  • 过滤器(Filter):当有一堆东西的时候,只选择符合要求的某一些。定义这些要求的工具,就是过滤器。顾名思义是用来过滤的,你传入的request,response提前过滤一些信息,或设置一些参数,然后进行业务逻辑处理,比如过滤掉非法url、统一设置字符集等。filter 流程是线性的, url传来检查之后,可保持原来流程继续执行,被下一个filter接收处理,形成一个链条.
  • 拦截器(Interceptor):在一个流程进行时,希望干预它的进展,甚至终止它进行,这是拦截器做的事情。用于在某个方法或字段被访问前后进行拦截,然后加入某些操作。拦截是AOP的一种实现策略
  • 监听器(Listener):当一个事件发生时,希望获得这个事件发生的详细信息,并不想干预这个事件本身的进程,这就用到监听器。监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前后可以做一些必要的处理。
19、
  • 同步阻塞IO(BlockIO):服务器的实现模式是一个连接一个线程,即客户端有连接请求的时候服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。需要总是去询问io操作是否就绪
  • 同步非阻塞IO(NoBlockIO):服务器实现模式是一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有io请求是才会启动一个线程进行处理。用户进程也需要时不时的去询问io操作是否就绪,这就需要用户进程不停的去询问。每个请求过来放入队列中,线程从队列中捞取请求数据做处理
  • 异步非阻塞IO(AIO)用户进程发起一个io操作后立即返回,等io操作真正的完成之后,应用程序会得到io操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的io读写操作,因为真正的io读写操作已经由内核完成。

你可能感兴趣的:(java)