Java基础

2023-03-09 14:53:43 浏览数 (1)

1. JVM的整体结构

JVM的整体结构主要由三个部分组成:

  1. 类加载系统:负责加载本地中的Class文件,对其进行校验与转换最后形成可以被虚拟机直接调用的java.lang.Class并保存于方法区中。
  2. 字节码引擎:对输入的字节码文件进行解析处理并输出执行的结果。
  3. 运行时数据区:类在加载完成后开始被使用的地方。

2. JVM的运行时数据区

运行时数据区可以被划分为5个主要组件:方法区、堆区、栈区、PC寄存器以及本地方法栈。其中方法区、堆区与栈区是其三大核心部分。

  1. 方法区(Method Area)

方法区存储了所有类级别的数据,包括静态变量。每个JVM中只能有一个方法区,其中所有资源共享,故不是线程安全的。

2. 堆区(Heap Area)

所有被创建的对象及其实例变量以及数组都被存放在堆区中,每个JVM同样也只有一个堆区,其内存被多个线程共享,故不是线程安全的。

3. 栈区(Stack Area)

所有的局部变量都被存储在栈区中,每个线程都有自己的运行时栈,因而栈区是线程安全的。

4. PC寄存器

每个线程都有一个单独的PC寄存器来保存当前执行指令的地址,当指令被执行后,PC寄存器便会更新至下一条指令的地址。5. 本地方法栈

所有的本地方法都被保存在这里,每个线程都有自己的本地方法栈。


3. Object类中的方法

  1. clone()
  2. equals()
  3. hashcode()
  4. wait()
  5. notify()
  6. notifyAll()
  7. finalize()
  8. toString()
  9. getClass()

4. 静态变量与实例变量的区别

对于静态变量而言,它是属于类的,因而随着类的创建而被创建,在类的加载过程中,JVM中只会被分配一次内存空间;对于实例变量而言,由于每创建一个对象JVM都会为其分配成员变量内存空间,而实例变量是属于实例对象的,因而创建了几个对象,JVM就会为实例变量分配几次内存空间。


5. String类的常用方法

  1. indexOf():返回指定字符的索引
  2. charAt():返回指定索引处的字符
  3. replace():进行字符串的替换
  4. trim():去除字符串前后两端空格
  5. split():对字符串进行分割并返回分割后的数组
  6. equals():字符串内容的比较
  7. subString():对字符串进行分割
  8. toLowerCase():全部转换为小写
  9. toUpperCase():全部转换为大写
  10. getBytes():返回字符串的byte类型的数组
  11. length():返回字符串长度

6. 数组中有没有length()方法?String类中有没有length()方法?

数组中没有length()方法,但是有length()的属性;而String类中有length()方法。

注: 数组中没有length()方法的原因是因为在定义数组时,数组的长度已经是固定的了,length在类中是public final的,因而也就无需设置一个方法在运行是获取数组的长度。

(Since arrays are fixed length defined at the time they are instantiated, length is public final field on the class. There is no need to make it a method since there is no calculation to be done at runtime.)


7. String、StringBuilder与StringBuffer的区别

  1. 可变与适用范围。String对象是不可变的,而StringBuilder与StringBuffer是可变的。每次对String对象的操作都相当于新建了一个对象,而对于StringBuilder与StringBuffer而言则是在原对象上的操作。因而当需要频繁修改对象时,应当选用StringBuilder或StringBuffer以减少频繁生成对象对系统资源的消耗。
  2. 线程安全性。String由于被final所修饰,因而是immutable的,是线程安全的。StringBuffer中的方法以及调用的方法都被synchronized所修饰,故也是线程安全的。而StringBuilder则是线程非安全的,但效率更高。

总而言之:

  1. 当需要操作少量数据时,选用String;
  2. 单线程操作字符串缓冲区中大量数据时,选用StringBuilder;
  3. 多线程操作字符串缓冲区下大量数据时,选用StringBuffer。

8. String str = "i"与String str = new String("i")一样吗?

对于String str = "i"而言,它首先会在字符串常量池中查找i的存在,如果不存在,则在常量池中开辟一块内存空间并将str指向该地址;而对于String str = new String("i")而言,它首先会在对内存中开辟一块内存空间存放str,随后在字符串常量池中查找i,如果不存在则会在常量池中开辟第二块内存空间,并将i指向该地址,也就是相当于新建了两个对象。


9. 实现字符串的反转与替换

  1. 字符串反转
代码语言:javascript复制
public static String reverse(String s){
   String res = "";
   for(int i = 0; i < s.length();   i){
   reverse = s.charAt(i)   reverse;
   }
   return reverse;
   }
代码语言:javascript复制
public static String reverseCharArrays(String s){
    char []array = s.toCharArray();
    String reverse = "";
    for(int i = array.length -1 ; i>=0 ; i--){
        reverse  =array[i];
    }
    return reverse;
    }
代码语言:javascript复制
public static String reverseStringBuffer(String s){
    StringBuffer sb = new StringBuffer(s);
    String afterReverse = sb.reverse().toString();
    return afterReverse;
    }
代码语言:javascript复制
public static String reverseRecursive(String s){
    int length = s.length();
    if(length<=1){
    return s;
    }
    String left  = s.substring(0,length/2);
    String right = s.substring(length/2 ,length);
    String afterReverse = reverseRecursive(right) reverseRecursive(left);
    return afterReverse;
    }
  1. 字符串替换
代码语言:javascript复制
public static void main(String[] args){
       StringBuffer buffer = new StringBuffer(“123456”);
       System.out.println(buffer.toString());
       buffer.replace(0, 1, “a”);
       System.out.println(buffer.toString());
  }

10. float f = 3.4正确吗?

错误。java中浮点数的默认精度为double,将双精度的double赋值给浮点型float属于下转型,会造成精度丢失,因此需要进行强转,如:float f = (float) 3.4或者float f = 3.4F


11. a = a b与a = b 的区别

二者的区别在于: =会隐式的将加的结果类型强制转换为持有结果的类型。如:

代码语言:javascript复制
byte a = 127;
byte b = 127;
b = a   b; //error: cannot convert from into byte
b  = a;

12. ==与equals的区别

  1. 对于基本数据类型而言,==比较的是二者的值是否相等;而equals不能用与基本数据类型的比较,必须将其转换为包装类才可以使用equals()方法;
  2. 对于引用数据类型而言,二者比较的都是地址值是否相同,但equals()方法可以通过重写来实现内容的比较。

13. 接口与抽象类的区别

  1. 抽象类中的成员方法可以有实现的细节,而接口中只能有public abstract的方法;
  2. 抽象类中的成员变量可以是任意的,而接口中的成员变量则是public static final的;
  3. 抽象类中可以有静态代码块与静态方法,而接口中不可以;
  4. 一个类只能继承一个抽象类,但可以同时实现多个接口。

14. Java中的值传递与引用传递

  1. 值传递

在方法的调用过程中,实参将其真实值传递给形参,该传递过程相当与将实参的复制一份传递到函数,对形参的操作不会影响到实参。

  1. 引用传递

引用传递弥补了值传递的不足,当数据量传输过大时,值传递会占用大量的内存空间。而引用传递则是将对象的地址值传递给函数,函数接收的是真实值,即对形参的操作会影响到实参。


15. sleep与wait的区别

  • sleep()是线程类中的方法,当调用该方法时会导致线程暂停指定时间,将执行机会让给其他线程,同时不会释放掉对象锁。
  • wait()是Object类中的方法,当调用该方法时会使当前线程释放掉对象锁,进入等待该对象的等待锁定池,只有针对该对象发出notify()或者notifyAll()方法时,该线程才会进入对象锁定池等待获得对象锁。

16. Java中的反射

反射指的是在运行状态中,对于任意一个类都可以获得其中的属性与方法;对于任意一个对象,都可以调用其中的任意方法。这种动态获取信息以及动态调用对象方法的功能便是Java中的反射。通过反射机制使得代码更加通用以及灵活,比如Spring/SpringBoot、MyBatis等框架大量用到了反射机制。


17. Java中的元注解以及注解可以加在什么地方?哪里用到了注解?

Java中的元注解包括:@Override@Deprecated@SuppressWarnings,分别用于标注重写类或方法、类或方法已过时和忽略警告。

注解通常用作对代码进行说明,可以标注在包、类、接口、字段、方法参数、局部变量等。

Spring、SpringMVC以及单元测试等都用到了大量的注解。


18. Java中final关键字的用法

  1. 修饰类表示该类不能被继承
  2. 修饰方法表示该方法不能被重写
  3. final修饰的局部变量必须被赋值才能使用
  4. final修饰的成员变量如果没有赋初值,则必须在构造器方法或静态代码块中初始化。

0 人点赞