Java面试清单

本文围绕Java基础面试问题展开,涵盖跨平台性、JDK与JRE区别、常量变量、数据类型转换等内容。详细解释了如==和equals的区别、static的作用、继承对成员变量和方法的影响等,还探讨了抽象类存在的意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础问答

1、解释java语言的跨平台性?

   与各个操作系统对应的jvm帮我们屏蔽了系统间的差异。比如我在windows环境下开发,代码放到linux环节下运行。很常见的一个跨系统操作,java代码都是同一份,就是因为win版的jvm,和Linux版的jvm发挥了作用。让我们的代码可以编译一次生成class文件,在不同的平台自由运行。


2、 JDK 和 JRE 有什么区别?

   - JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。
   - JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境。
   具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。
简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。(大多数人安装jdk的时候都安装了jre,没有这个必要。其实可以在安装jdk的时候勾掉jre选项)


3、 何为常量?何为变量?解释 int a = 100;

   常量:程序的运行过程中,内容保持不变。 例如 3,10,“学习java字符串” 诸如此类。
   变量:程序的运行过程中,内容发生变化。 例如 int a ,char c 。变量使用前记得要赋初值,不然编译错误。
   int a = 100; 从中划开,首先100是个常量,int a 定义了一个变量(内存中开辟了一块空间,这个空间有地址和内容(int 4个字节的范围),使用a代表这个内存空间的地址,从而来操纵这个空间的内容) 然后进行赋值,内容进行填充,换句话说,a所代表的地址空间是不变的,其中的内容是不断变化的。程序走到下一步,a = 200,或 a = 300;


4、 描述二进制(0,1)bit,字节(byte),十进制之间的关系?

  计算机只能识别0和1,产生了沟通问题,后来为了方便都用字节沟通。
  1个 bit 就是1位0,或者1位1 。1个字节(byte)=8个bit位(也就是8位0或1)那么有个问题8位的0和1组合那有非常多,有最大01111111和最小10000000的组合,有其范围转十进制范围为(-128~127),字节(byte)类型最终可以存放多大的数据就这样被决定出来了。字节是计算机存储的最小单元。
   总结: 1byte(字节)=8bit bit是1位0或者1组成,所以8位的0或者1,十进制范围(-128~127),换句话数byte类型变量只能存放(-128-127)之间的数据。 那么,short是2个字节,16位0或1组成,int 是4个字节,32位0或者1组成。二进制转十进制,十进制转二进制这里不做讨论。win环境下,点击一个文件查看属性显示多少字节和多少KB。1KB=1024byte,1KB=1024字节。


5、a++,++a 注意事项?

单独使用: a++单独一行使用,先加后加无所谓,最终结果都是 1;

int a = 0;
a++;
System.out.println(a);// 1

非单独使用:先赋值,然后加1,打印结果为0,后加1;

int a = 0;
System.out.println(a++); //0
System.out.println(a); //1

++a:单独使用无所谓,非单独使用,则先加1后赋值。

int a = 0;
System.out.println(++a); // 1

6、if(){},if(){}else{},if(){}else if(){}else{}代码的执行?

if语句是选择结构,看条件而执行。

格式执行
if(){}有可能执行,也有可能不执行
if(){}else{}二选一,非此即彼
if(){}else if(){}else{}择其一执行

7、数据类型转换问题?

小类型–>大类型 不用操心,默认完成。(自动类型转换)例如:

long l = 100;// ok

整型默认为int,浮点默认为double。100是int,int型赋值给long型,自动完成。

大类型–>小类型 ,需要我们强制类型转换如:

int i =  100L; // 编译错误
int i =  (int) 100L;  // long型强转为 int型,可能会损失精度

注意了:代码正常这是为啥呢?

byte b = 100  // 代码ok

byte b = 128  // 代码错误

解释:编译器帮我们检查,100虽然是int,但是大小却在byte范围之内,不用强转类型转换,编译器帮我们完成,所以代码ok。如果超过byte范围,那么编译错误。
再有如下代码是错误的。

byte b = 100;
b = b+1; // 代码错误

解释:第一行代码没问题,解释如上,但是第二行代码,编译阶段是不做运算的,这个运算结果是否满足byte取值范围,不得而知,所有编译不能让其通过。任何相加减都是存在着不确定性。


8、如下是否是重载?

本类中方法名相同,参数列表不同,即方法重载,参数列表不同,包含个数和类型。
例如:如下不是重载

public void Overload(int a ,int b)
public int Overload(int c,int z)

要点: 方法名,参数列表 【和别的因素无关 】


9、String str = new String(“Hello World”); 创建了几个对象?

解释:因为有new,所以堆中必然有一个对象。另外,如果常量池中已有"Hello World",则不创建,没有,则在常量池中创建。所以这句代码,究竟在内存中创建一个还是两个对象,视情况而定。


10、判断如下代码的结果
String s1 = "a";
String s2 = s1 + "b";  // 产生一个新的字符串,在堆中。
String s3 = "a" + "b"; // 只会产生一个对象,编译器对多个字符串常量相“+”做了优化,直接放到常量池中了。
System.out.println(s2 =="ab");	//false
System.out.println(s3 == "ab");	//true
System.out.println(s2 == s3);	//false

""双引号的字符串都在常量池中,多个常量相加如 String c = “a”+“b”+“c”; 等同 String c=“abc”;

切记: String str = “abc”; str是字符串引用,“abc”是字符串常量,字符串常量一旦创建是不可变的,但是str引用是可变的。


11、== 和 equals 的区别是什么?
== 解读

对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  • 基本类型:比较的是值是否相同;
  • 引用类型:比较的是引用是否相同;(判断对象是否是同一个)
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的是值,所以结果都为 true。

equals 解读

equals 本质上就是 ==,Object中的equals比较的就是引用值,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。

首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

class Cat {
    public Cat(String name) {
        this.name = name;
    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Cat c1 = new Cat("咪咪");
Cat c2 = new Cat("咪咪");
System.out.println(c1.equals(c2)); // false

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

public boolean equals(Object obj) {
        return (this == obj);
}

原来 equals 本质上就是 ==。

那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:

String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true

同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。

总结 : == 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。


11、Java 中的 Math. round(-1. 5) =?Math. ceil(-11.2) =?Math. floor(-11.2) =?

等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。四舍五入
等于-11.0,向上取整。
等于-12.0,向下取整。
记住数轴的样子,从左到右,越来越大。


12、简述static的作用和你的一些思索?
  • static修饰成员变量主要实现对象间共享数据的目的,静态成员和静态方法都是隶属于类的特征。

  • 静态方法只能访问静态成员,实例方法可以使用静态和非静态成员,因为,静态先存在内存中,非静态后存在内存。一般访问需要用类名点 或者实例点 的方式访问,以免混淆将静态成员变量当成普通成员变量,推荐使用类名点的方式。静态方法不能使用this关键字。

  • 静态代码块,优先于main()和构造方法,主要作用是初始化静态成员。

  • static修饰的内容(成员+方法+代码块)随类的加载而加载,仅加载一次,存储在方法区中的静态区。


13、谈谈继承?

继承解决共性抽取的问题,联想static,static是对象公用一份儿,继承是你有我有大家有。共性的代码抽取到父类中,子类只需要继承即可获得。
从三个方面阐述:继承对成员变量,成员方法,构造器的影响

成员变量
  1. 变量不重名
    子类父类中出现不重名的成员变量,这时的调用是没有影响的

  2. 变量重名
    直接通过子类对象访问成员变量:Zi zi = new Zi(); zi.num;
    等号左边是谁,就优先用谁,没有则向上找。
    间接通过成员方法访问成员变量: zi.methodZi(); zi.methodFu();
    该方法属于谁(方法要是重名请看下面),就优先用谁的成员,没有则向上找。

public class Fu { //父类
    int num = 100; 
    public void methodFu() {
        // 使用的是本类当中的,不会向下找子类的
        System.out.println(num);
    }
}
public class Zi extends Fu{  // 子类
    int num = 200;
    public void methodZi() {
        // 因为本类当中有num,所以这里用的是本类的num
        System.out.println(num);
    }
}

public class Hello {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("zi.num="+zi.num); // 200 普通调用,对象.成员变量 看左边(Zi zi)
        System.out.println("===========");
        // 这个方法是子类的,优先用子类的,没有再向上找
        zi.methodZi(); // 200
        // 这个方法是在父类当中定义的,
        zi.methodFu(); // 100
    }
}
成员方法
  1. 方法不重名:Zi zi = new Zi(); zi.method();
      如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。

  2. 方法重名(特例重写)
     概念:在继承关系当中,方法的名称一样,参数列表也一样。
     重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
     重载(Overload):方法的名称一样,参数列表【不一样】。
     方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

  • 创建的对象是谁(new),就优先用谁的方法,如果没有则向上找。
  • 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
方法覆盖重写的注意事项:

1. 必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

2. 子类方法的返回值必须【小于等于】父类方法的返回值范围。
小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。

3. 子类方法的权限必须【大于等于】父类方法的权限修饰符。
小扩展提示:public > protected > (default) > private
构造器
public class Fu { //父类
    public Fu() {
        System.out.println("父类无参构造");
    }
    public Fu(int num) {
        System.out.println("父类有参构造!");
    }
}
public class Zi extends Fu {

    public Zi() {
        super(); // 在调用父类无参构造方法
//      super(20); // 在调用父类重载的构造方法
        System.out.println("子类构造方法!");
    }
    public void method() {
//      super(); // 错误写法!只有子类构造方法,才能调用父类构造方法。
    }
}
/*
继承关系中,父子类构造方法的访问特点:

1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
2. 子类构造可以通过super关键字来调用父类重载构造。
3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
 */
/*
super关键字的用法有三种:
1. 在子类的成员方法中,访问父类的成员变量。
2. 在子类的成员方法中,访问父类的成员方法。
3. 在子类的构造方法中,访问父类的构造方法。
 */
public class Zi extends Fu {
    int num = 20;
    public Zi() {
        super();
    }
    public void methodZi() {
        System.out.println(super.num); // 父类中的num
    }
    public void method() {
        super.method(); // 访问父类中的method
        System.out.println("子类方法");
    }
}

super关键字用来访问父类内容,而this关键字用来访问本对象内容。
A. this(…)调用也必须是构造方法的第一个语句,唯1一个。
B. super和this两种构造调用,不能同时使用。

public void showNum() {
    int num = 10;
    System.out.println(num); // 局部变量
    System.out.println(this.num); // 本类中的成员变量
    System.out.println(super.num); // 父类中的成员变量
}


14、既然有了普通类,为何还需要抽象类?是否多余了?

解释:抽象类还是隶属于类,从名字就可以看出。举例,假如我们有一个动物类,有一个共性行为,吃东西。吃东西这个行为无法准确描述,动物们的吃东西方式各自不同。从而方法的方法体是不能确定的。给这样的类起个名字叫抽象类。同时也是抽象类无法直接实例的原因。

public abstract class Abs{
    public abstract void eat();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值