一、面向对象和面向过程
面向对象:把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。
面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发。
二、Java基本数据类型
基本类型 | 大小(字节) | 默认值 | 封装类 |
byte | 1 | 0 | Byte |
short | 2 | 0 | Short |
int | 4 | 0 | Integer |
long | 8 | 0l | Long |
duble | 8 | 0.0d | Dubble |
float | 4 | 0.0f | Float |
boolean | - | false | Boolean |
char | 2 | \u0000(null) | Character |
基本数据类型在声明时系统会自动给它分配空间,而引用类型声明时只是分配了引用空间,必须通过实例化开辟数据空间之后才可以赋值。数组对象也是一个引用对象,将一个数组赋值给另一个数组时只是复制了一个引用,所以通过某一个数组所做的修改在另一个数组中也看的见。虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。使用int的原因是,对于当下32位的处理器(CPU)来说,一次处理数是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。
三、重写与重载
重写 总结:
- 发生在父类与子类之间
- 方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
- 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
- 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
重载 总结:
- 重载Overload是一个类中多态性的一种表现
- 重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
- 重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分
四、内部类
目的:提高安全性
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这三种:成员内部类、局部内部类、匿名内部类,如下图所示:
五、Java中的四种引用
强引用:强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收,例如:String archer = new String("archer")。
软引用 :软引用在程序内存不足时,会被回收。
例如:SoftReference<String> archer = new SoftReference<String>(new String("archer"));
注意:archer这个引用也是强引用,它是指向SoftReference这个对象的,这里的软引用指的是指向new String("str")的引用,也就是SoftReference类中T
可用场景: 创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM就会回收早先创建的对象。
弱引用:弱引用就是只要JVM垃圾回收器发现了它,就会将之回收。
例如:WeakReference<String> archer = new WeakReference<String>("archer");
可用场景: Java源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,我的理解就是,一旦我不需要某个引用,JVM会自动帮我处理它,这样我就不需要做其它操作。
虚引用:虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。注意哦,其它引用是被JVM回收后才被传入 ReferenceQueue 中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有 ReferenceQueue。
例如:PhantomReference prf = new PhantomReference(new String("str"), new ReferenceQueue<>());
可用场景: 对象销毁前的一些操作,比如说资源释放等。 Object.finalize() 虽然也可以做这类动作,但是这个方式即不安全又低效。
六、HashCode的作用
hashCode方法返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
两个不相等的对象可能会有相同的 hashcode 值,hashcode是根据hash算法计算出来的,可以进行再哈希,用多个不同的Hash函数,当发生冲突时,使用第二个,第三个….等哈希函数 计算地址,直到无冲突。
七、深拷贝和浅拷贝
原型模式:设计模式 --> Spring bean的Scope
浅拷贝: 浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:把要复制的对象所引用的对象都复制了一遍。
八、static用法
除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作;
此外static也多用于修饰内部类,此时称之为静态内部类;
最后一种用法就是静态导包,即 import static .import static,可以用 来指定导入某个类中的静态资源,并且不需要使用类名,可以直接使用资源名,例如main方法。
九、Object中的常用方法
clone 方法
finalize 方法:该方法和垃圾收集器有关系,判断一个对象是否可以被回收的最后一步就是判断是否重写了此方 法。
equals 方法:一般 equals 和 == 是不一样的,但是在 Object 中两者是一样的。equals用来比较的是两个对象的内容是否相等,== 比较的是变量(栈)内存中存放的对象的(堆)内存地址。
hashCode 方法:该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法,这个方法在一些具有哈 希功能的 Collection 中用到。
wait 方法
配合 synchronized 使用,wait 方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait() 方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。 调用该方法后当前线程进入睡眠状态,直到以下事件发生。
- 其他线程调用了该对象的 notify 方法;
- 其他线程调用了该对象的 notifyAll 方法;
- 其他线程调用了 interrupt 中断该线程;
- 时间间隔到了。 此时该线程就可以被调度了,如果是被中断的话就抛出一个 InterruptedException 异常。
notify 方法
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的某个线程(同步队列中的线程是给抢占 CPU 的线程,等待队列中的线程指的是等待唤醒的线程)。
notifyAll 方法
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的所有线程。
十、Java 创建对象方式
创建对象的方式关键字:new、反射、clone 拷贝、反序列化。
反射方式:使用 newInstance(),但是得处理两个异常 InstantiationException、IllegalAccessException:
User user=User.class.newInstance();
Object object=(Object)Class.forName("java.lang.Object").newInstance()
反序列化操作
调用 ObjectInputStream 类的 readObject() 方法。我们反序列化一个对象,JVM 会给我们创建一个单独的对象。JVM 创建对象并不会调用任何构造函数。一个对象实现了 Serializable 接口,就可以把对象写入到文中,并通过读取文件来创建对象。
十一、 fail-fast机制
fail-fast** 机制是 Java 集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生 fail-fast 事件。
例如:当某一个线程 A 通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变了,那么线程 A 访问集合时,就会抛出 ConcurrentModificationException 异常,产生 fail-fast 事件。这里的操作主要是指 add、remove 和 clear,对集合元素个数进行修改。
解决办法:建议使用“java.util.concurrent 包下的类”去取代“java.util 包下的类”。可以这么理解:在遍历之前,把 modCount 记下来 expectModCount,后面 expectModCount 去和 modCount 进行比较,如果不相等了,证明已并发了,被修改了,于是抛出ConcurrentModificationException 异常。
十二、Java集合
TreeSet的本质是TreeMap
HashSet的本质是HashMap
十三、红黑树的理解
红黑色的本质:2-3-4树
红黑树保证黑节点平衡的方式:左旋/右旋+变色 来保证
十四、try-finally中的return关键字
return语句的本质:
- return语句获取到变量的地址
- return将获取的地址返回,也就是return本质是传地址
十五、异常处理对性能的影响
异常处理的性能成本非常高,每个 Java 程序员在开发时都应牢记这句话。创建一个异常非常慢,抛出一个异常又会消耗1~5ms,当一个异常在应用的多个层级之间传递时,会拖累整个应用的性能。
仅在异常情况下使用异常;在可恢复的异常情况下使用异常;尽管使用异常有利于 Java 开发,但是在应用中最好不要捕获太多的调用栈,因为在很多情况下都不需要打印调用栈就知道哪里出错了。因此,异常消息应该提供恰到好处的信息。
十六、try-with-resource语法
try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。所谓的资源(resource)是指在程序完成后,必须关闭的对象。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。
关闭单个资源:
关闭多个资源:
处理规则:
- 凡是实现了AutoCloseable接口的类,在try()里声明该类实例的时候,在try结束后,close方法都会被调用
- try结束后自动调用的close方法,这个动作会早于finally里调用的方法。
- 不管是否出现异常(int i=1/0会抛出异常),try()里的实例都会被调用close方法
- 越晚声明的对象,会越早被close掉。
如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中直接使用该变量,而无需在 try-with-resources 语句中声明一个新变量。