最近闲暇时间看到网上的一些面试题,抽空整理了一下,写了一些自己的见解。其中有错漏之处,还望指正。
1 java语言特点
简单性:Java没有像C++那样的指针,运算符重载,类的多继承。并且实现了垃圾的自动回收,简化了程序开发者对于内存管理的工作
面向对象:对象是指封装数据和操作方法的程序实体。Java提供了简单的类机制以及动态接口。表现形式是封装 继承 多态
跨平台: Java语言开发的软件在Windows/ mac/ Linux 系统下都能运行, 只需要在操作系统上安装虚拟机 (Java Virtual Machine --- JVM )即可
移植性: 如果Java直接编译成系统能识的二进制码,可能一个标识在windows下是1100,而Linux 下是1001,这样java在windows下编译后无法在Linux 运行。所以java先编译成字节码(中间码),由JVM(java虚拟机来解释执行),而这个JVM对于主流的操作系统都有相应的版本,目的就是将统一的中间码编译成对应操作系统识的二进制码,然后执行。所以不论你在什么系统中编译的java,得到的都是统一的字节码(中间码)
2 Java的基本数据类型有哪些, 各占几个字节
整数型 byte short int long 浮点型 float double 字符型 char 布尔型 boolean
基本数据类型 | byte | short | int | long | float | double | boolean | cahr |
---|---|---|---|---|---|---|---|---|
占用字节数 | 1 | 2 | 4 | 8 | 4 | 8 | 占一位,而不是字节 | 2 |
扩展:
引用数据类型:
字符串、数组、类、接口、Lambda等 注意事项:
-
字符串不是基本类型,而是引用类型。
-
浮点型可能只是一个近似值,并非精确的值(所以不要用来比较)。
-
数据范围与字节数不一定相关,例如float数据范围比long更加广泛(long只能表示整数,而float表示的是小数),但是float是4字节,long是8字节。
-
浮点数当中默认类型是double。如果一定要使用float类型,需要加上一个后缀F。 如果是整数,默认为int类型,如果一定要使用long类型,需要加上一个后缀L。推荐使用大写字母后缀。
3 long(8)与float(4)的取值范围谁大谁小?
float的取值范围更大。虽然 long 是 8个字节, float 是 4个字节, 但是 float 的取值范围比 long 的取值范围大,因为 float 的算法与 long 的不一样。long只能表示整数,而float表示的是小数。举个例子:1到10之间的整数只有那么几个,那么1到10之间的小数有多少个呢?
4 Java语言中的字符 char可以存储一个中文汉字吗? 为什么呢?
可以,因为java默认使用Unicode编码,而在Unicode编码中一个中文汉字占两位,所以char可以存储一个中文汉字。
5 看下面的程序是否有问题,如果有问题,请指出并说明理由。
short s=1; s = s+1; // 报错
short s=1; s += 1; // 编译通过
这里涉及到+=与 + 的区别。
第一行报错:报错是因为第一行先进行了s+1的操作,然后赋值给s。等号右边short 类型数据 跟 默认的 int 类型的数据相加时, 会自动转化成 int 类型数据,而s是short类型的,造成了数据类型不匹配,所以编译会报错。
第二行可以编译通过:因为+=实际上对后面的值进行了强制类型转换,这里相当于s=(short)s+1;
扩展一下吧:
再举一个上面提到的例子分析一下:
public static void main(String[] args){
byte s = 1;
s+=1;
System.out.println(s);
}
分析: s += 1 逻辑上看作是 s = s + 1 计算结果被提升为int类型,再向byte类型赋值时发生错误,因为不能将取值范围大的类型赋值到取值范围小的类型。但是, s=s+1进行了两次运算 ,而 += 是一个运算符,只运算一次,并带有强制转换的特点, 也就是说 s += 1 就是 s = (byte)(s + 1) ,因此程序没有问题编译通过,运行结果是2.接着看一下下面这个程序:
public static void main(String[] args){
byte b1=1;
byte b2=2;
byte b3=1 + 2;
byte b4=b1+b2;
System.out.println(b3);
System.out.println(b4);
}
分析: b3 = 1 + 2 , 1 和 2 是常量,为固定不变的数据,在编译的时候(编译器javac),已经确定了 1+2 的结果并没有超过byte类型的取值范围,可以赋值给变量 b3 ,因此 b3=1 + 2 是正确的。
反之, b4 = b2 + b3 , b2 和 b3 是变量,变量的值是可能变化的,在编译的时候,编译器javac不确定b2+b3的结果是什么,因此会将结果以int类型进行处理,所以int类型不能赋值给byte类型,因此编译失败。
6 请自己实现两个整数变量的交换(不需要定义第三方变量)
先扩展一下:
实现两个变量交换的方式:
方式一:定义一个临时变量。简单举例:
int a=3;
int b=5;
int temp;
temp=a; //temp=3
a=b; //a=5
b=temp; //b=3
方式二:两加一减(不需要定义临时变量)
int a=3;
int b=5;
a=a+b; //a=8
b=a-b; //b=3
a=a-b; //a=5
方式三:位运算。也是最有效率的一种方式,同样不需要定义临时变量。
位异或运算符的特点:
^的特点:一个数据对另一个数据位异或两次,该数本身不变。
int a = 1;
int b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
关于^的知识点:
^是异或运算符(把数据转换成二进制,然后按位进行运算)。
运算规则:0^0 = 0, 1^0 = 1, 0^1 = 1, 1^1 = 0,简单理解:相同则为0,不同则为1.
如:3^5 的运算过程为:
(1)先将3和5转换成二进制的11和101
(2)再按对应的位分别进行运算,11位数不足补零
011
^ 101
-----------
110
(3)运算结果转换成10进制:6
异或运算的三个特点:
(1) 0^0=0, 0^1=1 0与任何数异或=任何数
(2) 1^0=1, 1^1=0 1与任何数异或 =任何数取反
(3) 任何数异或自己=把自己置0
异或运算的常见用途:
(1) 使某些特定的位翻转
例如对数10100001的第2位和第3位翻转,其他位不变,则可以将该数与00000110进行按位异或运算。
10100001^00000110 = 10100111
(2) 实现两个值的交换,而不必使用临时变量。
例如交换两个整数a=10100001,b=00000110的值,可通过下列语句实现:
a = a^b; //a=10100111
b = a^b; //b=10100001
a = a^b; //a=00000110
(3) 在汇编语言中经常用于将变量置零:
xor a,a
(4) 快速判断两个值是否相等
判断两个整数a,b是否相等,则可通过下列语句实现:
return ((a ^ b) == 0)
参考链接:https://blog.csdn.net/gtkknd/article/details/52798337
7 最有效率的算出2 * 8
的结果
2*8相当于2乘以2的3次方,所以这里只需要将2向左位移三位即可。即:2<<3 (向左位移为乘,向右为除)
8 关于 switch的表达式下面正确的是
1. byte 可以作为 switch 的表达式吗? 可以
2. long 可以作为 switch 的表达式吗? 可以
3. String 可以作为 switch 的表达式吗? 也可以,但是必须jdk1.7以后才支持
注意:
-
switch语句中,表达式的数据类型,可以是byte,short,int,char,enum(枚举),JDK7后可以接收字符串。但是不支持浮点类型。
-
在switch语句中,如果case的后面不写break,将出现case穿透现象,也就是不会再判断下一个case的值,直接向后运行,直到遇到break,或者整体switch结束
case穿透的测试:不判断条件,向下执行,直到遇到break为止。
//先看看正常情况
输出结果为:今天是周四
//将case 4中的break注释掉
输出结果为:
今天是周四
今天是周五
可以看到,明明day=4和5是不匹配的,但是case 5中的语句仍旧打印了,因为根本就没有对case 5进行判断,这就是case穿透现象。而case 5中遇到了break,所以case穿透现象也就在case 5中结束了。
9 return和 break以及 continue的区别?
return:如果后面接了东西,代表返回这个东西。如果仅仅是个return的话,代表结束当前方法 。 break:是跳出当前循环,然后执行循环外面的内容 continue:是终止本次循环,继续下次循环 break 和 continue 只能用在循环结构语句中。return,不仅可以用在循环结构中,也可以用在循环结构外
10 运算符 a++ 与 ++a 的区别
就单独运用的话,其实这两个并没有区别。但是参与到混合运算,则两者有所不同。 举例:b=a++和b=++a 假如原本a=5。 b=a++是先赋值,再+1.结果是b=5,而a=6. b=++a则是先自加一在赋值,也就是a和b都等于6.
扩充:a++或者a--
a=a++; 事实上,底层是这样:定义一个临时变量=a原来的值;a=a+1;b=临时变量;
public void test06() {
int a=3;
a=a++;
System.out.println(a);//输出3
}
11 Java 中到底是传值还是传地址?
事实上,java中传递的都是值,因为地址也是值。所以不管是传递基本数据类型还是引用数据类型,都是在传值。
12 指出下面变量的区别
int[] x;
int[] y[];
int[] x,y[]; // x是一维数组,y是二维数组
解释一下:
int[] a; // 一维数组a
int[][] b; // 二维数组b
int c[]; //一维数组,相当于int[] c
int[] d[]; //二维数组,相当于int[][] d
int[] e, f[]; //相当于int[]e和int[]f[];所以e是一维数组,f是二维数组
//一维数组:1)int[] x;2)int x[];
//二维数组:1)int[][] y;2)int y[][];3)int[]y[]
13 面向对象特征
封装、继承、多态 。如果非要再来一个的话,那就是抽象,不过我们一般比较认同的是前面三个。
-
封装: 把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。对外提供公有的方法以供操作。让调用者不需要知道怎么做,只需要知道做什么即可。
-
继承: 可以使得层次结构更清晰,实现了代码的可重复使用
-
多态 降低耦合,增强可替换性,提高了程序的可扩展性。
14 继承相关面试题一
//下面程序的输出结果是?
class Fu {
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu {
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
public class Test1 {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
打印:
fu
zi
30
20
10
15 继承相关的面试题二
public class Test {
public static void main(String[] args) {
Zi z =new Zi();
}
}
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() { // 内部系统默认有 super();
System.out.println("构造方法Zi");
}
}
打印:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
16 继承面试题三
class Person {
static {
System.out.println("Person 静态代码块"); //3
}
{
System.out.println("Person 构造代码块");//4 //6
}
public Person() {
System.out.println("Person 构造方法"); //5 //7
}
}
public class Demo{
static {
System.out.println("Demo静态代码块"); //1
}
public static void main(String[] args) {
System.out.println("我是main方法"); //2
Person p1 = new Person();
Person p2 = new Person();
}
}
小结:
1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
3.其次,初始化父类的普通成员变量和代码块,再执行父类的构造方法;
4.最后,初始化子类的普通成员变量和代码块,再执行子类的构造方法;
静态代码块在类第一次加载进内存的时候就会执行, 且只执行一次 构造代码块在构造方法真正要执行之前就会执行, 每次调用构造方法都会执行一次
静态代码块 执行:随着类的加载而执行且执行一次,优先于main方法和构造方法的执行。 作用:给类变量进行初始化赋值
17方法重写重载的面试题
-
Overload 重载能改变返回值类型吗? 可以,方法重载只看参数列表的不同。
-
Override 重写和 Overload 重载的区别?
重写: (一) 父类方法的参数列表必须完全与被子类重写的方法的参数列表相同 (二) 父类的返回类型必须与被子类重写的方法返回类型相同 (三) Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限。编写过Java程序的人就知道,
父类中的方法并不是在任何情况下都可以重写的,当父类中方法的访问权限修饰符为private时,该方法只能被自己的类访问,不能被外部的类访问,在子类是不能被重写的。如果定义父类的方法为public,在子类定义为private,程序运行时就会报错。
(四) 由于父类的访问权限修饰符的限制一定要大于被子类重写方法的访问权限修饰符,而private权限最小。
所以如果某一个方法在父类中的访问权限是private,那么就不能在子类中对其进行重写。如果重新定义,也只是定义了一个新的方法,不会达到重写的效果。 (五) 在继承过程中如果父类当中的方法抛出异常,那么在子类中重写父类的该方法时,也要抛出异常,而且抛出的异常不能多于父类中抛出的异常(可以等于父类中抛出的异常)。换句话说,重写方法一定不能抛出新的检查异常,或者比被重写方法声明更加宽泛的检查型异常。例如,父类的一个方法申明了一个检查异常IOException,在重写这个方法时就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。同样的道理,如果子类中创建了一个成员变量,而该变量和父类中的一个变量名称相同,称作变量重写或属性覆盖。但是此概念一般很少有人去研究它,因为意义不大。
重载:我们将名字相同,参数列表不同的两个(或多个)方法称为重载方法。 参数列表的不同体现在以下两点: 1 参数的类型不同 2 参数的个数不同
18 一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义
可以。这么做的目的只有一个,就是不让其它类创建本类对象,交给子类完成。
抽象类: 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类。 抽象类的子类必须全部重写抽象父类的抽象方法,除非该子类也是抽象类。。
19 abstract不能与哪些关键字共存
1)static
abstract修饰的是对象级别,static修饰的是类级别的,对象方法和类方法是冲突的。
2)final
final修饰的是常量级别的,不可被修改。abstract的目的就是为了让子类实现,显然final的存在会使得abstract变得没有意义。
3)private
private修饰的类或者方法只有自己能使用,子类无法访问,显然和abstract是矛盾的。
关于final 与 static的修饰总结
final 关键字的修饰特点:
-
修饰类,类不能被继承,相当于做了丁克
-
修饰方法,那么这个方法不能被重写
-
修饰变量,变量就变成了常量,只能被赋值一次
* final 修饰变量叫做常量,一般会与 public , static 共用
* 常量命名规范,如果是一个单词,所有字母大写,
如果是多个单词,每个单词都大写,中间用下划线隔开,
如 public static final MAX_AGE = 125;
* 如果修饰的变量是基本类型,是值不能被改变
* 在定义变量时, 就马上初始化【这种初始化方法比较常用】
在构造方法中, 进行初始化 [不常用]
* 修饰引用类型的变量,是地址值不能被改变,
即对象本身不可变, 但对象中的属性可以改变
修饰引用类型不可以赋值, 同类型的引用对象
final Person p = new Person("hxl", 18);
p.name = "xhl";
p.age = 16;
Person p2 = new Person();
p = p2; // 报错
p = new Person(); // 报错
static 关键字的特点:
-
随着类的加载而加载
-
优先于对象存在
-
被类的所有对象共享
-
如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
-
1. static 声明的成员属性可以通过类名调用
静态变量属于类,所以也称为为类变量
成员变量属于对象,所以也称为实例变量(对象变量)
推荐使用类名调用【强调】。
其实它本身也可以通过对象名调用。[不推荐, 会有警告]
静态修饰的内容一般我们称其为:与类相关的类成员
2. static 也可以用来修饰方法
静态方法只能访问静态的成员变量和静态的成员方法【掌握】
非静态方法可以访问静态的成员变量和静态的成员方法【掌握】
3. 在静态方法中是没有 this 关键字的, 如何理解呢?【掌握】
静态是随着类的加载而加载, this 是随着对象的创建而存在。
静态比对象先存在。
4. 如果一个类中所有的方法都是静态的
我们可以再多做一步, 私有构造方法, 不让其他类创建本类对象
确保用类名调用方法
public class Demo01 {
public static void main(String[] args) {
// Student stu = new Student();
Student.test01();
Student.say01();
Student.speak01();
}
}
class Student {
String name;
int age;
private Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
private Student() {
super();
// TODO Auto-generated constructor stub
}
static void test01() {
System.out.println("test01");
}
static void say01() {
System.out.println("say01");
}
public final static void speak01() {
System.out.println("speak01");
}
}
20 package,import,class有没有顺序关系?
-
ackage 只能有一个,必须放在java文件的第一行,
-
rt 只能放在 package 的下面,多个 import 应放在一起,
-
class 放在 package 或者import的下面
21 成员内部类
//要求:使用已知的变量,在控制台输出30,20,10。
public class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
22 int i=1234;System.out.println(i/1000*1000);输出的内容是?
输出的内容是1000。因为i/1000不会保留小数部分,所以等于1.在*1000等于1000。
知识点:ava中,整数使用+、-、*、/、%、++、--这些运算符,无论怎么计算,也不会得到小数
23 指出并解释下面哪里会编译错误
byte b1=1;
byte b2=2; //byte、short、char类型的变量在进行运算时,会自动转换为int类型。
byte b3=1+2; //这里不会报错,因为1+2在编译时会直接编译成3
byte b4=b1+b2; //报错,因为不知道b1+b2的值会不会超出byte的取值范围
System.out.println(b3);
System.out.println(b4);
public void test01() {
byte a=2;
//a=2*a; 编译错误
a*=2;
}
//byte、short、char类型的变量在进行运算时,会自动转换为int类型。
//a=2a;(这里是错误的,因为a是byte类型,而a*2是int类型)
//a+=2或a*=2等都是可以的,这源于运算符的特殊性。
24 谈一谈for循环和while循环的区别
控制条件语句所控制的那个变量,在for循环结束后,就不能再被访问到了,而while循环结束还可以继续使用,如果你想继续使用,就用while,否则推荐使用for。原因是for循环结束,该变量就从内存中消 失,能够提高内存的使用效率。 在已知循环次数的时候使用推荐使用for,循环次数未知的时推荐使用while。
25 java面向对象的六大原则(模式设计的六大原则)
-
单一职责
-
开放封闭
-
里氏替换
-
依赖倒置
-
接口隔离
-
迪米特法则(最少知道原则)
26 java有什么核心优势让其流行?
跨平台是JAVA语言的核心优势,在各个平台上都可以使用JAVA语言。JAVA还具有以下优势:
安全性,面向对象,简单性,高性能,分布式,多线程,健壮性。
27java是解释型语言还是编译型语言?
既可以说是编译型的(因为所有的Java代码都是要编译的,.java不经过编译就什么用都没有 ),也可以说是解释型的(因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释运行的,那也就算是解释的了),或者说是二者结合的。事实上,现在仅用编译型和解释型来区分编程语言已经有些力不从心了。
28标识符能不能以汉字开头?为什么?
可以,java规定了标识符要以数字、字母、美元符号和下划线组成并且不能以数字开头。而java默认采用的是unicode编码,在Unicode编码中一个汉字相当于一个字母,所以可以使用汉字开头。但是日常的开发中不建议使用汉字。并且参照阿里巴巴的编程规范的话,是不能以下划线和美元符号开头或者结尾,不能中英文混用(包括拼音),更不能使用汉字。
29java中有没有goto语句?有没有goto关键字?
java中没有goto语句。但是java中goto仍被作为保留字,所以有关键字。
30如何用科学计数法表示3.14
314E-2
十进制数表示形式: 3.14 0.314 3140.0
科学计数法表示: 314e-2 314E-3 314E1 e或者E表示10,后面代表次方
31java语言中整型常量的四种表现形式:
二进制:要求以0B或者0b开始,如:0B10110
八进制:要求以0开头,如015
十进制:不解释了
十六进制:要求以0X或者0x开头,如0x15
32浮点数能用于比较吗?
不能,浮点数是不精确的。如果需要比较,那么使用任意精度整数运算( BigInteger
)和任意精度十进制运算( BigDecimal
)
float a=123213123f;
float b=a+1;
System.out.println(a==b); //输出结果是true。
33java中垃圾回收的算法:
引用计数法、引用可达法(根搜索算法)
34布尔类型占用一位还是一个字节?
一位。
35 这种写法好不好?if(a==true)
不好,应改为if(a)
36java中使用哪个关键字来定义常量
final。一般和static配合使用。
37使用Scanner接收键盘输入,是否一定要加import Java.util.*;
不用,也可以写为import java.util.Scanner;或者使用Scanner的全类名.
38引用类型占用几个字节?
这个问题我真不清楚,放两个链接,大家参考一下
https://blog.csdn.net/uudou/article/details/47662237
https://oomake.com/question/1322554
39算术运算符中类型提升是怎么回事?int a=3,long b=3;a+b返回什么类型?
返回的是long类型。
知识点:
数据类型转换
自动转换:
• 将取值范围小的类型 自动提升为 取值范围大的类型
转换规则
• 范围小的类型向范围大的类型提升, byte、short、char 运算时直接提升为 int 。
byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
强制转换:
1. 将取值范围大的类型 强制转换成 取值范围小的类型 。
2. 比较而言,自动转换是Java自动执行的,而强制转换需要我们自己手动执行。
强烈注意
- 浮点转成整数,直接取消小数点,可能造成数据损失精度。
- int 强制转成 short 砍掉2个字节,可能造成数据丢失。
40 关系运算符中能不能这么写:1<a<3
不能。
41 这两个表达式分别返回什么结果?
((1<3)?"a":"b")+3+4; //应该返回a34
x=-2;x>0?1:(x==0?0:-1); //应该返回-1
42 什么情况下,加号会变成字符串连接符?
当字符串与字符串类型或者其他数据类型进行加法运算的时候。
43 4&5,4|5的结果分别是多少?4&&5这个操作可行吗?
4&5=4;
4|5=5;
4&&5 在java中这个操作不行!!!
在js中值为5.
在c语言中值为1(真).
解释:
44 int能否自动转换成byte,short,char? 是否有一定条件才能转换?
不能自动转换,需要强制类型转换。
45 long能自动转换成int吗?long能自动转换成float吗?
long不能自动转换成int,long可以自动转换为float。因为int的取值范围比long小,而float的取值范围比long大。
46自动类型转换中,容量小和容量大指的是什么意思?
容量大小指的是不同数据类型的存储数据的范围
47下面哪种写法比较好?
a)70L*60*24*365*70*20
b)70*60*24*365*70*20L
a写法比较好。因为第一种写法L放在前面,代表70是一个long类型的数,那么运算时会最早的转换为long类型进行运算。而b写法在最后面,那么前面的数在进行运算时仍旧是int类型,而多次相乘之后的值很可能超出int的取值范围,造成精度损失。所以a写法比较好。
48 简单讲一下& 和&&的区别,|和||的区别
简单举例:
如果是:
条件1&条件2,那么程序会判断条件1和条件2,只有条件1和条件2都为true时,返回值才是true,如果两者有一个的值为false或者两者都为false,那么返回值都是false。
&&叫做短路与,顾名思义,类似于电路中的短路。条件1&&条件2,同样是两个条件都为true时返回值才是true。只要有一个为false或者两者都为false则返回false。但是,这里和&就有区别了。如果条件1已经是false了,那么程序不会判断条件2,直接判定返回值为false。已经确定条件1是false了,那么结果必然为false,所以就不用判断条件2了,可以提升性能。
条件1|条件2,程序会判断条件1和条件2,只要条件1和条件2其中有一个的结果是true,那么返回值就是true。当然,如果两者的返回值都是true,最终结果也是true。
条件1||条件2,与短路与类似,如果程序判断条件1为true,那么结果必然为true,所以不需要判断条件2,可以直接返回最终结果为true,节省了性能。
49 为什么不能通过返回类型来区分重载
首先,java分为编译期和运行期。在调用的时候编译器不知道具体要使用哪一个方法,也就无法编译。例如有下面两个方法:
int sum(int a,int b);
long sum(int a,int b);
当调用sum求和方法时,如:sum(1,2),那么我们到底该调用哪个方法呢?显然,仅仅通过返回值类型来区分重载是不合理的。
50 ==和equals的区别
其实最大的一个区别点在于“==”是运算符,而equals是方法。很多人在回答这个问题的时候往往会忽略这点。
其次,==如果比较的是基本数据类型,那么比较的是数值是否相等。如果比较的是引用数据类型,那么比较的是引用对象的地址值是否一致。