Java基础
- 一、Java语言的三大特性
- 二、Java语言主要特征
- 三、JDK和JRE的区别
- 四、Java基本数据类型及其包装类
- 五、如果main方法被声明为private会怎样?
- 六、说明一下public static void main(String args[])这段声明里每个关键字的作用?
- 七、==与equals的区别?
- 八、Object有哪些公用方法?
- 九、为什么Java里没有全局变量?
- 十、while循环和do循环有什么不同?
- 十一、char类型变量中能不能存储一个中文汉字?
- 十二、Java中的访问修饰符?
- 十三、float f = 3.1;是否正确?
- 十四、&和&&的区别?
- 十五、比较Integer类型的数值结果?
- 十六、Locale类是什么?
- 十七、Java中final、finally、finalize的区别和用法?
- 十八、hashCode()和equals()的区别?
- 十九、深拷贝和浅拷贝的区别是什么(重点)?
- 二十、Java中操作字符串的都有哪些类?它们之间有何区别(重点)?
- 二十一、String str = "a"与String str = new String("a")一样吗?
- 二十二、抽象类能用 final 修饰吗?
- 二十三、static关键字五连问?
- 二十四、重载(Overload)和重写(Override)的区别?重载的方法能否根据返回类型进行区分?
- 二十五、Java的四种引用?
- 二十六、Java中的Comparator与Comparable有何不同?
- 二十七、Java序列化,反序列化?
- 二十八、序列化的实现?不想序列化?
- 二十九、Java中的IO?
- 三十、Java泛型和类型擦除?
一、Java语言的三大特性
-
封装
封装就是把属于同一事物的共性归到一个类中,以方便使用。
封装也叫信息隐藏,隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
-
继承
从已有类得到继承信息并创建新类的过程。
也就是个性接受共性的属性和方法,并加入个性特有的属性和方法。
-
多态
允许不同子类型的对象对同一消息做出不同的响应。
也就是指同一行为,具有多个不同的表现形式。
-
抽象
是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。
二、Java语言主要特征
- Java语言是易学的;
- Java语言是强制面向对象的;
- Java语言是分布式的;
- Java语言是健壮的;
- Java语言是安全的;
- Java语言是解释型的;
- Java语言是体系结构中立的;
- Java语言是性能略高的;
- Java语言是远程支持多线程的。
三、JDK和JRE的区别
-
JDK:Java开发工具包,提供了Java的开发环境和运行环境;
-
JRE:Java运行环境,为Java的运行提供了所需环境。
JDK(编译) > JRE(运行) > JVM
四、Java基本数据类型及其包装类
-
为什么需要封装类?
因为泛型类包括预定义的集合,使用的参数都是对象类型,无法直接使用基本数据类型,所以Java又提供了这些基本类型的封装类。
-
基本数据类型和对应的封装类由于本质的不同,存在哪些差别?
- 基本数据类型只能按值传递,而封装类按引用传递;
- 基本数据类型会在栈中创建,而对于对象类型,对象在堆中创建,对象的引用在栈中创建,基本数据类型由于在栈中,效率会比较高,但是可能存在内存泄露的问题。
五、如果main方法被声明为private会怎样?
能正常编译,但是运行的时候会提示“main方法不是public的”。在idea中如果不用public修饰,则会自动去掉可运行的按钮。
六、说明一下public static void main(String args[])这段声明里每个关键字的作用?
- public:main方法是Java程序运行时调用的第一个方法,因此它必须对Java环境可见。所以可见性设置为public;
- static:Java平台调用这个方法时不会创建这个类的一个实例,因此这个方法必须声明为static;
- void:main方法没有返回值;
- String:是命令行传进参数的类型,args是指命令行传进的字符串数组。
七、==与equals的区别?
- ==:比较的是引用;
- equals:如果对equals方法进行了重写,默认比较的就是内容,不重写比较的是引用。
String,BitSet,Date,File都对equals方法进行了重写,在比较时默认比较的是内容。
八、Object有哪些公用方法?
Object是所有类的父类,任何类都默认继承Object。
-
clone
保护方法,实现对象的浅复制
,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。 -
equals
在Object中与==是一样的,子类一般需要重写该方法。 -
hashCode
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。 -
getClass
final方法,获得运行时类型。 -
wait
使当前线程等待该对象的锁
,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。调用该方法后当前线程进入睡眠状态,直到以下事件发生:
1. 其他线程调用了该对象的notify方法
2. 其他线程调用了该对象的notifyAll方法
3. 其他线程调用了interrupt中断该线程
4. 时间间隔到了
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常 -
notify
唤醒在该对象上等待的某个线程。 -
notifyAll
唤醒在该对象上等待的所有线程。 -
toString
转换成字符串,一般子类都有重写,否则打印句柄。
九、为什么Java里没有全局变量?
全局变量是全局可见的,Java不支持全局可见的变量。因为全局变量破坏了引用透明性原则,全局变量导致了命名空间的冲突。
可以使用 properties 类将想要全局有效的变量值写在 properties 文件中,那么在何处用时都从此properties文件中读取这个变量的值就可以了,此值在任何时候都可以修改的。
十、while循环和do循环有什么不同?
while结构在循环的开始判断下一个迭代是否应该继续。
do/while结构在循环的结尾来判断是否将继续下一轮迭代,do结构至少会执行一次循环体。
十一、char类型变量中能不能存储一个中文汉字?
可以。
Java默认为Unicode编码,Unicode码占16位,而char刚好是两个字节16位。
十二、Java中的访问修饰符?
十三、float f = 3.1;是否正确?
不正确。3.4是双精度数,将双精度型赋值给浮点型属于下转型,会造成精度损失,因此要进行强制类型转换float f = (float)3.4或者写成float f = 3.4F。
数据类型的自动转换:
byte、short、char —> int —> long —> float —> double
十四、&和&&的区别?
-
&:按位与和逻辑与
按位与:0 & 1 = 0;0 & 0 = 0;1 & 1 = 1;
逻辑与:a == b & b == c(即使a == b已经是false了,但是程序还会继续判断b是否等于c)。 -
&&:短路与
a == b && b == c(当a == b为false则不会继续判断b是否等于c)。
十五、比较Integer类型的数值结果?
public class IntegerTest {
public static void main(String[] args) {
Integer a = 100, b = 100 ,c = 129,d = 129;
System.out.println(a==b);System.out.println(c==d);
}
}
结果:
true
false
通过查看源码可以得知,这样的结果是因为整形常量池中缓存了-127~128之间的值,如果不在这个常量池中就会创建新的 Integer 对象。
这样的做法就合理优化了高频数值的复用。
十六、Locale类是什么?
Locale类用来根据语言环境来动态调整程序的输出。
十七、Java中final、finally、finalize的区别和用法?
-
final
final是一个修饰符也是一个关键字。
用于声明属性、方法和类。分别表示属性不可变、方法不可覆盖、被其修饰的类不可继承。
-
finally
finally是一个关键字。
异常处理语句结构的一部分,表示总是执行。
异常执行顺序:
try ——> catch ——> finally
当finally中有return语句时,执行完finally后直接返回;当finally中没有return语句时,执行完finally后再执行catch中的return(catch中没有return就直接返回)。 -
finalize
finalize()是Object类的protected方法,子类可以覆盖该方法以实现资源清理工作。
在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收。
十八、hashCode()和equals()的区别?
hashCode()方法和equals()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致。
equals() 相等的两个对象的 hashCode() 肯定相等,也就是用 equals() 对比是绝对可靠的;
hashCode() 相等的两个对象的 equals() 不一定相等,也就是 hashCode() 不是绝对可靠的。
关于hashCode()和equals()的区别可以参考此文章
十九、深拷贝和浅拷贝的区别是什么(重点)?
-
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。
-
深拷贝
深拷贝复制变量值,对于引用数据,则递归至基本类型后再复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
public Object clone() throws CloneNotSupportedException {
// 浅复制时:
// Object object = super.clone();
// return object;
// 改为深复制:
Student student = (Student) super.clone();
// 本来是浅复制,现在将Teacher对象复制⼀份并重新set进来
student.setTeacher((Teacher)student.getTeacher().clone());
return student;
}
二十、Java中操作字符串的都有哪些类?它们之间有何区别(重点)?
String、StringBuffer、StringBuilder的区别?
我们通过反编译可知:无论使用何种方式进行字符串连接,实际上都是使用的 StringBuilder。
区别:
- String声明的是不可变的对象,每次操作都会生成新的String对象,然后将指针指向新的String对象。而StringBuffer和StringBuilder可以在原有读写的基础上进行操作。
- StringBuffer是线程安全的,而StringBuilder是非线程安全的。但是StringBuilder的性能高于StringBuffer,StringBuilder一般在单线程环境下使用。
在Java中无论使用何种方式进行字符串连接("+"),实际上都使用的是StringBuilder中的append()方法。
class StringEqualTest {
public static void main(String[] args) {
// 最多创建一个String对象,最少不创建String对象(常量池中有)
String s1 = "Programming";
// 最多创建两个String对象,至少创建一个String对象
String s2 = new String("Programming");
String s3 = "Program";
String s4 = "ming";
// 自动拼接成Programming,再找常量池中是否存在Programming
String s5 = "Program" + "ming";
// 调用StringBuilder进行append()操作,再toString(),相当于创建了一个新对象
String s6 = s3 + s4;
System.out.println(s1 == s2); //false
System.out.println(s1 == s5); //true
System.out.println(s1 == s6); //false
// intern()方法得到字符串在倡廉吃中对应的版本的引用(最终是个字符串)
System.out.println(s1 == s6.intern()); //true
// s2.intern() 表示在常量池中找是否有“programming”,与s2进行equals()比较,true则返回该字符串
System.out.println(s2 == s2.intern());//false
}
}
二十一、String str = "a"与String str = new String(“a”)一样吗?
不一样。
因为内存分配的方式不一样。
String str = “a”; ——> 常量池
String str = new String(“a”); ——> 堆内存
二十二、抽象类能用 final 修饰吗?
不能。
定义抽象类就是让其他类继承的,而 final 修饰的类不能被继承。
二十三、static关键字五连问?
-
抽象(abstract)的方法是否可同时是静态(static)的?
抽象方法将来是要被重写的,而静态方法是不能被重写的。
-
是否可以从一个静态(static)方法内部发出对非静态方法的调用?
不可以。
静态方法只能访问静态成员,非静态方法的调用要先创建对象。 -
static可否用来修饰局部变量?
static不允许用来修饰局部变量。
-
内部类与静态内部类的区别?
静态内部类相对于外部类是独立存在的,在静态内部类中无法直接访问外部类中的变量、方法。如果要访问的话,必须new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法。
普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。
如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。
如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同步类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性。
如果其他的类要访问静态内部类的属性或者调用静态内部类的方法,直接创建一个静态内部类对象即可。
-
Java中是否可以覆盖一个private或者是static的方法?
Java中的static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不使用。
二十四、重载(Overload)和重写(Override)的区别?重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式。
-
重载
实现
编译时
的多态性。方法重载规则:
- 方法名一致;
- 参数列表中参数的顺序、类型、个数不同;
- 重载与方法的返回值无关,存在于父类和子类、同类中;
- 可以抛出不同的异常,可以有不同的修饰符
-
重写
实现
运行时
的多态性。方法重写规则:
- 参数列表必须完全与被重写方法一致,返回值类型必须完全与被重写方法的返回值一致;
- 构造方法不能被重写,声明为final的方法不能被重写,声明为static的方法不能被重写,但是能够被再次声明;
- 访问权限不能比父类中被重写方法的访问权限更低;
- .重写的方法能够抛出任何非强制异常(UncheckedException,也叫非运行时异常),无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
二十五、Java的四种引用?
-
强引用
最普遍的一种引用方式,如String s = “abc”;变量s就是字符串"zbc"的强引用,只要强引用存在,则垃圾回收期就不会回收这个对象。
-
软引用(SoftReference)
用于描述还有用但非必须的对象,如果内存足够就不回收,如果内存不足就回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
-
弱引用(WeakReference)
弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
-
虚引用(PhantomReference)
就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟找那个对象被垃圾回收器回收的活动。
二十六、Java中的Comparator与Comparable有何不同?
Comparable接口用于定义对象的自然顺序,是排序接口
,而Comparator通常用于定义用户定制的顺序,是比较接口
。
我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个"该类的比较器"来进行排序。Comparable总是只有一个,但是可以有多个Comparator来定义对象的顺序。
二十七、Java序列化,反序列化?
-
序列化
序列化就是指将对象转换为字节序列的过程,也就是将对象写入到IO流。
将对象转化为二进制,用于保存或网络传输。
为了解决在对对象流进行读写操作时所引发的问题。
objectOutputStream.writeObject(obj);
-
反序列化
反序列化就是指将字节序列转换成目标对象的过程,也就是从IO流中恢复对象。
将二进制转化为对象。
objectInputStream.readObject();
二十八、序列化的实现?不想序列化?
-
序列化的实现
让类实现Serializable接口,标注该类对象是可被序列化的。
-
不想序列化
在字段前加上 transient 关键字:
transient private String phone;//不参与序列化
二十九、Java中的IO?
按照流的方向:输入流和输出流
按照实现功能:节点流和处理流
按照处理数据的单位:字节流和字符流
在java中能够被序列化的类必须先实现Serializable接口,该接口没有任何抽象方法只是起到一个标记作用。
字节流读取的时候,读到一个字节就返回一个字节; 字符流使用了字节流读到一个或多个字节时,先去查指定的编码表,将查到的字符返回。 字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。
只要是处理纯文本
数据,就要优先考虑使用字符流
,除此之外都用字节流。
字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream 字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。
三十、Java泛型和类型擦除?
泛型即参数化类型,在创建集合时,指定集合元素的类型,刺激和只能传入该类型的参数。
类型擦除:Java编译器生成的字节码不包含泛型信息,所以在编译时擦除(1. 泛型用最顶级父类替换;2. 移除)