面试必背 - Java篇(一)

1、面向对象的特征有哪些方面?

面向对象的特征主要有以下几个方面:

  • 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

    例:

    abstract class Animal {
        public abstract void makeSound(); // 抽象方法,让子类去实现
    }
    
    class Dog extends Animal {
        @Override
        public void makeSound() {
            System.out.println("汪汪汪");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Animal animal = new Dog(); // 将Dog对象赋值给Animal类型的引用变量
            animal.makeSound(); // 调用makeSound方法,输出“汪汪汪”
        }
    }
    
    
  • 封装:封装是将对象的属性和方法包装在一起,对外提供一组简单的接口,隐藏内部实现细节,达到数据安全和简化编程的目的。

    例:

    class Person {
        private String name; // 私有属性,只能在类内部访问
    
        public Person(String name) { // 构造方法,用于创建对象时初始化属性
            this.name = name;
        }
    
        public String getName() { // getter方法,用于获取属性值
            return name;
        }
    
        public void setName(String name) { // setter方法,用于设置属性值
            this.name = name;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Person person = new Person("张三"); // 创建一个Person对象
            System.out.println(person.getName()); // 调用getName方法,输出“张三”
            person.setName("李四"); // 调用setName方法,将name属性设置为“李四”
            System.out.println(person.getName()); // 再次调用getName方法,输出“李四”
        }
    }
    
  • 继承:继承是子类自动拥有父类所有属性和方法的过程,可以实现代码复用。

    例:

    class Animal {
        public void makeSound() {
            System.out.println("动物发出声音");
        }
    }
    
    class Dog extends Animal {
        @Override
        public void makeSound() {
            System.out.println("汪汪汪");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Animal animal = new Dog(); // 创建一个Dog对象,并将其赋值给Animal类型的引用变量
            animal.makeSound(); // 调用makeSound方法,输出“汪汪汪”
        }
    }
    
    
  • 多态:多态是指不同类的对象对同一消息会作出不同的响应。

    例:

    interface Flyable {
        void fly(); // 定义一个飞行接口
    }
    
    class Bird implements Flyable {
        @Override
        public void fly() {
            System.out.println("鸟儿展翅高飞");
        }
    }
    
    class Airplane implements Flyable {
        @Override
        public void fly() {
            System.out.println("飞机在天空中翱翔");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Flyable bird = new Bird(); // 创建一个Bird对象,并将其赋值给Flyable类型的引用变量
            Flyable airplane = new Airplane(); // 创建一个Airplane对象,并将其赋值给Flyable类型的引用变量
            bird.fly(); // 调用bird对象的fly方法,输出“鸟儿展翅高飞”
            airplane.fly(); // 调用airplane对象的fly方法,输出“飞机在天空中翱翔”
        }
    }
    
    
2、访问修饰符 public,private,protected,以及不写(默认)时的区别?

public:公共访问修饰符,表示该成员可以被任何类访问。

private:私有访问修饰符,表示该成员只能被本类中的成员访问。

protected:受保护的访问修饰符,表示该成员可以被本类、子类和同一个包中的其他类访问。

default(不写):默认访问修饰符,表示该成员可以被同一包中的其他类访问。

例:

// 定义一个公共类
public class Person {
    // 公共变量,可以被任何类访问
    public String name;

    // 私有变量,只能在本类中访问
    private int age;

    // 受保护的变量,可以被本类、子类和同一个包中的其他类访问
    protected String gender;

    // 默认访问修饰符,表示该成员可以被同一包中的其他类访问
    String address;
}

// 定义一个子类
class Student extends Person {
    // 可以访问父类的公共变量
    public void setName(String name) {
        this.name = name;
    }

    // 无法访问父类的私有变量
    // private void setAge(int age) {
    //     this.age = age;
    // }

    // 可以访问父类的受保护的变量
    protected void setGender(String gender) {
        this.gender = gender;
    }

    // 可以访问父类的默认访问修饰符变量
    void setAddress(String address) {
        this.address = address;
    }
}
3、String 是最基本的数据类型吗?

String 不是最基本的数据类型,它是 Java 中的一种引用数据类型。Java 中有八种基本数据类型:byte、short、int、long、float、double、char、boolean。

下面是一个使用基本数据类型的代码示例:

public class BasicDataTypes {
    public static void main(String[] args) {
        // 整型变量
        int num1 = 10;
        int num2 = 20;
        int sum = num1 + num2;
        System.out.println("整型相加结果:" + sum);

        // 浮点型变量
        double num3 = 3.14;
        double num4 = 2.718;
        double product = num3 * num4;
        System.out.println("浮点型相乘结果:" + product);

        // 字符型变量
        char letter = 'A';
        System.out.println("字符型变量值:" + letter);

        // 布尔型变量
        boolean flag = true;
        System.out.println("布尔型变量值:" + flag);
    }
}

输出结果:

整型相加结果:30
浮点型相乘结果:8.538
字符型变量值:A
布尔型变量值:true
4、float f=3.4;是否正确?

float f=3.4不是正确的。在Java中, 在Java中,浮点数默认为double类型,因此需要使用f后缀将其转换为float类型。下面是一个使用float类型的代码示例:

public class FloatExample {
    public static void main(String[] args) {
        // 声明一个float类型的变量
        float f = 3.4f;

        // 输出变量的值和类型
        System.out.println("变量f的值为:" + f);
        System.out.println("变量f的类型为:" + typeof(f));
    }
}

输出结果:

变量f的值为:3.4
变量f的类型为:class java.lang.Float
5、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

short s1 = 1; s1 = s1 + 1; 这行代码是没有错误的,它的作用是将变量s1的值加1后重新赋值给s1。

short s1 = 1; s1 += 1; 这行代码也是没有错误的,它的作用是将变量s1的值加1后直接更新到原来的值上。

下面是带注释的代码示例:

// 定义一个short类型的变量s1,并初始化为1
short s1 = 1;

// 将s1的值加1,并将结果重新赋值给s1
s1 = s1 + 1;

// 将s1的值加1,并直接更新到原来的值上(等价于s1 = s1 + 1)
s1 += 1;
6、Java 有没有 goto?

Java 中没有 goto 语句。在 Java 中,goto 语句被认为是一种不良的编程习惯,因为它会导致代码难以理解和维护。相反,Java 提供了其他控制流语句,如 if、for、while 等,来控制程序的执行流程。

下面是一个使用 if 语句的示例代码,它实现了与 goto 语句相同的功能:

public class GotoExample {
    public static void main(String[] args) {
        int i = 0;
        boolean flag = false;

        while (!flag) {
            if (i == 5) {
                flag = true;
            } else {
                i++;
            }
        }

        System.out.println("程序结束");
    }
}

在上面的代码中,我们使用了一个 while 循环和一个 if 语句来模拟 goto 语句的行为。当 i 的值等于 5 时,我们将 flag 设置为 true,这将导致 while 循环结束。否则,我们将 i 的值加 1,并继续执行循环。

需要注意的是,虽然上面的代码实现了与 goto 语句相同的功能,但它并不是一个好的编程实践。在实际开发中,我们应该尽可能避免使用 goto 语句,而是使用更加清晰和易于维护的控制流语句来编写代码。

7、int 和 Integer 有什么区别?

int 和 Integer 都是 Java 中的基本数据类型,但它们之间有一些区别。

  1. int 是基本数据类型,而 Integer 是对象类型。
  2. int 是原始数据类型,它的值直接存储在内存中,而 Integer 是一个包装类,它的值存储在一个对象中。
  3. int 的取值范围是 -2^31 ~ 2^31-1,而 Integer 的取值范围是 -2^31 ~ 2^31-1 之间。
  4. int 是值传递,而 Integer 是引用传递。

下面是一个简单的示例代码,演示了 int 和 Integer 的区别:

public class IntAndIntegerExample {
    public static void main(String[] args) {
        // 定义一个 int 类型的变量 i,并赋值为 10
        int i = 10;
        System.out.println("i 的值:" + i); // 输出 i 的值:10

        // 定义一个 Integer 类型的变量 j,并赋值为 null
        Integer j = null;
        System.out.println("j 的值:" + j); // 输出 j 的值:null

        // 将 i 的值赋给 j
        j = i;
        System.out.println("j 的值:" + j); // 输出 j 的值:10

        // 修改 j 的值
        j = 20;
        System.out.println("j 的值:" + j); // 输出 j 的值:20
    }
}

在上面的代码中,我们定义了一个 int 类型的变量 i,并将其赋值为 10。然后,我们定义了一个 Integer 类型的变量 j,并将其赋值为 null。接下来,我们将 i 的值赋给了 j,并输出了 j 的值。最后,我们修改了 j 的值,并再次输出了 j 的值。

需要注意的是,由于 Integer 是一个对象类型,因此在将 int 类型的值赋给 Integer 类型的变量时,需要进行拆箱操作。而在将 Integer 类型的值赋给 int 类型的变量时,则不需要进行拆箱操作。

8、和&&的区别?

& 和 && 都是用于逻辑运算的运算符,但它们之间有一些区别。

  1. & 是按位与运算符,它可以用于整数类型和布尔类型。当用于整数类型时,它会将两个操作数进行按位与运算;当用于布尔类型时,它会将两个操作数进行逻辑与运算。
  2. && 是短路与运算符,它只能用于布尔类型。当第一个操作数的值为 false 时,它不会计算第二个操作数的值,因为无论第二个操作数的值是什么,结果都是 false。

下面是一个简单的示例代码,演示了 & 和 && 的区别:

public class AndOperatorExample {
    public static void main(String[] args) {
        // 定义两个整数变量 a 和 b,并初始化为 5 和 3
        int a = 5;
        int b = 3;
        System.out.println("a & b 的结果是:" + (a & b)); // 输出 a & b 的结果是:1

        // 定义两个布尔变量 c 和 d,并初始化为 true 和 false
        boolean c = true;
        boolean d = false;
        System.out.println("c && d 的结果是:" + (c && d)); // 输出 c && d 的结果是:false

        // 定义一个布尔变量 e,并初始化为 true
        boolean e = true;
        System.out.println("e & d 的结果是:" + (e & d)); // 输出 e & d 的结果是:false
    }
}

在上面的代码中,我们分别使用了 & 和 && 运算符对整数和布尔类型的变量进行了逻辑运算。可以看到,当使用 & 运算符时,我们需要将整数类型的变量转换为布尔类型,然后再进行逻辑与运算;而当使用 && 运算符时,我们可以直接进行逻辑与运算,不需要进行类型转换。

9、解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

栈(stack)、堆(heap)和方法区(method area)是Java虚拟机中用于存储数据的三个主要部分。它们的作用和用法如下:

  1. 栈(stack)

栈是一种线性数据结构,它用于存储局部变量、方法参数、返回值等。每当一个方法被调用时,Java虚拟机会在栈上创建一个栈帧(frame)来存储该方法的相关信息。每个栈帧包含了方法的局部变量表、操作数栈、动态链接和方法出口等信息。当方法执行完毕后,对应的栈帧会被销毁。

下面是一个简单的示例代码,演示了栈的用法:

public class StackExample {
    public static void main(String[] args) {
        // 创建一个整数变量并赋值为10
        int num = 10;
        // 调用方法,将num作为参数传入
        System.out.println("num的值是:" + add(num));
    }
    
    public static int add(int a) {
        // 创建一个整数变量并赋值为20
        int b = 20;
        // 计算a和b的和,并将结果返回
        return a + b;
    }
}

在上面的代码中,我们定义了一个add方法,该方法接收一个整数参数a,并返回a和b的和。在main方法中,我们创建了一个整数变量num,并将其作为参数传入add方法。当add方法被调用时,Java虚拟机会在栈上创建一个栈帧来存储add方法的局部变量表、操作数栈等信息。当add方法执行完毕后,对应的栈帧会被销毁。

  1. 堆(heap)

堆是一种动态分配的内存区域,它用于存储对象实例。当我们创建一个对象时,Java虚拟机会在堆上为其分配一块连续的内存空间,并将该对象的引用存储在栈帧中。当我们需要访问该对象时,可以通过栈帧中的引用来访问堆上的内存空间。

下面是一个简单的示例代码,演示了堆的用法:

public class HeapExample {
    public static void main(String[] args) {
        // 创建一个字符串对象,并将其引用存储在栈帧中
        String str = new String("Hello, world!");
        // 输出字符串的内容
        System.out.println(str);
    }
}

在上面的代码中,我们创建了一个字符串对象,并将其引用存储在栈帧中。当str被访问时,Java虚拟机会通过栈帧中的引用来访问堆上的内存空间,并输出字符串的内容。

  1. 方法区(method area)

方法区是一种专门用于存储类信息、常量、静态变量等数据的区域。它与堆一样,也是在Java虚拟机启动时由JVM自动管理的。方法区的大小可以通过-Xmx和-Xms参数进行设置。

下面是一个简单的示例代码,演示了方法区的用法:

public class MethodAreaExample {
    public static void main(String[] args) {
        // 获取当前类的Class对象
        Class<?> clazz = HeapExample.class;
        // 获取clazz的方法名数组
        String[] methodNames = clazz.getDeclaredMethods();
        // 遍历方法名数组,并输出每个方法的名称
        for (String methodName : methodNames) {
            System.out.println(methodName);
        }
    }
}

在上面的代码中,我们首先获取了HeapExample类的Class对象,然后通过getDeclaredMethods()方法获取了该类的所有方法名数组。最后,我们遍历了方法名数组,并输出了每个方法的名称。需要注意的是,由于方法区是与类相关的,因此只有在同一个类中才能访问到方法区中的数据。

10、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?

Math.round() 是 JavaScript 中的一个内置函数,用于将一个数字四舍五入到最接近的整数。如果省略第二个参数,则默认为0。

对于第一个问题,Math.round(11.5) 的结果为 12,因为 11.5 四舍五入后最接近的整数是 12。

对于第二个问题,Math.round(-11.5) 的结果为 -11,因为 -11.5 四舍五入后最接近的整数是 -12,但由于 Math.round() 函数遵循“四舍六入五成双”的规则,即当小数部分为 5 时,会舍入到最近的偶数,因此最终结果为 -11。

下面是代码解释和注释:

// 使用 Math.round() 函数将 11.5 四舍五入到最接近的整数
var result1 = Math.round(11.5); // 结果为 12

// 使用 Math.round() 函数将 -11.5 四舍五入到最接近的整数
var result2 = Math.round(-11.5); // 结果为 -11,因为 Math.round() 函数遵循“四舍六入五成双”的规则
switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?

switch 语句可以作用在 byte、long 和 String 类型上。

对于 byte 类型,switch 语句会根据 byte 的值进行匹配,并执行相应的 case 分支。例如:

byte b = 1;
switch (b) {
    case 1:
        System.out.println("b 的值为 1");
        break;
    case 2:
        System.out.println("b 的值为 2");
        break;
    default:
        System.out.println("b 的值不是 1 或 2");
}

对于 long 类型,switch 语句同样会根据 long 的值进行匹配,并执行相应的 case 分支。例如:

long l = 3L;
switch (l) {
    case 1L:
        System.out.println("l 的值为 1");
        break;
    case 2L:
        System.out.println("l 的值为 2");
        break;
    default:
        System.out.println("l 的值不是 1 或 2");
}

对于 String 类型,switch 语句会根据字符串的内容进行匹配,并执行相应的 case 分支。例如:

String str = "hello";
switch (str) {
    case "world":
        System.out.println("str 的值为 world");
        break;
    case "hello":
        System.out.println("str 的值为 hello");
        break;
    default:
        System.out.println("str 的值不是 world 或 hello");
}

需要注意的是,如果 switch 语句中的值与任何 case 都不匹配,则会执行 default 分支。如果没有 default 分支,且没有任何 case 匹配,则会出现编译错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值