简历理论回顾之java基础

Java基础:

1.什么是oop思想?
基本思想: 类是具有相同属性和方法的一组对象的集合,万物皆可抽象成类,系统构造中尽可能运用人类的自然思维方式
使用对象、类、继承、封装、多态等基本概念来进行程序设计
 
Java中的类实现包括两个部分:类声明和类体。
类声明
[public][abstract|final] classclassName [extendssuperclassName] [implementsinterfaceNameList]{……}
其中,修饰符public,abstract,final 说明了类的属性,className为类名,superclassName为类的父类的名字,interfaceNameList为类所实现的接口列表。
类体
classclassName{
[public| protected| private] [static] [final] [transient] [volatile] type variableName;//成员变量
[public| protected| private] [static] [final| abstract] [native] [synchronized] returnType methodName([paramList]) [throwsexceptionList]{
statements
}//成员方法
}
成员变量限定词的含义:
 
  • static: 静态变量(类变量)
  • final: 常量;transient: 暂时性变量,用于对象存档,用于对象的串行化
  • volatile: 贡献变量,用于并发线程的共享
方法的实现也包括两部分内容:方法声明和方法体。
方法声明中的限定词的含义:
  • static: 类方法,可通过类名直接调用
  • abstract: 抽象方法,没有方法体
  • final: 方法不能被重写
  • native: 集成其它语言的代码
  • synchronized: 控制多个并发线程的访问
方法体
方法体是对方法的实现,它包括局部变量的声明以及所有合法的Java指令。方法体中声明的局部变量的作用域在该方法内部。若局部变量与类的成员变量同名,则类的成员变量被隐藏。
为了区别参数和类的成员变量,我们必须使用this。this用在一个方法中引用当前对象,它的值是调用该方法的对象。
 
2.构造方法的特点?
  • 构造方法是一个特殊的方法。Java 中的每个类都有构造方法,用来初始化该类的一个对象。
  • 构造方法具有和类名相同的名称,而且不返回任何数据类型。
  • 重载经常用于构造方法。
  • 构造方法只能由new运算符调用
4.oop基本特性?
封装
  封装性就是尽可能的隐藏对象内部细节,对外形成一道边界,只保留有限的接口和方法与外界进行交互。封装的原则是使对象以外的部分不能随意的访问和操作对象的内部属性,从而避免了外界对对象内部属性的破坏。
private default protected public
继承
  子类的对象拥有父类的全部属性与方法,称作子类对父类的继承。
  • Java中父类可以拥有多个子类,但是子类只能继承一个父类,称为单继承。
  • 继承实现了代码的复用。
  • Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的。
  • 子类不能继承父类中访问权限为private的成员变量和方法。
  • 子类可以重写父类的方法,即命名与父类同名的成员变量。
  Java中通过super来实现对父类成员的访问,super用来引用当前对象的父类。super 的使用有三种情况:
  • 访问父类被隐藏的成员变量,如:super.variable;
  • 调用父类中被重写的方法,如:super.Method([paramlist]),super()调用父类构造方法;
  • 调用父类的构造函数,如:super([paramlist]);
 
多态
对象的多态性是指在父类中定义的属性或方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为。
Java的多态性体现在两个方面:由方法重载实现的静态多态性(编译时多态)和方法重写实现的动态多态性(运行时多态)。
重载(Overloading)
  • 方法重载是让类以统一的方式处理不同数据类型的手段。
  • 一个类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法。
  • 返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准。
  重写(Overriding)
  • 子类对父类的方法进行重新编写。如果在子类中的方法与其父类有相同的的方法名、返回类型和参数表,我们说该方法被重写 (Overriding)。
  • 如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
  • 子类函数的访问修饰权限不能低于父类的。
 
 
java 内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack)
简历理论回顾之java基础
 

线程私有

程序计数器: 用于顺序调用程序指令, 选取下一条需要执行的字节码指令,完成程序的流程控制( 如:顺序执行、选择、循环、异常处理。)
虚拟机栈: Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。
Java 虚拟机栈会出现两种异常:*Error 和 OutOfMemoryError。
*Error: 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出*Error异常。
OutOfMemoryError: 若 Java 虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。
本地方法栈: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。内部构造同虚拟机栈。

线程共享

堆: 1.java管理内存中最大的一块,Java 堆是所有线程共享的一块内存区域,用于存储对象的实例,
2.Java 堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap)
3. 从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代
 
方法区:各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。主要目的是为了与堆(Heap)区分开来,方便GC(垃圾收集器)。
 
运行时常量池: 是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用) 什么是字面量: 字符串(final类);final修饰常量值;基本数据类型;其他
 
3.垃圾回收?
垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存。
那些内存需要回收?(对象是否可以被回收的两种经典算法: 引用计数法 和 可达性分析算法)
什么时候回收? (堆的新生代、老年代、永久代的垃圾回收时机,MinorGC 和 FullGC)
如何回收?(三种经典垃圾回收算法(标记清除算法、复制算法、标记整理算法)及分代收集算法 和 七种垃圾收集器)
 
 
 
 
list是一个接口,表示单列集合(当然内部可以是复杂对象),体系:父接口Collection下有List 和Set两个接口,
list有两个实现类:ArrayList 和LinkedList
set有两个实现类:HashSet和TreeSet 其中HashSet有子类LinkedHashSet
1.list和set的区别:
list集合元素有序并且允许重复
set集合元素无需且不允许重复
2.ArrayList 和LinkedList的区别:
Arraylist底层数据结构为数组,所以有索引,查询速度比较快但是增删速度比较慢
LinkedList底层数据是双向链表,所以没有索引,查询速度比较慢,但是增删比较快
 
Map是一个接口,表示双列集合,体系:父接口Map下面有HashMap和HashTable两个实现类(还有个ConCurrentHashMap类不常用)
HashMap数据结构
JDK1.7:数组+链表
JDK1.8之后:数组+链表+二叉树 :DK1.8之后在集合put元素的时候新增了一个长度检测,如果同意hash地址下的链表长度大于了等于了7,那么就会将链表转化为红黑树(为了提高查询效率)
 
Hashmap数据结构(这里以1.7为例)是由数组(table)+链表(entry)组成,每个entry对应着一个table的索引页对应着一个唯一的hash地址值
特点:
1.HashMap可以put key为null的值
2.HashMap的key具有唯一性
原理:Hashmap在put的数据的时候,在底层代码中会先通过判断put的值的key是否为null,如果为null,会固定存放到table[0]下面,如果不为null,会通过hash()方法计算出key对应的hash地址,通过hash地址去寻找数据应存放的table的指定索引下,找到之后会判断put的key在链表中是否存在(地址值和具体值都要判断)如果存在则为替换,如果不存在则为新增
 
HashMap和Hashtable的区别
Hashmap可以存储Key为null的值,线程不安全,但是效率高
Hashtable不可以存储Key为null的值,线程安全,但是效率低
 
 
4.线程池?

线程池的优点

我们通过创建一个线程对象,并且实现Runnable接口就可以实现一个简单的线程。可以利用上多核CPU。当一个任务结束,当前线程就接收。
但很多时候,我们不止会执行一个任务。如果每次都是如此的创建线程->执行任务->销毁线程,会造成很大的性能开销。
那能否一个线程创建后,执行完一个任务后,又去执行另一个任务,而不是销毁。这就是线程池。
这也就是池化技术的思想,通过预先创建好多个线程,放在池中,这样可以在需要使用线程的时候直接获取,避免多次重复创建、销毁带来的开销。
ExecutorService executorService = new ThreadPoolExecutor(1, 1,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10));
 
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("abcdefg");
}
});
 
executorService.shutdown();
 

线程池的风险

死锁 资源不足 并发错误 线程泄漏 请求过载
 
 

线程池的状态

ThreadPoolExecutor类中定义了一个volatile变量runState来表示线程池的状态,
线程池有四种状态,分别为RUNNING、SHURDOWN、STOP、TERMINATED。
 
5.异常处理?
自定义异常:super继承Exception中相同参数的方法,方法名自定义 ,通常用于描述业务逻辑功能错误 ,Exception类继承自Throwable,Exception里面全是构造方法Exception()及其重载!
public IllegalAgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
抛出: 一个方法内部使用throw抛出一个异常,就要在方法上使用throws声明该异常的抛出以告知调用者处理这个异常 (RuntimeException例外
throw new IllegalAgeException("年龄不合法");
/*
* 当我们调用一个含有throws声明异常抛出的方法时,编译器要求我们必须处理这个异常,处理方式有两种:
* 1try—catch自行捕获异常并处理
* 2:在当前方法上继续使用throws声明将该异常抛出
* 3.永远不要在main方法throws,意味要将异常抛给jvm处理,jvm的处理结果就是直接死机,就是立即结束程序的执行
*
*/
/**
* finally (不是必须要加的)
* finally块只能定义在异常处理机制的最后,可以直接跟在try后面或者最后一个catch之后。
*
* fianlly可以保证只要程序运行到try当中,那么无论try当中的代码片段是否出现异常,finally块里面的
* 代码都必然执行
通常把释放资源等操作放在fianlly中,比如流的关闭
* @author zhengliang
*
*/
javatry(){}try{}finally{} try(){}块退出时,会自动调用()中io对象的close()方法,关闭资源。
自动关闭语法是编译器认可,编译后的.class文件中流的关闭还是在finally中进行的
 
//当需要把内存中的数据存储到持久化设备上的这个动作称为输出(写)output操作;
//当把持久设备上的数据读取到内存中的这个动作称为输入(读)input操作。
//这个输入和输出的动作称为IO操作。
IO的作用是可以让我们的程序与外界进行数据交换
* 比如从网络读写数据,读取键盘数据,读写文件数据等等
 
* java将流按照读写单位划分为字节流与字符流
* InputStreamOutputStream是所有字节流父类
* java.io.Readerjava.io.Writer是字符流的父类
 
* 字符流只是方便我们读写字符,底层本质还是读写字节,只是字节与字符的转换工作交给了字符流来完成
*
* 转换流(承上启下) 用于连接字节流和字符流 注:本身也是字符流
* java.io.InputStreamReader
* java.io.OutputStreamWriter
 
* 流分为:节点流(低级流),处理流(高级流)
* 节点流:实际连接程序与另一端的管道,负责在两端之间传送数据,注意:读写一定是建立在节点流的基础上进行的
* 处理流:不能独立存在,可以连接在其他流上,处理流自带某种对数据的加工操作,所以数据流经该流会对这些数据进行处理,这样可以简化我们对数据的处理操作
*
 
低级流:
InputStream类-> FileInputStream ByteArrayInputStream PipedInputStream 及每个对应的OutputStream
Reader类-> CharArrayReader StringReader PipedReader FileReader 及每个对应的Writer
文件流
* 文件流是一套低级流,作用是读写文件数据
 
高级流:
InputStream类-> DataInputStream BufferedInputStream ObjectInputStream 及每个对应的OutputStream
Reader类-> BufferedReader InputStreamReader 及每个对应的Writer 还有 PrintWriter 带有自动行刷新的缓冲字符输出流(常用)
* 缓冲流 作用是提高读写效率
* java.io.BufferedInputStream
* java.io.BufferedOutputStream
 
* 缓冲流BufferedOutputStream的缓冲区操作
* FileOutputStream 文件输出流 ,无缓冲区,write一次,就往文件里面写一次数据,效率较低。
*
* BufferedOutputStream 缓存输出流, 缓存区默认大小为8192byte,可通过构造函数定义。
* write方法将数据写入缓存区中,缓存区满时写入文件。 flush方法强制将缓存区的数据写入文件,高效。
 
对象流
* 对象流是一对高级流,可以方便我们将java中任何对象进行读写操作
* java.io.ObjectOutputStream
* 对象输出流,可以将对象转换位一组字节写出(包含数据信息和结构信息,所以会比真实的数据的字节数要多)
* 将对象转换为一组字节 称为对象序列化
* 将字节写入文件 称为数据持久化
*
* java.io.ObjectInputStream
* 对象输入流,可以读取一组字节将其还原为对象,前提是读取的这组字节应当是对象输出流将一个对象转换的字节
* 将一组字节将其还原为对象 称为对象反序列化
* 需要注意,若当前类的实例希望能被对象流读写,那么要求当前类必须实现java.io.Serializable接口
* Serializable是签名接口(没有抽象方法),编译器编译时,识别出其实现了Serializable这个接口,就会自动添加一个隐含方法(将对象转成字节信息的方法)
 
1.按照流向来分:
输入流:只能从中读取字节数据,不能向其写出数据
输出流:只能向其写入字节数据,不能从中读取数据
2.按照流所处理的数据类型划分:可分为:
字节流:用于处理字节数据。
字符流:用于处理Unicode字符数据。
3.按照格式可以分为:
节点流(低级流)可以从向一个特定的IO设备(如磁盘,网络)读写数据的流。
处理流(高级流):可以对一个已存在的流的连接和封装,通过所封装的流的功能实现数据读写功能的流。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

简历理论回顾之java基础

上一篇:几种多线程同步方式总结


下一篇:一些最近的学习RoadMap