第二天:JAVA面试八股文(一.Java基础篇)

学习目标:JAVA面试八股文(一.Java基础篇)

提示:第二天开学


学习内容:

提示:自己的学习计划

如下:
1.String能被继承吗 为什么用final修饰
2. String buffer和String builder区别
3. final、finally、finalize
4.Object中有哪些方法
5.说一下集合体系
6.ArrarList和LinkedList区别


学习内容:

提示:这里可根据自己的资源对照学习

1.String能被继承吗 为什么用final修饰:
a.在Java中,String类是一个final类,因此不能被继承。final关键字可以用来修饰类、方法和变量,一旦使用了final关键字,就表示它们不能再被修改或继承。
b.String类是不可变的,也就是说,一旦创建了一个字符串对象,它的值就不能再被改变了。这是通过将String类中所有可能导致其值改变的方法(如concat、replace等)都标记为final来实现的。如果允许String类被继承并修改其中的方法,那么很可能会导致字符串对象的值被意外地改变,从而引发一些安全问题和逻辑错误。
c.同时,String类作为Java中最常用的类之一,具有非常广泛的应用场景。为了保证程序的正确性和稳定性,Java设计者决定将String类标记为final,以防止不必要的风险和误操作。

// 以下代码会导致编译错误,因为String类是final的,不能被继承
public class MyString extends String {
    // ...
}

2. String buffer和String builder区别

StringBuffer和StringBuilder都是用来操作字符串的类,它们之间的主要区别在于线程安全性和性能。

线程安全性:

StringBuffer是线程安全的,所有对它的操作都是同步的,这意味着多个线程可以安全地同时调用StringBuffer的方法进行操作。
StringBuilder则不是线程安全的,它的操作没有被同步,因此在多线程环境下使用StringBuilder可能会出现线程安全问题。
性能:

由于StringBuffer的所有方法都是同步的,因此在单线程环境中,它的性能可能会略逊于StringBuilder。
StringBuilder由于不需要考虑线程安全,它的操作都是非同步的,因此在单线程环境中它具有更好的性能。
由于StringBuffer和StringBuilder之间的这些区别,我们可以根据具体的需求选择合适的类。如果在多线程环境中需要进行字符串操作,应该使用StringBuffer以确保线程安全;而在单线程环境中,为了获得更好的性能,可以选择使用StringBuilder。

public class Main {
    public static void main(String[] args) {
        StringBuffer stringBuffer = new StringBuffer();
        StringBuilder stringBuilder = new StringBuilder();

        // 在循环中向字符串对象追加内容
        for (int i = 0; i < 10000; i++) {
            final String str = "test" + i;
            // 使用StringBuffer进行字符串拼接
            new Thread(() -> {
                stringBuffer.append(str);
            }).start();

            // 使用StringBuilder进行字符串拼接
            new Thread(() -> {
                stringBuilder.append(str);
            }).start();
        }

        // 输出结果长度
        System.out.println("StringBuffer 长度:" + stringBuffer.length());
        System.out.println("StringBuilder 长度:" + stringBuilder.length());
    }
}

3. final、finally、finalize :
final

		A.final是Java语言中的一个关键字,可以用来修饰类、方法和变量。

当final修饰一个类时,该类不能被继承。
当final修饰一个方法时,该方法不能被子类重写。
当final修饰一个变量时,该变量只能被赋值一次,也就是说它是常量。
finally

		B.finally也是Java语言中的一个关键字,用于定义在try-catch语句块中的一个代码块。

无论是否发生异常,finally中的代码都会被执行。
finally通常用于释放资源或者确保某些代码一定会被执行,比如关闭数据库连接、文件流等。
finalize

		C.finalize是Object类中的一个方法,用于在对象被垃圾回收之前执行一些清理操作。

finalize方法在对象被垃圾回收器回收之前被调用,但不能保证它一定会被调用。
finalize方法通常用于释放非Java资源,比如文件句柄、网络连接等。

public class Main {
    public static void main(String[] args) {
        // final关键字的使用
        final int a = 10;
        // 下面代码会提示编译错误,因为a是常量,不能再次赋值
        // a = 20;

        // finally关键字的使用
        try {
            System.out.println("try block");
            throw new Exception("exception message");
        } catch (Exception ex) {
            System.out.println("catch block");
        } finally {
            System.out.println("finally block");
        }

        // finalize方法的使用
        try {
            Main obj = new Main();
            obj = null;
            // 强制垃圾回收
            System.gc();
            Thread.sleep(1000);
            System.out.println("End of program");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize method called");
    }
}

4.Object中有哪些方法
equals(Object obj):判断当前对象是否与给定对象相等。
hashCode():返回当前对象的哈希码值。
toString():返回当前对象的字符串表示。
getClass():返回当前对象的运行时类。
clone():创建并返回当前对象的副本。
finalize():在对象被垃圾回收之前调用,用于执行一些清理操作。
notify():唤醒在当前对象上等待的单个线程。
notifyAll():唤醒在当前对象上等待的所有线程。
wait():导致当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者指定时间已过。
wait(long timeout):导致当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者指定时间已过。
wait(long timeout, int nanos):导致当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者指定时间已过。
除了上述方法之外,Object类还有一些其他的方法,用于监视对象的锁定状态、比较对象的引用等。需要注意的是,Object类中的这些方法都是被protected修饰的,因此在子类中可以进行重写和访问。

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Person)) {
            return false;
        }
        Person other = (Person) obj;
        return Objects.equals(name, other.name) && age == other.age;
    }
}

// 测试代码
Person p1 = new Person("Tom", 20);
Person p2 = new Person("Tom", 20);
System.out.println(p1.equals(p2)); // 输出true

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

// 测试代码
Person p = new Person("Tom", 20);
System.out.println(p.hashCode()); // 输出-1608389035

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 测试代码
Person p = new Person("Tom", 20);
System.out.println(p); // 输出Person{name='Tom', age=20}

5.集合体系:
Java集合体系是用于存储和操作数据的一组类和接口的集合。它提供了各种类型的集合,如List、Set、Map等,以及它们的实现类,以满足不同的数据结构需求。下面是Java集合体系的主要部分:

Collection接口:Collection是所有集合类的根接口,它代表一组对象,这些对象也称为集合的元素。Collection接口继承自Iterable接口,提供了对集合元素进行基本操作的方法,如添加、删除、遍历等。

List接口:List是有序集合,允许重复元素。它的常见实现类有ArrayList、LinkedList、Vector等。
Set接口:Set是不允许重复元素的集合,通常用于存储不重复的对象。它的常见实现类有HashSet、LinkedHashSet、TreeSet等。
Map接口:Map用于存储键值对映射关系的集合,其中每个键值对称为一个条目(entry)。Map中的键是唯一的,但值可以重复。

常见的Map实现类包括HashMap、LinkedHashMap、TreeMap等。

除了上述核心接口和实现类外,Java集合体系还包括一些其它的类和接口,如Queue接口、Deque接口、Iterator接口等,它们提供了各种不同的集合类型和操作方式。

import java.util.List;
import java.util.ArrayList;

public class ListExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();

        // 添加元素
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");

        // 获取元素
        String firstFruit = fruits.get(0);
        System.out.println("第一个水果:" + firstFruit);

        // 修改元素
        fruits.set(1, "Mango");
        System.out.println("修改后的水果列表:" + fruits);

        // 删除元素
        fruits.remove(2);
        System.out.println("删除后的水果列表:" + fruits);

        // 遍历元素
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}

import java.util.Set;
import java.util.HashSet;

public class SetExample {
    public static void main(String[] args) {
        Set<String> colors = new HashSet<>();

        // 添加元素
        colors.add("Red");
        colors.add("Green");
        colors.add("Blue");

        // 判断是否包含元素
        boolean containsRed = colors.contains("Red");
        System.out.println("是否包含红色:" + containsRed);

        // 删除元素
        colors.remove("Green");
        System.out.println("删除绿色后的颜色集合:" + colors);

        // 遍历元素
        for (String color : colors) {
            System.out.println(color);
        }
    }
}

~~我们使用Set接口的实现类HashSet来创建一个颜色集合。我们通过add()方法添加元素,通过contains()方法判断是否包含某个元素,通过remove()方法删除元素。最后,我们使用增强型for循环遍历集合中的元素并打印出来。
6.ArrarList和LinkedList区别
ArrayList和LinkedList是Java集合框架中List接口的两个不同实现类,它们在内部数据结构和性能方面有所不同。

内部数据结构:

ArrayList:ArrayList使用动态数组作为其内部数据结构。它通过数组实现元素的存储和访问,可以根据需要调整数组的大小。由于基于数组的实现,ArrayList适用于频繁访问和随机访问元素的场景。
LinkedList:LinkedList使用双向链表作为其内部数据结构。每个节点包含一个元素和指向前一个节点和后一个节点的引用。由于基于链表的实现,LinkedList适用于频繁插入和删除元素的场景。
访问效率:

ArrayList:由于基于数组实现,ArrayList可以通过索引直接访问元素,因此在随机访问、按索引查找元素时具有较高的效率。但是,在插入和删除元素时需要移动其他元素,效率较低。
LinkedList:由于基于链表实现,LinkedList在插入和删除元素时只需要修改节点的引用,不需要移动其他元素,因此在插入和删除操作上具有较高的效率。但是,在随机访问和按索引查找元素时需要遍历链表,效率较低。
空间占用:

ArrayList:ArrayList在内存中连续存储元素,因此相对于LinkedList而言,它的空间占用更小。
LinkedList:LinkedList在内存中通过节点和引用存储元素,因此相对于ArrayList而言,它的空间占用更大。

import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<Integer> numbers = new ArrayList<>();

        // 添加元素
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // 遍历元素
        for (int i = 0; i < numbers.size(); i++) {
            System.out.println(numbers.get(i));
        }
    }
}

import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> names = new LinkedList<>();

        // 添加元素
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");

        // 遍历元素
        for (String name : names) {
            System.out.println(name);
        }
    }
}

在上述示例中,我们使用LinkedList创建一个字符串列表。通过add()方法添加元素。最后,通过增强型for循环遍历列表中的元素并打印出来。

剩下的明天继续 加油干

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值