简单易学、有丰富的类库
面向对象(ava最重要的特性,让程序耦合度更低,内聚性更高)
与平台无关性(JVM是Java跨平台使用的根本)
安全可靠
支持多线程和网络编程
面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现, 然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等-一般采用面向过程开发
面向对象:把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。但是性能上来说,比面向过程要低。
基本类型 | 大小(字节) | 默认值 | 封装类 |
---|---|---|---|
byte | 1 | (byte)0 | Byte |
short | 2 | (short)0 | Short |
int | 4 | 0 | Integer |
long | 8 | 0L | Long |
float | 4 | 0.0f | Float |
double | 8 | 0.0d | Double |
boolean | - | false | Boolean |
char | 2 | \u000(null) | Character |
注意:
int是基本数据类型,Integer是int的封装类, 是引用类型。int默认值是0,而Integer默认值是null,所以Integer能区分出0和nulI的情况。一旦java看到nul,就知道这个引用还没有指向某个对象,再任何弓|用使用前,必须为其指定一个对象, 否则会报错。
基本数据类型在声明时系统会自动给它分配空间,而引用类型声明时只是分配了引用空间,必须通过实例化开辟数据空间之后才可以赋值。数组对象也是一个引用对象, 将一个数组赋值给另一个数组时只是复制了一个引用,所以通过某一个数组所做的修改在另-一个数组中也看的见。
虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语 言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。使用int的原因是,对于当下32位的处理器(CPU) 来说,一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。
命名规则(硬性要求)
命名规范(非硬性要求)
instanceof严格来说式Java中的一个双目运算符,用来测试一个对象是否为一个对象的实例
面试题1:以下的代码会输出什么
public class Main{
public static void main(Sttring[] args){
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
输出的结果为:
为什么会出现这样的结果?输出结果表明i1和i2指向的是同-一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的valueOf方法的具体实现:
public static Integer valueOf(int i){
if(i >= -128 && i<=IntegerCache.high)
return IntegerCache.chche[i+128];
else
return new Integer(i)
}
其中IntegerCache类的实现为:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {
}
}
从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候, 如果数值在[-128,127]之间, 便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。
面试题2:以下的代码会输出什么
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
输出结果如下:
**原因:**在某个范围内的整型数值的个数是有限的,而浮点数却不是
从字面上看,重写就是重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下,对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
重写总结
在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
重载总结
hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
String是只读字符串,它并不是基本数据类型,而是一个对象。 从底层源码来看是一个final类型的字符数组,所弓|用的字符串不能被改变,一经定义, 无法再增删改。每次对String的操作都会生成新的String对象。
String 类中使用 final 关键字修饰字符数组来保存字符串,private final char[] value
,所以 String 对象是不可变的。
在 Java 9 之后,String 类的实现改用 byte 数组存储字符串, private final byte[] value
StringBuffer和StringBuilder他们两都继承了AbstractStringBuilder
抽象类,从AbstractStringBuilder
抽象类中我们可以看到,他并没有用final
来修饰,所以是可变的:
/**
* The value is used for character storage
**/
char[] value;
他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和StringBuilder来进行操作。另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
Array (数组)是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。
Array获取数据的时间复杂度是0(1),但是要删除数据却是开销很大,因为这需要重排数组中的所有数据,(因为删除数据以后,需要把后面所有的数据前移)
缺点:数组初始化必须指定初始化的长度,否则报错
List-是-个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承Collection。他有两个重要的实现类:ArrayList和LinkedList
ArrayList可以看作是一个能够自动增长容量的数组,ArrayList的toArray方法返回一个数组,asList方法返回一个列表,ArrayList的底层的实现是Array,数组扩容实现
LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁。
两者的父类不同
HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。 不过它们都实现了同时实现.了map、Cloneable (可复制)、Serializable (可序列化)这三个接口。
对外提供的接口不同
Hashtable比HashMap多提供了elments()和contains()两个方法。elments()方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。
contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()-致。事实上,contansValue()就只是调用了一下contains() 方法。
Hashtable:key和value都不能为null。
HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性,可以有多个key值对应的value为null。
HashMap是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自己处理多线程的安全问题。
Hashtable是线程安全的,它的每个方法上都有synchronized关键字,因此可直接用于多线程中。
虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部分的使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap.
ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
Collection是集合类的上级接口,子接口有Set、List、 LinkedList. ArrayList、 Vector、 Stack;
Collections是集合类的一个帮助类,它包含有各种有 关集合操作的静态多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作。此类不能实例化,就像-个工具类,服务于Java的Collection框架。
强引用是我们平常中使用最多的引用,强引用再程序内存不足(OOM)的时候也不会被回收,使用方式:
String str = new String("str");
软引用在程序内存不足时,会被回收,使用方式:
//注意:wrf这个引用也是强引用,它是指向SoftReference这个对象的
//这里的软引用指的是指向new String("str")的引用,也就是SoftReference类中T
SoftReference<String> wrf = new SoftReference<String>(new String("str"));
可用场景:创建缓存的时候,把创建的对象放进缓存中,当内存不足时,JVM会回收早先创建的对象。
弱引用就是只要JVM垃圾回收器发现了它,就会将之回收,使用方式:
WeakReference<String> wrf = new WeakReference<String>(str);
**可用场景:**java源码中的java.util.weakHashMap
中的key就是使用弱引用,我的理解就是,一旦我不需要某个引用,JVM会自动,JVM会自动帮我处理它,这样我就不需要做其他操作。
虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入ReferenceQueue
中。注意哦,其它引用是被JVM回收后才被传入ReferenceQueue
中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有ReferenceQueue
。
PhantomReference<String> prf = new PhantomReference<String>(new String("str")),new ReferenceQueue<>());
可用场景:对象销毁前的一些操作,比如说资源释放等,object.finalize()
虽然也可以做这类动作,但是这个方式即不安全又低效
上诉所说的几类引用,都是指对象的引用,而不是指Reference
的四个子类(SoftReference
等)
不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba//
//StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba
不需要,抽象类不一定非要有抽象方法
普通类和抽象类的区别如下:
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
当产生hash冲突时,两个不相等的对象就会有相同的hashcode值,当hash冲突产生的时候,解决办法有三种:
+=
操作符会进行隐式自动类型转换,a+=b隐式地将加的操作的结果类型强制转换为持有结果类型,而a=a+b则不会自动进行类型转换
执行。总结如下:
1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
性能:重写的hash()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只需要产生一个hash值进行比较就可以了,效率很高
可靠性:hashCode并不是完全可靠的,有时候不同的对象他们产生的hashCode也会一样
(1)equals相等的两个对象他们的hashCode肯定相等,也就是说equals()是绝对可靠的
(2)hashCode相等的两个对象他们的equals()不一定相等,也就是说hashCode不是绝对可靠的
是为了提高效率,采取重写hashcode方法,先进行hashcode比较,如果不同,那么就没必要在进行equals的比较了,这样就大大减少了equals比较的次数,这对比需要比较的数量很大的效率提高是很明显的。
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作。
public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。
public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
protected void finalize() throws Throwable {
}//实例被垃圾回收器回收的时候触发的操作