Java 培训基础高频面试题八股文分享
Java 的特点
Java 是一门面向对象的编程语言。面向对象和面向过程的区别参考第三道题。
Java 具有平台独立性和移植性。
Java 有一句口号:Write once, run anywhere,一次编写、到处运行。这也是 Java 的魅力所在。而实现这种特性的正是 Java 虚拟机 JVM。已编译的 Java 程序可以在任何带有 JVM 的平台上运行。你可以在 windows 平台编写代码,然后拿到 linux 上运行。java培训只要你在编写完代码后,将代码编译成.class 文件,再把 class 文件打成 Java 包,这个 jar 包就可以在不同的平台上运行了。
Java 具有稳健性。
Java 是一个强类型语言,它允许扩展编译时检查潜在类型不匹配问题的功能。Java 要求显式的方法声明,它不支持 C 风格的隐式声明。这些严格的要求保证编译程序能捕捉调用错误,这就导致更可靠的程序。
异常处理是 Java 中使得程序更稳健的另一个特征。异常是某种类似于错误的异常条件出现的信号。使用 try/catch/finally 语句,程序员可以找到出错的处理代码,这就简化了出错处理和恢复的任务。
Java 与 C++ 的区别
Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 兼容 C ,不但支持面向对象也支持面向过程。
Java 通过虚拟机从而实现跨平台特性, C++ 依赖于特定的平台。
Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
Java 支持自动垃圾回收,而 C++ 需要手动回收。
Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
面向对象和面向过程的区别?
面向对象和面向过程是一种软件开发思想。
面向过程就是分析出解决问题所需要的步骤,然后用函数按这些步骤实现,使用的时候依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,分别设计这些对象,然后将他们组装成有完整功能的系统。面向过程只用函数实现,面向对象是用类实现各个功能模块。
以五子棋为例,面向过程的设计思路就是首先分析问题的步骤:
1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤 2,9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为:
黑白双方
棋盘系统,负责绘制画面
规则系统,负责判定诸如犯规、输赢等。
黑白双方负责接受用户的输入,并告知棋盘系统棋子布局发生变化,棋盘系统接收到了棋子的变化的信息就负责在屏幕上面显示出这种变化,同时利用规则系统来对棋局进行判定。
JKD 和 JRE 的区别?
JDK 和 JRE 是 Java 开发和运行工具,其中 JDK 包含了 JRE,而 JRE 是可以独立安装的。
JDK:Java Development Kit,JAVA 语言的软件工具开发包,是整个 JAVA 开发的核心,它包含了 JAVA 的运行(JVM+JAVA 类库)环境和 JAVA 工具。
JRE:Java Runtime Environment,Java 运行环境,包含 JVM 标准实现及 Java 核心类库。JRE 是 Java 运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)。
JRE 是运行基于 Java 语言编写的程序所不可缺少的运行环境。也是通过它,Java 的开发者才得以将自己开发的程序发布到用户手中,让用户使用。
面向对象有哪些特性?
面向对象四大特性:封装,继承,多态,抽象
1、封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问。良好的封装能够减少耦合。
2、继承是从已有的类中派生出新的类,新的类继承父类的属性和行为,并能扩展新的能力,大大增加程序的重用性和易维护性。在 Java 中是单继承的,也就是说一个子类只有一个父类。
3、多态是同一个行为具有多个不同表现形式的能力。在不修改程序代码的情况下改变程序运行时绑定的代码。实现多态的三要素:继承、重写、父类引用指向子类对象。
静态多态性:通过重载实现,相同的方法有不同的參数列表,可以根据参数的不同,做出不同的处理。
动态多态性:在子类中重写父类的方法。运行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
4、抽象。把客观事物用代码抽象出来。
Java 的基本数据类型有哪些?
byte,8bit
char,16bit
short,16bit
int,32bit
float,32bit
long,64bit
double,64bit
boolean,只有两个值:true、false,可以使⽤用 1 bit 来存储
什么是值传递和引用传递?
值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。所以对引用对象进行操作会同时改变原对象。
自动装箱和拆箱
Java 中基础数据类型与它们对应的包装类见下表:
装箱:将基础类型转化为包装类型。
拆箱:将包装类型转化为基础类型。
当基础类型与它们的包装类有如下几种情况时,编译器会自动帮我们进行装箱或拆箱:
赋值操作(装箱或拆箱)
进行加减乘除混合运算 (拆箱)
进行>、<、==比较运算(拆箱)
调用 equals 进行比较(装箱)
ArrayList、HashMap 等集合类添加基础类型数据时(装箱)
示例代码:
Integer x = 1; // 装箱 调⽤ Integer.valueOf(1)
int y = x; // 拆箱 调⽤了 X.intValue()
下面看一道常见的面试题:
public void testAutoBox() {
int a = 100;
Integer b = 100;
System.out.println(a == b);
Integer c = 100;
Integer d = 100;
System.out.println(c == d);
Integer e = 200;
Integer f = 200;
System.out.println(e == f);
}
输出:
true
true
false
为什么第三个输出是 false?看看 Integer 类的源码就知道啦。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer e = 200; 会调用 调⽤Integer.valueOf(200)。而从 Integer 的 valueOf()源码可以看到,这里的实现并不是简单的 new Integer,而是用 IntegerCache 做一个 cache。
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;
}
...
}
这是 IntegerCache 静态代码块中的一段,默认 Integer cache 的下限是-128,上限默认 127。当赋值 100 给 Integer 时,刚好在这个范围内,所以从 cache 中取对应的 Integer 并返回,所以二次返回的是同一个对象,所以==比较是相等的,当赋值 200 给 Integer 时,不在 cache 的范围内,所以会 new Integer 并返回,当然==比较的结果是不相等的_java培训机构。
String 为什么不可变?
先看下 Java8 String 类的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
String 类是 final 的,它的所有成员变量也都是 final 的。为什么是 final 的?
线程安全。同一个字符串实例可以被多个线程共享,因为字符串不可变,本身就是线程安全的。
支持 hash 映射和缓存。因为 String 的 hash 值经常会使用到,比如作为 Map 的键,不可变的特性使得 hash 值也不会变,不需要重新计算。
字符串常量池优化。String 对象创建之后,会缓存到字符串常量池中,下次需要创建同样的对象时,可以直接返回缓存的引用。
String, StringBuffer 和 StringBuilder 区别
1. 可变性
String 不可变
StringBuffer 和 StringBuilder 可变
2. 线程安全
String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步
String 类的常用方法有哪些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
new String("dabin")会创建几个对象?
使用这种方式会创建两个字符串对象(前提是字符串常量池中没有 "dabin" 这个字符串对象)。
"dabin" 属于字符串字面量,因此编译时期会在字符串常量池中创建一个字符串对象,指向这个 "dabin" 字符串字面量;
使用 new 的方式会在堆中创建一个字符串对象。
什么是字符串常量池?
字符串常量池保存着所有字符串字面量,这些字面量在编译时期就确定。字符串常量池位于堆内存中,专门用来存储字符串常量。在创建字符串时,JVM 首先会检查字符串常量池,如果该字符串已经存在池中,则返回其引用,如果不存在,则创建此字符串并放入池中,并返回其引用。
Object 常用方法有哪些?
Object 常用方法有:toString()、equals()、hashCode()、clone()、getClass()等。
toString:默认输出对象地址。可以重写 toString 方法,按照重写逻辑输出对象值。
equals:默认比较两个引用变量是否指向同一个对象(内存地址)。
hashCode:将与对象相关的信息映射成一个哈希值,默认的实现 hashCode 值是根据内存地址换算出来。
clone:可以实现对对象中各个属性的复制。
getClass:返回此 Object 的运行时类,常用于 java 反射机制。
wait:当前线程调用对象的 wait()方法之后,当前线程会释放对象锁,进入等待状态。等待其他线程调用此对象的 notify()/notifyAll()唤醒或者等待超时时间 wait(long timeout)自动唤醒。线程需要获取 obj 对象锁之后才能调用 obj.wait()。
notify:唤醒在此对象上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象上等待的所有线程。
文章来源于程序员大彬
评论