java基础
1.JVM、JDK和JRE区别
- JVM:运行Java字节码的虚拟机,在不同的系统运行相同的字节码得到相同的效果
- JRE:Java Runtime Environment,Java运行时环境,JRE=JVM+Java基础和核心类库,运行已编译 Java 程序所需的所有内容的集合
- JDK:Java Development Kit,功能齐全的Java SDK,JDK=JRE+Java开发工具(编译器、反编译器、调试器等),能够创建和编译程序
2.字符型常量和字符串常量的区别
- 形式上:字符型常量是单引号引起的字符;字符串常量是双引号引起的0个或若干个字符
- 含义上:字符型常量相当于一个整值(ASCII值),可以参与表达式运算;字符串常量代表一个地址值(该字符串在内存中存放的位置)
- 占内存大小:字符型常量占两个字节;字符串常量占多个字节
3.构造器Constructor是否能被override
父类的私有属性和构造方法不能被继承,所以Constructor不能被override重写,但是能被overload重载,所以一个类中有多个构造函数。
4.Java面向对象编程三大特性
- 封装:把一个对象的属性私有化,同时提供一些对外访问的属性的方法
- 继承:子类拥有父类的非private的属性和方法并修改,也可以拥有自己的属性和方法
- 多态:在同一个类或者继承体系结构的基类与派生类中,用同名函数来实现各种不同的功能,主要体现在继承(多个子类对同一个方法的重写)和接口(实现接口并覆盖接口中的同一个方法)
5.String、StringBuffer和StringBuilder的区别
- String:String 类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是不可变的
- StringBuffer:StringBuffer对象是一个字符序列可变的字符串,它没有重新生成一个对象,而且在原来的对象中可以连接新的字符串。
- StringBuilder:StringBuilder和StringBuffer不同的是:StringBuffer类中的方法都添加了synchronized关键字来保证线程安全,而StringBuilder则没有实现线程安全功能,所以性能略高。
6.接口和抽象类的区别
- 抽象类中的成员变量可以实现多个权限 public private protected final等,接口中只能用 public static final修饰
- 一个类可以实现多个接口,但只能实现一个抽象类
- 抽象类不用实现接口的所有方法
- 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范
- 接口所有方法在接口中不能有实现(Java 8开始
接口方法可以有默认实现),抽象类可以有非抽象的方法
7.抽象类和继承的区别
抽象类不能被实例化
8.成员变量与局部变量的区别
- 语法上:成员变量属于类,局部变量属于方法;成员变量可以被访问控制符(private、public等)及static修饰,局部变量不行;都能被final修饰
- 内存的存储方式:成员变量是对象的一部分,存在于堆中;局部变量存在于栈中
- 内存的生存时间:成员变量随对象的创建而存在;局部变量随着方法的调用而自动消失
- 成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值;局部变量不会
9.对象实体和对象引用的区别
对象的引用在栈中,对象实际存放在堆中。
10.在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
帮助子类做初始化工作。
11. == 与 equals的区别
- == :基本数据类型比较的是值,引用数据类型比较的是内存地址
- equals() : 有两种使用情况:
• 情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
• 情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
12.hashCode() 与 equals()
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
- 如果两个对象相等,则 hashcode 一定也是相同的
- 两个对象相等,对两个对象分别调用 equals 方法都返回 true
- 两个对象有相同的 hashcode 值,它们也不一定是相等的因此,equals()被覆盖过,则hashCode()也必须被覆盖
- hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
13.简述线程,程序、进程的基本概念。以及他们之间关系是什么
- 程序:是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码
- 进程:是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中
- 线程:与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程
14.线程有哪些基本状态
1.新建状态(New):
当用new操作符创建一个线程时, 例如new Thread®,线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码
2.就绪状态(Runnable)
一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
3.运行状态(Running)
当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
4.阻塞状态(Blocked)
线程运行过程中,可能由于各种原因进入阻塞状态:
1>线程通过调用sleep方法进入睡眠状态;
2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3>线程试图得到一个锁,而该锁正被其他线程持有;
4>线程在等待某个触发条件;
…
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
5.死亡状态(Dead)
有两个原因会导致线程死亡:
1) run方法正常退出而自然死亡,
2) 一个未捕获的异常终止了run方法而使线程猝死。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.
15.final关键字
final 关键字主要用在三个地方:变量、方法、类。
-
对于一个 final 变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
-
当用 final 修饰一个类时,表明这个类不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法。
-
使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的 Java 实现版本中,会将final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。
16.Java 中的异常处理
Java标准库内建了一些通用的异常,这些类以java.lang 包中的Throwable为顶层父类。Throwable又派生出Error类和Exception类。
-
错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
-
异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。
- NullPointerException:要访问的变量没有引用任何对象时,抛出该异常
- ArithmeticException:算术运算异常,一个整数除以 0 时,抛出该异常
- ArrayIndexOutOfBoundsException:下标越界异常。
注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
Throwable 类常用方法
-
getMessage():返回异常发生时的详细信息
-
toString():返回异常发生时的简要描述
-
getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
-
printStackTrace():在控制台上打印 Throwable 对象封装的异常信息
异常处理总结
-
try 块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch块,则必须跟一个 finally 块。
-
catch 块:用于处理 try 捕获到的异常。
-
finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。
当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。
在以下4 种特殊情况下,finally 块不会被执行:
-
在 finally 语句块中发生了异常。
-
在前面的代码中用了 System.exit()退出程序。
-
程序所在的线程死亡。
-
关闭 CPU。
17.Java序列化中如果有些字段不想进行序列化如何操作
对于不想进行序列化的变量,使用 transient 关键字修饰。
transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。 transient 只能修饰变量,不能修饰类和方法。
18.final finally finalize的区别
- final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
- finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
- finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用 System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断。
19.对象的四种引用
- 强引用:Java中默认的引用类型,一个对象如果具有强引用那么只要这种引用还存在就不会被GC
Object obj = new Object();
User user=new User();
- 软引用:非必须引用,内存溢出之前进行回收,和redis类似
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();//有时候会返回null
- 弱引用:拥有更短的生命周期,只要垃圾回收器扫描到它,不管内存空间充足与否,都会回收它的内存。ThreadLocal里有用到
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
wf.get();//有时候会返回null
wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾
- 虚引用:每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null。虚引用主要用于检测对象是否已经从内存中删除
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永远返回null
pf.isEnQueued();//返回是否从内存中已经删除
20.Java获取反射的三种方法
- 通过new对象实现反射机制
- 通过路径实现反射机制
- 通过类名实现反射机制
public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
//方式二(所在通过路径-相对路径)
System.out.println(classobj1.getName());
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
}
21.Java反射机制
- 定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 作用:java的反射机制就是增加程序的灵活性,避免将程序写死到代码里
22.介绍IO
IO即Input/Output,输入和输出; 数据输入到计算机内存的过程即输入,反之输出到外部存储的过程即输出。IO流在Java中分为输入流和输出流,根据数据处理方式又分为字节流和字符流。
- 输入流基类:InputStream字节输入流,Reader字符输入流
- 输出流基类:OutputStream字节输出流,Writer字符输出流
23.BIO、NIO、AIO区别
- BIO:Blocking I/O,服务器实现模式为一个连接一个线程,即客户端有连接请求时就需要启动一个线程进行处理,如果这个连接不做任何事情就会造成不必要的开销,可以通过线程池机制来改善。BIO模式主要支持连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,在jdk1.4之前是唯一的IO
- NIO:New I/O,服务器实现模式为一个请求一个线程,即客户端发送的请求都会注册到多路复用器上,多路复用器会轮询到连接有IO请求时才会启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中,jdk1.4开始支持
- AIO:Asynchronous I/O,服务器实现模式为一个有效请求一个线程,客户端的请求都是由操作系统先完成了再通知服务器启动线程并进行处理。AIO适用于连接数目多且连接比较长的架构,比如相册服务器,充分调用OS参与并发操作,jdk1.7开始支持