可变性java
String类中使用的是final关键字修饰字符数组保存字符串,private final char value[],因此String对象是不可变的。git
StringBuffer和StringBuilder都继承AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组来保存字符串 char[] value,可是没有用final关键字修饰,因此两种对象是可变的。github
线程安全性面试
String中的对象是不可变的,所以也能够理解成线程安全的。数组
AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操做,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,因此是线程安全的。StringBuilder 并无对方法进行加同步锁,因此是非线程安全的。安全
(引伸一道题:i++是线程安全的吗?=============>线程不安全)多线程
性能app
每次对String类型进行改变的时候,都会生成一个新的String对象,而后将指针指向新的String对象,这个过程当中会从新开辟内存空间,对内存空间极大的浪费。ide
StringBuffer 每次都会对 StringBuffer 对象自己进行操做,而不是生成新的对象并改变对象引用。相同状况下使用 StringBuilder 相比使用 StringBuffer 仅能得到 10%~15% 左右的性能提高,但却要冒多线程不安全的风险。函数
所以:因为 StringBuilder 相较于 StringBuffer 有速度优点,因此多数状况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的状况下,则必须使用 StringBuffer 类。
总结
1.少许数据:适用String
2.单线程操做字符串缓冲区下操做大量数据: 适用StringBuilder
3.多线程操做字符串缓冲区下操做大量数据: 适用StringBuffer
java中,父类的私有属性和构造方法都不能被继承,因此Constructor也就不能被重写,可是能够重载,全部能够看到一个类中有多个构建函数的状况。
重写:重写是子类对父类的容许访问的方法的实现过程进行从新编写,发生在子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。另外,若是父类方法访问修饰符为 private 则子类就不能重写该方法。也就是说方法提供的行为改变,而方法的外貌并无改变。
重载:同一个类中,方法名相同,参数类型不一样,个数不一样,顺序不一样,方法返回值和访问修饰符不一样。eg:构建函数。
封装:封装把一个对象的属性私有化,同时提供一些能够被外界访问的属性的方法,(get,set)。
继承:继承是使用已存在的类的定义做为基础创建新类的技术,新类的定义能够增长新的数据或新的功能,也能够用父类的功能,但不能选择性地继承父类。经过使用继承咱们可以很是方便地复用之前的代码。
多态:多态指的是同一个方法调用,因为对象不一样可能会有不一样的行为。
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
基本类型与引用类型:
基础数据类型:它们存储的都是数据量比较小的数据,只须要1个或者少许几个字节就能够了,所以,这些数据类型的变量的二进制就直接保存着他们的值。
引用数据类型:它主要用来指向某个对象,对象保存的数据通常都比较大。
基本数据类型 引用数据类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
普通的方法调用都是经过”对象名.方法名“来调用,即须要一个对象,然而静态方法能够不经过对象进行调用,所以不能调用其余非静态变量,也不能访问非静态变量的成员。
对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们指向的内存地址是否相等。
== : 它的做用是判断两个对象的地址是否是相等。即,判断两个对象是否是同一个对象(基本数据类型=比较的是值,引用数据类型=比较的是内存地址)。
equals() : 它的做用也是判断两个对象是否相等。但它通常有两种使用状况:
状况1:类没有覆盖 equals() 方法。则经过 equals() 比较该类的两个对象时,等价于经过“==”比较这两个对象。
状况2:类覆盖了 equals() 方法。通常,咱们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
public class test1 { public static void main(String[] args) { String a = new String("ab"); // a 为一个引用 String b = new String("ab"); // b为另外一个引用,对象的内容同样 String aa = "ab"; // 放在常量池中 String bb = "ab"; // 从常量池中查找 if (aa == bb) // true System.out.println("aa==bb"); if (a == b) // false,非同一对象 System.out.println("a==b"); if (a.equals(b)) // true System.out.println("true"); if (37 == 37.0) { // true System.out.println("true"); } } }
String 中的 equals 方法是被重写过的,由于 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
当建立 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要建立的值相同的对象,若是有就把它赋给当前引用。若是没有就在常量池中从新建立一个 String 对象。
面试官可能会问你:“你重写过 hashcode 和 equals 么,为何重写equals时必须重写hashCode方法?”
hashCode()介绍
hashCode() 的做用是获取哈希码,也称为散列码;它其实是返回一个int整数。这个哈希码的做用是肯定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。
散列表存储的是键值对(key-value),它的特色是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(能够快速找到所须要的对象)
为何要有 hashCode
咱们先以“HashSet 如何检查重复”为例子来讲明为何要有 hashCode: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其余已经加入的对象的 hashcode 值做比较,若是没有相符的hashcode,HashSet会假设对象没有重复出现。可是若是发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。若是二者相同,HashSet 就不会让其加入操做成功。若是不一样的话,就会从新散列到其余位置。(摘自个人Java启蒙书《Head first java》第二版)。这样咱们就大大减小了 equals 的次数,相应就大大提升了执行速度。
经过咱们能够看出:hashCode() 的做用就是获取哈希码,也称为散列码;它其实是返回一个int整数。这个哈希码的做用是肯定该对象在哈希表中的索引位置。hashCode()在散列表中才有用,在其它状况下没用。在散列表中hashCode() 的做用是获取对象的散列码,进而肯定该对象在散列表中的位置。
hashCode()与equals()的相关规定
若是两个对象相等,则hashcode必定也是相同的
两个对象相等,对两个对象分别调用equals方法都返回true
两个对象有相同的hashcode值,它们也不必定是相等的
所以,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。若是没有重写 hashCode(),则该 class 的两个对象不管如何都不会相等(即便这两个对象指向相同的数据)
10.线程,进程,程序的基本概念及关系
线程与进程类似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程当中能够产生多个线程。与进程不一样的是同类的多个线程共享同一块内存空间和一组系统资源,因此系统在产生一个线程,或是在各个线程之间做切换工做时,负担要比进程小得多,也正由于如此,线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或其余的数据存储设备中,也就是说程序是静态的代码。
进程是程序的一次执行过程,是系统运行程序的基本单位,所以进程是动态的。系统运行一个程序便是一个进程从建立,运行到消亡的过程。简单来讲,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每一个进程还占有某些系统资源如CPU时间,内存空间,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操做系统载入内存中。 线程是进程划分红的更小的运行单位。线程和进程最大的不一样在于基本上各进程是独立的,而各线程则不必定,由于同一进程中的线程极有可能会相互影响。从另外一角度来讲,进程属于操做系统的范畴,主要是同一段时间内,能够同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。