Java基础篇
文章目录
- Java基础篇
- 1. Java语言的特点
- 2. 面向对象和面向过程的区别
- 3. 八种基本数据类型的大小,以及他们的封装类
- 4. 标识符的命名规则
- 5. instanceof关键字的作用
- 6. Java自动装箱和拆箱
- 7. 重写和重载的区别
- 8. equals和==的区别
- 9. Hashcode的作用
- 10. String、StringBuffer、StringBuilder的区别是什么
- 11. ArrayList和LinkedList的区别
- 12. HashMap和HashTable的区别
- 13. Collection包结构与Collections的区别
- 14. Java的四种引用
- 15. 泛型常用特点
- 16. Java创建对象的几种方式
- 17. 深拷贝和浅拷贝的区别
- 18. final有哪些用法
- 19. static有哪些用法
- 20. 3*0.1==0.3的返回值是什么
- 21. a = a + b 和a += b 有什么区别
- 22. try catch finally,try中有return,finally还会执行吗
- 23. Exception与Error包结构
- 24. OOM你遇到哪些问题,SOF你遇到哪些情况
- 25. 简述进程、线程、程序的基本概念以及之间的关系
- 26. 线程有哪些基本状态
- 27. Java序列化
- 28. Java中IO流
- 29. Java中IO与NIO的区别
- 30. Java反射的作用与原理
- 31. List,Set,Map三者之间的区别
- 31. List,Set,Map三者之间的区别
1. Java语言的特点
简单性:Java语言继承了C++语言的优点,去掉了C++中学习比较难的多继承、、指针等概念,所以学习起来更简单,使用也更方便。
面向对象:Java是一种面向对象的编程语言。
分布性:Java设计支持在网络上应用,它是分布式语言。所以只要用Java编写了一个程序,就可以到处应用,可以节省大量人力物力。
编译和解释性:Java编译程序生成字节码,而不是通常的机器码,这使得Java开发程序比用其他语言开发快很多。
稳健性:Java刚开始被设计出来就是为了写高可靠和稳健的软件的,所以用Java写可靠的软件很容易。目前许多第三方交易系统、银行平台的前台和后台电子交易系统等都会用Java语言开发。
安全性:Java的存储分配模型是它防御恶意代码的主要防御方法之一。所以很多大型企业级项目开发都会选择Java开发。
可移植性:Java并不依赖平台,用Java编写的程序可以运用到任何操作系统上。
高能性:Java是一种先编译后解释的语言,所以它不如全编译语言快。但Java设计者制作了“及时”编译程序,这样就可以实现全编译了。
多线索性:Java是多线索语言,它可以同时执行多个程序,能处理不同任务。
动态性:Java语言设计适用于变化的环境,它是一个动态的语言。
2. 面向对象和面向过程的区别
编程思想不同:面向过程是一种以过程为中心的编程思想,都是以什么正在发生为主要目标进行编程;面向对象是一类以对象作为基本程序结构单位的程序设计语言,用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。
特点不同:面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个个依次调用就可以;面向对象具有识认性,系统中的基本构件可识认为一组可识别的离散对象,对象具有唯一的静态类型和多个可能的动态类型,在基本层次关系的不同类中共享数据和操作。
优势不同:面向过程不支持丰富的“面向对象”特性(比如继承、多态),并且不允许混合持久化状态和域逻辑;面向对象在内部被表示为一个指向一组属性的指针,任何对这个对象的操作都会经过这个指针操作对象的属性和方法。
3. 八种基本数据类型的大小,以及他们的封装类
基本类型 | 大小(字节) | 默认值 | 封装类 |
---|---|---|---|
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 | \u0000(null) | Character |
4. 标识符的命名规则
- 必须由字母、数字、下划线及美元符号组成
- 不能以数字开头
- 不能与关键字冲突
- 不能和Java类库的类名冲突
- 应该使用有意义的名称
5. instanceof关键字的作用
Java中的instanceof运算符是通过返回一个布尔值在运行时指出对象是否是特定类或者他的子类的一个实例。
6. Java自动装箱和拆箱
简单一点来说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将 包装器类型转换为基本数据类型。
7. 重写和重载的区别
重写:
1.发生在父类和子类之间
2.方法名,参数列表,返回值类型必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定泵抛出新的检查异常或者比重写方法申明更加宽泛的检查型异常
重载:
1.重载Overload是一个类中多态性的一种表现
2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
3.重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准
8. equals和==的区别
1.==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向内存空间的值是不是相同
2.==是指对内存地址进行比较,equals()是对字符串的内容进行比较
3.==指引用是否相同,equals()指的是值是否相同
9. Hashcode的作用
1.hashCode的存在主要是用于查找的快捷性,如Hashtable、HashMap等,hashCode是用于散列存储结构中确定对象的存储地址的。
2.如果两个对象相同,就是适用于equals(java.lang,Object)方法,那么这两个对象的hashCode一定要相同。
3.如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面第二条。
4.两个对象的hashCode相同,并不表示两个对象就一定相同,也就是不一定会适用于equals(java.lang.Object)方法,只能够说明两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子中”。
10. String、StringBuffer、StringBuilder的区别是什么
1.可变与不可变:String类中使用字符串保存字符串,因为有final修饰,所以String对象是不可变的;StringBuilder和StringBuffer对象都是可变的。
2.是否多线程安全:String中的对象是不可变的,显然线程安全;StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以线程是安全的;StringBuilder并没有对方法加同步锁,所以是非线程安全的。
3.StringBuilder和StringBuffer共同点:StringBuilder和StringBuffer有公共父类AbstractStringBuilder(抽象类);StringBuffer会在方法上加synchronized关键字进行同步;如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。
11. ArrayList和LinkedList的区别
1.ArrayList是Array(动态数组)的数据结构,是数组队列 ,相当于动态数组;LinkedList是Link(链表)的数据结构,是双向链表结构,也可当作堆栈、队列、双端队列。此外,他们两个都是对List接口的实现。
2.当随机访问List(get和set操作),ArrayList比LinkedList效率更高,因为 LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
3.当对数据进行增加和删除的操作(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有的数据的下标造成影响,需要进行数据的移动。
4.从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
5.ArrayList主要控件开销在需要在List列表预留一定空间;而LinkedList主要控件开销在需要存储节点信息以及结点指针信息。
12. HashMap和HashTable的区别
1.产生时间不同:HashTable是Java一开始发布就提供的键值映射的数据结构,而HashMap产生于JDK1.2.虽然HashTable比HashMap出现的早一些,但是现在HashMap基本上已经弃用了。
2.继承的父类不同:HashMap继承自AbstractMap类,而HashTable继承自Dictionary类。不过他们都同时实现了map、cloneable(可复制)、Serializable(可序列化)这三个接口。
3.对外提供的接口不同:HashTable比HashMap多提供了elements()和contains()两个方法。elements()方法用于返回此HashTable中的value的枚举;contains()方法判断该HashTable是否包含传入的value,它的作用与containsValue()一致,事实上,containsValue()只是调用了一下contains()方法。
4.对Null key和Null value的支持不同:HashTable中既不支持Null key也不支持Null value,HashTable的put()方法的注释中有说明。HashMap中,null可作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是HashMap中没有该键,也可能是该键所对应的值为null;因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
5.线程安全性不同:HashTable是线程安全的,它的每一个方法中都加入了Synchronize方法,在多线程并发的环境下,可以直接使用HashTable,不需要自己为它的方法实现同步;HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题,使用HashMap时需要自己添加同步处理。虽然HashMap不是线程安全的,但是他的效率会比HashTable要好很多。
6.遍历方式的内部实现不同:HashTable、、HashMap都使用了Iterator。由于历史原因,HashTable还使用了Enumeration的方式。
7.计算hash值的方法不同:为了得到元素的位置,首先需要根据元素的Key计算出一个hash值,然后在用这个hash值来计算得到最终的位置。HashTable直接使用对象的hashCode,hashCode是JDK根据对象的地址或字符串或者数字计算出来的int类型的数值,然后在使用除留余数来获得最终的位置。HashTable在计算元素的位置时需要进行一次位除运算,而除法运算是比较耗时的。HashMap为了提高运算效率,将哈希表的大小固定为2的幂,这样在取模运算时,不需要做除法,只需要做位运算,位运算比除法的效率要高很多。
8.初始容量大小和每次扩充容量大小的不同:HashTable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始大小为16,之后每次扩充,容量变为原来的2倍。
13. Collection包结构与Collections的区别
Collection框架:
区别:
Collection是一个集合接口,提供了对集合对象进行基本操作的通用接口方法。
Collections是针对集合类的一个包装类,提供了一系列静态方法以实现对各种集合的搜索、排序、线程安全化等操作。Collections类不能实例化,服务于Collection框架。
14. Java的四种引用
强引用: 创建对象时的直接引用例如:Object o = new Object(),属于强可到达性;GC不会回收这种强引用对象,即使在内存溢出时宁愿报错也不会回收。
软引用: 利用SoftReference实现的引用对象(类似于包装),同时该对象属于软可到达性(即无强引用)时,GC机制会在保证虚拟机抛出 OutOfMemoryError 之前清除软引用对象,同时如果有引用队列引用会加入队列。
弱引用: 利用WeakReference实现的引用对象(类似于包装), 同时该对象属于弱可到达对象时,一旦GC线程在执行期间确定了该对象为弱引用对象,那么不论是否内存溢出都会会执行GC机制,同时如果有引用队列引用会加入队列。
虚引用: 利用PhantomReference实现的引用对象(类似于包装),同时该对象属于虚可到达对象时,如果有队列便会加入队列,但是特点在于被虚引用的对象的生命周期不会受到印象,由于这种引用主要是用于接收当对象被回收时的通知,因此无法利用虚引用获取到该对。
15. 泛型常用特点
泛型只在编译阶段有效。
16. Java创建对象的几种方式
1.使用new关键字:最常见的创建对象的方式,可以调用任意的构造函数(无参和带参)
2.使用Class类的newInstance方法:可以调用无参的构造函数创建对象
3.使用Constructor类的newInstance方法:可以调用有参数的和私有的构造参数
4.使用clone方法:创建对象不会调用任何构造函数(要使用clone方法,需要先实现Cloneable接口并实现其定义的clone方法)
5.使用反序列化:创建对象不会调用任何构造函(为了反序列化一个对象,我们需要让我们的类实现Serializable接口)
17. 深拷贝和浅拷贝的区别
浅拷贝: 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝: 被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
18. final有哪些用法
final修饰数据,数据不能被修改;final修饰方法,方法不能被重写;final修饰类,类不能被继承
19. static有哪些用法
static修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
static修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类;
静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键;
静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。
20. 3*0.1==0.3的返回值是什么
false,因为有些浮点数不能完全精确的表示出来。
21. a = a + b 和a += b 有什么区别
+=操作符会进行隐式自动类型转换,而a = a + b不会进行自动类型转换。
22. try catch finally,try中有return,finally还会执行吗
1.不管是否出现异常,finally块中代码都会执行;
2.当try和catch中有return时,finally仍然还会执行;
3.finally实在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码是怎么样的,返回值都不会改变,仍然是之前保存的值),所以函数返回值实在finally执行之前确定的;
4.finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
23. Exception与Error包结构
24. OOM你遇到哪些问题,SOF你遇到哪些情况
最常见的OOM情况:
Java堆内存溢出:一般由于内存泄漏或者堆的大小设置不当引起。对于内存泄漏,需要通过内存监控软件查找程序中的泄漏代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
Java永久代码溢出:即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib
等反射机制的情况下,因为上述情况下会产生大量的Class信息存储于方法区,此种情况可以通过更改方法区的大小解决。另外,过多的常量尤其是字符串也会导致方法区溢出。
最常见的SOF情况:
Java虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出,可以通过虚拟机参数-Xss设置栈的大小。
25. 简述进程、线程、程序的基本概念以及之间的关系
程序: 是含有指令和数据的文件,被存储在磁盘或着其他的数据存储设备中,也就是说程序是静态的代码。
进程: 是程序的一次执行过程,是系统运行的程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程: 与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或者在各个线程之间切换工作时,负担要比进程小得多,也正是因为如此,线程被称为轻量级进程。
26. 线程有哪些基本状态
新建(new): 新创建了一个进程对象
可运行(runnable): 线程对象创建后,其他线程(比如main线程)调用了该对象中的start()方法,该状态的线程位于可运行线程池中,等待线程调度选中,获取cpu使用权。
运行(running): 可运行状态的线程获得了cpu的时间片(timeslice),执行程序代码。
阻塞(block): 阻塞状态是指线程因为某种原因放弃了cpu
使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行状态,才有机会再次获得cpu timeslice转到运行状态。阻塞的情况分三种:
等待阻塞: 运行的线程执行o.wait()方法,JVM会把该线程放入到等待队列中。
同步阻塞: 运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入到锁池(lock pool)中。
其他阻塞: 运行的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I
/O处理完毕时,线程重新转入可运行状态。
死亡(dead): 线程run()、main()方法执行完毕,或者因异常退出了run()方法,则该线程结束生命周。死亡的线程不可再次复生。
27. Java序列化
序列化的含义: 将对象写入到IO流中
序列化的意义: 序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以保存在磁盘上,或者通过网络传输,以达到以后恢复成原来的对象,序列化机制使得对象可以脱离程序的运行而独立存在。
序列化实现的两种方式: Serializable(普通序列化)和Externalizable(强制自定义序列化)
序列化的步骤: 1.创建一个ObjectOutputStream输出流 2.调用ObjectOutputStream对象的writeObject输出可序列化对象。
两种序列化对比:
实现Serializable接口:系统自动存储必要信息;Java内建支持,易于实现,只需要实现该接口即可,无需任何代码支持;性能略差
实现Externalizable接口:程序员决定存储哪些信息;必须实现接口的两个方法;性能略好
28. Java中IO流
分类:
按照流的流向分为:输入流(只读)和输出流(只写)
按照操作单元划分:字节流和字符流
按照流的角色划分:节点流和处理流
29. Java中IO与NIO的区别
我们使用InputStream从输入流中读取数据时,如果没有读取到有效的数据,程序将在此处阻塞该线程的执行。其实传统的输入里和输出流都是阻塞式的进行输入和输出。 不仅如此,传统的输入流、输出流都是通过字节的移动来处理的(即使我们不直接处理字节流,但底层实现还是依赖于字节处理),也就是说,面向流的输入和输出一次只能处理一个字节,因此面向流的输入和输出系统效率通常不高。
从JDk1.4开始,java提供了一系列改进的输入和输出处理的新功能,这些功能被统称为新IO(NIO)。新增了许多用于处理输入和输出的类,这些类都被放在java.nio包及其子包下,并且对原io的很多类都以NIO为基础进行了改写。新增了满足NIO的功能。
NIO采用了内存映射对象的方式来处理输入和输出,NIO将文件或者文件的一块区域映射到内存中,这样就可以像访问内存一样来访问文件了。通过这种方式来进行输入/输出比传统的输入和输出要快的多。
30. Java反射的作用与原理
原理: Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。
作用:
1.获取一个对象的类信息
2.获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息
3.检获属于一个接口的常量和方法声明
4.创建一个知道程序运行期间才知道名字的类的实例
5.获取并设置一个对象的成员,甚至这个成员的名字是在程序运行期间才知道
6.检测一个在运行期间才知道名字的对象的方法
31. List,Set,Map三者之间的区别
元素的区别:
List中的元素,有序、可重复、可为空
Set中的元素,无序、不重复、只有一个空元素
Map中的元素,无序、键不重,值可重、可一个空键、多可空值
实现类的区别:
List:ArrayList、LinkedList
Set:HashSet、LinkedHashSet、TreeSet、SortedSet等等
Map:HashMap、TreeMap、WeakHashMap、LinkedHashMap、、IdentityHashMap等等
方法
31. List,Set,Map三者之间的区别
元素的区别:
List中的元素,有序、可重复、可为空
Set中的元素,无序、不重复、只有一个空元素
Map中的元素,无序、键不重,值可重、可一个空键、多可空值
实现类的区别:
List:ArrayList、LinkedList
Set:HashSet、LinkedHashSet、TreeSet、SortedSet等等
Map:HashMap、TreeMap、WeakHashMap、LinkedHashMap、、IdentityHashMap等等