学习java基础知识的第四天

1、有哪些垃圾收集算法?以及各自的特点是什么?

1)标记-清除法:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。缺点:效率低,空间利用率低,会产生大量不连续的碎片。
2)复制算法:将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,将存活的对象复制到另一块中,再把使用的空间一次性清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
3)标记-整理法:结合老年代的特点提出的一种标记算法,标记过程同标记-清除算法,但是在回收过程中,是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
4)分代收集算法:当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。

2、什么是泛型?

泛型一般用于实现代码的重用和抽象,使用泛型可以提高代码的可读性、可维护性和类型安全性,可以使我们编写一次代码,然后在不同的类型上进行实例化。
在Java中,泛型可以被用于类、接口和方法中,用于指定一种通用的类型或一组类型。使用泛型可以提高代码的可读性、可维护性和类型安全性,可以使我们编写一次代码,然后在不同的类型上进行实例化。

举个例子,假设我们需要实现一个通用的栈数据结构,它可以存储任意类型的元素。我们可以使用泛型类来实现这个栈,代码如下:

public class Stack<E> {
    private ArrayList<E> elements;

    public Stack() {
        elements = new ArrayList<E>();
    }

    public void push(E element) {
        elements.add(element);
    }

    public E pop() {
        if (elements.size() == 0) {
            throw new EmptyStackException();
        }
        return elements.remove(elements.size() - 1);
    }

    public boolean isEmpty() {
        return elements.size() == 0;
    }

    public int size() {
        return elements.size();
    }
}

这个栈使用泛型类实现,其中的类型参数E表示元素的类型。在创建栈的实例时,我们可以指定元素的类型,例如:

Stack<Integer> stack1 = new Stack<Integer>();    // 存储整数类型的元素
Stack<String> stack2 = new Stack<String>();    // 存储字符串类型的元素
Stack<Object> stack3 = new Stack<Object>();    // 存储任意类型的元素

使用泛型类可以使我们编写一次代码,然后在不同的类型上进行实例化,从而避免了代码的冗余和重复。

另外一个例子是使用泛型方法来实现一个通用的最大值函数。这个函数可以接受任意类型的参数,比较它们的大小并返回最大值。代码如下:

public class Utils {
    public static <T extends Comparable<T>> T getMax(T a, T b) {
        if (a.compareTo(b) > 0) {
            return a;
        } else {
            return b;
        }
    }
}

这个函数使用泛型方法实现,其中的类型参数T表示元素的类型,它必须是实现了Comparable接口的类型。在调用这个函数时,我们可以传递不同类型的参数,例如:

int maxInt = Utils.getMax(1, 2);    // 返回 2
double maxDouble = Utils.getMax(2.5, 1.2);    // 返回 2.5
String maxString = Utils.getMax("hello", "world");    // 返回 "world"

使用泛型方法可以使我们编写一次代码,然后在不同的类型上进行实例化,从而避免了代码的冗余和重复。

3、java反射在实际项目中的应用场景

java反射是指在程序运行时动态地获取类的信息、访问和操作对象的属性和方法。
应用场景
1)框架设计:许多Java框架都使用反射机制来实现插件化、动态配置等功能。例如Spring框架中,反射机制用于实现IoC容器、AOP、MVC等核心功能。
2)数据库编程:Java反射可以动态地获取类的属性信息,可以方便地将数据库表的字段映射到Java对象的属性上。许多ORM框架(如Hibernate、MyBatis等)都使用反射来实现对象和数据库之间的映射。
3)单元测试:Java反射可以动态地创建和执行对象的方法,可以方便地编写单元测试框架和测试用例。例如JUnit测试框架中,反射机制用于执行测试用例的方法。
4)动态代理:Java反射可以动态地创建代理对象,并在代理对象中添加额外的逻辑。动态代理常用于AOP编程中,可以在不修改原始对象的情况下,实现对对象的增强和拦截。
5)序列化和反序列化:Java反射可以动态地获取对象的属性和方法信息,并将其转换为二进制流,用于对象的序列化和反序列化。例如Java中的ObjectOutputStream和ObjectInputStream类,就使用了反射机制实现对象的序列化和反序列化。

4、说说java的四种引用方式

在Java中,引用是指在程序中引用对象的变量,而不是对象本身。
强引用(Strong Reference):最常见,是指通过new操作符创建对象时所创建的默认引用方式。强引用所指向的对象在任何情况下都不会被垃圾回收器回收,只有在强引用被断开时,对象才会被回收。
软引用(Soft Reference):是指一些还有用但并非必需的对象所使用的引用方式。当系统内存不足时,垃圾回收器会优先回收软引用所指向的对象,以释放内存空间。
弱引用(Weak Reference):是指一些非必需对象所使用的引用方式。当垃圾回收器扫描到弱引用所指向的对象时,无论当前内存是否充足,都会立即回收弱引用所指向的对象。
虚引用(Phantom Reference):是指一些无法被直接访问的对象所使用的引用方式。虚引用的主要作用是在对象被垃圾回收器回收时,能够收到一个通知。虚引用必须与引用队列(ReferenceQueue)一起使用,垃圾回收器在回收对象时,会将虚引用加入到引用队列中,程序可以通过引用队列来获取通知。

5、java中处理异常的步骤。

捕获异常(Catching Exceptions):在程序中,可以使用try-catch语句来捕获异常。try语句块中包含可能出现异常的代码,如果出现异常,会立即跳转到catch语句块中,执行相应的异常处理代码。
处理异常(Handling Exceptions):在catch语句块中,可以编写异常处理代码,包括记录日志、提示用户、重新抛出异常等。
回收资源:finally语句块包含的代码会在try-catch语句块执行完毕后执行,无论是否发生异常。finally语句块通常用于资源释放等操作。

6、在finally中return会发生什么?

在通常情况下,不要在finally块中使用return、throw等导致方法终止的语句,一旦在finally块中使用了return、throw语句,将会导致try块、catch块中的return、throw语句失效。

7、一个Java文件里可以有多个类吗(不含内部类)?

1)一个java文件里可以有多个类,但最多只能有一个被public修饰的类;
2)如果这个java文件中包含public修饰的类,则这个类的名称必须和java文件名一致。

8、java的数据类型

包括基本数据类型和引用类型
基本数据类型
byte:1字节(8位),数据范围是 -2^7 ~ 2^7-1。

short:2字节(16位),数据范围是 -2^15 ~ 2^15-1。

int:4字节(32位),数据范围是 -2^31 ~ 2^31-1。

long:8字节(64位),数据范围是 -2^63 ~ 2^63-1。

float:4字节(32位),数据范围大约是 -3.410^38 ~ 3.410^38。

double:8字节(64位),数据范围大约是 -1.810^308 ~ 1.810^308。

char:2字节(16位),数据范围是 \u0000 ~ \uffff。

boolean:Java规范没有明确的规定,不同的JVM有不同的实现机制。

Java中的引用数据类型包括:

类(Class)
接口(Interface)
数组(Array)
枚举(Enumeration)
注解(Annotation)
泛型类型(Generic Types)

9、 int和Integer有什么区别,二者在做==运算时会得到什么结果?

int是基本数据类型,Integer是int的包装类。二者在做==运算时,Integer会自动拆箱为int类型,然后再进行比较。此时,如果两个int值相等则返回true,否则就返回false。

10、 构造方法能不能重写?

构造方法不可以重写。因为构造方法需要和类保持同名,而重写的要求是子类方法要和父类方法保持同名。如果允许重写构造方法的话,那么子类中将会存在与类名不同的构造方法,这与构造方法的要求是矛盾的。

11、为什么要重写hashCode()和equals()?

Object类提供的equals()方法默认是用==来进行比较的,也就是说只有两个对象是同一个对象时,才能返回相等的结果。而实际的业务中,我们通常的需求是,若两个不同的对象它们的内容是相同的,就认为它们相等。鉴于这种情况,Object类中equals()方法的默认实现是没有实用价值的,所以通常都要重写。
而hashCode()与equals()具有一定的联系,因此当equals()方法重写时,通常也要将hashCode()进行重写,使得这两个方法始终满足相关的约定。

12、String常见的方法有哪些?

String类是java最常见的API,包含了大量处理字符串的方法,常用的方法如下:

  • char charAt(int index):返回指定索引处的字符
  • String substring(int beginIndex, int endIndex):从字符串中截取一部分字符串
  • String[] split(String str):以指定的规则将此字符串分割成数组。
  • String trim():删除字符串前导和后置的空格
  • int indexOf(String str):返回子串在此字符串中首次出现的索引
  • int lastIndexOf(String str):返回子串在此字符串中最后出现的索引
  • boolean startsWith(String prefix):判断此字符串是否以指定的前缀开头
  • boolean endWith(String suffix):判断此字符串是否以指定的后缀结尾
  • Sring toUpperCase():将此字符串中的所有字符大写
  • String toLowerCase():将此字符串中的所有字符小写
  • String replaceFirst(String regex,String replacement):用指定字符串替换第一个匹配的子串
  • String replaceAll(String regex,String replacement):用指定字符串替换所有匹配的子串

13、字符串拼接的四种方式

1)使用“+”号拼接字符串:如果拼接的都是字符串直接量,则适合使用 + 运算符实现拼接;
2)使用StringBuilder拼接字符串:如果拼接的字符串中包含变量,并不要求线程安全,则适合使用StringBuilder;
3)使用StringBuffer拼接字符串:如果拼接的字符串中包含变量,并且要求线程安全,则适合使用StringBuffer;
4)使用String类的concat方法:如果只是对两个字符串进行拼接,并且包含变量,则适合使用concat方法;

14、String a = “abc”; ,说一下这个过程会创建什么,放在哪里?

JVM会使用常量池来管理字符串直接量。在执行这句话时,JVM会先检查常量池中是否已经存有"abc",若没有则将"abc"存入常量池,否则就复用常量池中已有的"abc",将其引用赋值给变量a。

15、构造方法有哪些特性

1)名字与类名相同。
2)没有返回值,但不能⽤ void 声明构造函数。
3)⽣成类的对象时⾃动执⾏,⽆需调⽤。

16、对象的相等与指向他们的引⽤相等,两者有什么不同?

对象的相等,是指内存中存放的内容是否相等。⽽引⽤相等,指的是他们指向的内存地址是
否相等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值